27#include <winpr/cast.h>
28#include <winpr/i18n.h>
29#include <winpr/pipe.h>
31#include <freerdp/config.h>
32#include <freerdp/utils/signal.h>
40#include <freerdp/client.h>
42#include <freerdp/freerdp.h>
43#include <freerdp/addin.h>
44#include <freerdp/assistance.h>
45#include <freerdp/client/file.h>
46#include <freerdp/utils/passphrase.h>
47#include <freerdp/client/cmdline.h>
48#include <freerdp/client/channels.h>
49#include <freerdp/event.h>
50#include <freerdp/utils/smartcardlogon.h>
51#include <freerdp/session.h>
53#if defined(CHANNEL_AINPUT_CLIENT)
54#include <freerdp/client/ainput.h>
55#include <freerdp/channels/ainput.h>
58#if defined(CHANNEL_VIDEO_CLIENT)
59#include <freerdp/client/video.h>
60#include <freerdp/channels/video.h>
63#if defined(CHANNEL_RDPGFX_CLIENT)
64#include <freerdp/client/rdpgfx.h>
65#include <freerdp/channels/rdpgfx.h>
66#include <freerdp/gdi/gfx.h>
69#if defined(CHANNEL_GEOMETRY_CLIENT)
70#include <freerdp/client/geometry.h>
71#include <freerdp/channels/geometry.h>
74#if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
75#include <freerdp/gdi/video.h>
78#include <freerdp/channels/rdpewa.h>
81#include <freerdp/utils/http.h>
82#include <freerdp/utils/aad.h>
83#include <freerdp/client/aad_helper.h>
87#include "sso_mib_tokens.h"
92#include <freerdp/log.h>
95static BOOL freerdp_client_common_pre_connect(rdpContext* context);
97BOOL freerdp_client_enable_translation(
const char* locale,
const char* searchPath)
99 return freerdp_enable_translation(locale, searchPath) &&
100 winpr_i18n_bind_domain(
"freerdp-client", searchPath);
102#define TAG CLIENT_TAG("common")
107 window_events_fkt_t window_events;
109} handle_window_events_t;
112static BOOL requireRdpClientContext(
const rdpContext* context)
116 WLog_ERR(TAG,
"[APPLICATION BUG] Function must be called with a context != NULL!");
120 freerdp* instance = context->instance;
124 "[APPLICATION BUG] Function must be called with a context->instance != NULL!");
128 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
131 WLog_ERR(TAG,
"[APPLICATION BUG] Function must be called with a "
132 "context->instance->pclientEntryPoints != NULL!");
138 if (
sizeof(rdpClientContext) > instance->ContextSize)
142 "[APPLICATION BUG] Function must be called with a context based on rdpClientContext!");
144 "[APPLICATION BUG] sizeof(rdpClientContext)[%" PRIuz
145 "] > instance->ContextSize[%" PRIuz
"])",
146 sizeof(rdpClientContext), instance->ContextSize);
153static void set_default_callbacks(freerdp* instance)
155 WINPR_ASSERT(instance);
156 instance->AuthenticateEx = client_cli_authenticate_ex;
157 instance->ChooseSmartcard = client_cli_choose_smartcard;
158 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
159 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
160 instance->PresentGatewayMessage = client_cli_present_gateway_message;
161 instance->LogonErrorInfo = client_cli_logon_error_info;
162 instance->GetAccessToken = client_cli_get_access_token;
163 instance->RetryDialog = client_common_retry_dialog;
165 WINPR_ASSERT(instance->context);
166 WINPR_ASSERT(instance->context->update);
167 instance->context->update->SaveSessionInfo = client_common_save_session_info;
170static void client_cli_user_notification(
void* context,
const UserNotificationEventArgs* e)
172 WINPR_UNUSED(context);
174 if (strcmp(e->e.Sender, RDPEWA_CHANNEL_NAME) != 0)
177 if (!e->message || e->message[0] ==
'\0')
179 (void)fprintf(stderr,
"[%s] Touch the security key\n", e->e.Sender);
180 (void)fflush(stderr);
184static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
186 WINPR_ASSERT(instance);
187 WINPR_ASSERT(context);
189 instance->LoadChannels = freerdp_client_load_channels;
190 set_default_callbacks(instance);
192 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
193 WINPR_ASSERT(pEntryPoints);
195 if (requireRdpClientContext(context))
197 rdpClientContext* cctx = (rdpClientContext*)context;
198 cctx->oauth2 = freerdp_oauth2_new();
203 const BOOL rc = IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
206 return freerdp_client_common_pre_connect(context);
209static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
211 WINPR_ASSERT(instance);
212 WINPR_ASSERT(context);
214 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
215 WINPR_ASSERT(pEntryPoints);
216 IFCALL(pEntryPoints->ClientFree, instance, context);
218 if (requireRdpClientContext(context))
220 rdpClientContext* cctx = (rdpClientContext*)context;
221 freerdp_oauth2_free(cctx->oauth2);
222 cctx->oauth2 =
nullptr;
228rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
230 freerdp* instance =
nullptr;
231 rdpContext* context =
nullptr;
236 if (!IFCALLRESULT(TRUE, pEntryPoints->GlobalInit))
239 instance = freerdp_new();
244 instance->ContextSize = pEntryPoints->ContextSize;
245 instance->ContextNew = freerdp_client_common_new;
246 instance->ContextFree = freerdp_client_common_free;
247 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
249 if (!instance->pClientEntryPoints)
252 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
254 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
257 context = instance->context;
258 context->instance = instance;
260#if defined(WITH_CLIENT_CHANNELS)
261 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
268 free(instance->pClientEntryPoints);
270 freerdp_free(instance);
274void freerdp_client_context_free(rdpContext* context)
276 freerdp* instance =
nullptr;
281 instance = context->instance;
285 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
286 freerdp_context_free(instance);
289 IFCALL(pEntryPoints->GlobalUninit);
291 free(instance->pClientEntryPoints);
292 freerdp_free(instance);
296int freerdp_client_start(rdpContext* context)
298 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
300 if (!context || !context->instance || !context->instance->pClientEntryPoints)
301 return ERROR_BAD_ARGUMENTS;
305 set_default_callbacks(context->instance);
309 PubSub_SubscribeUserNotification(context->pubSub, client_cli_user_notification);
316 if (requireRdpClientContext(context))
318 rdpClientContext* client_context = (rdpClientContext*)context;
319 client_context->mibClientWrapper = sso_mib_new(context);
320 if (!client_context->mibClientWrapper)
321 return ERROR_INTERNAL_ERROR;
325 pEntryPoints = context->instance->pClientEntryPoints;
326 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
329int freerdp_client_stop(rdpContext* context)
331 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
333 if (!context || !context->instance || !context->instance->pClientEntryPoints)
334 return ERROR_BAD_ARGUMENTS;
336 pEntryPoints = context->instance->pClientEntryPoints;
337 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
340 PubSub_UnsubscribeUserNotification(context->pubSub, client_cli_user_notification);
343 if (requireRdpClientContext(context))
345 rdpClientContext* client_context = (rdpClientContext*)context;
346 sso_mib_free(client_context->mibClientWrapper);
347 client_context->mibClientWrapper =
nullptr;
353freerdp* freerdp_client_get_instance(rdpContext* context)
355 if (!context || !context->instance)
358 return context->instance;
361HANDLE freerdp_client_get_thread(rdpContext* context)
366 WINPR_ASSERT(requireRdpClientContext(context));
367 if (!requireRdpClientContext(context))
370 return ((rdpClientContext*)context)->thread;
374static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
399 settings, FreeRDP_GatewayPassword,
437int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
441 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown,
442 nullptr, 0,
nullptr,
nullptr);
445int freerdp_client_settings_parse_command_line_ex(
447 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
457 status = freerdp_client_settings_parse_command_line_arguments_ex(
458 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
465 if (!freerdp_client_settings_post_process(settings))
468 const char* name = argv[0];
469 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
470 freerdp_get_build_config());
474int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
476 rdpFile* file =
nullptr;
478 file = freerdp_client_rdp_file_new();
483 if (!freerdp_client_parse_rdp_file(file, filename))
486 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
491 freerdp_client_rdp_file_free(file);
495int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
498 rdpFile* file =
nullptr;
500 file = freerdp_client_rdp_file_new();
505 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
506 freerdp_client_populate_settings_from_rdp_file(file, settings))
511 freerdp_client_rdp_file_free(file);
515int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
518 rdpFile* file =
nullptr;
520 file = freerdp_client_rdp_file_new();
525 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
528 if (!freerdp_client_write_rdp_file(file, filename, unicode))
533 freerdp_client_rdp_file_free(file);
537int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
541 char* filename =
nullptr;
542 char* password =
nullptr;
543 rdpAssistanceFile* file =
nullptr;
545 if (!settings || !argv || (argc < 2))
550 for (
int x = 2; x < argc; x++)
552 const char* key = strstr(argv[x],
"assistance:");
556 char* sep = strchr(key,
':');
564 file = freerdp_assistance_file_new();
569 status = freerdp_assistance_parse_file(file, filename, password);
574 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
579 freerdp_assistance_file_free(file);
584static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
587 WINPR_ASSERT(instance);
589 WINPR_ASSERT(result);
593 (void)fflush(stdout);
595 char* line =
nullptr;
596 if (suggestion && strlen(suggestion) > 0)
598 line = _strdup(suggestion);
599 size = strlen(suggestion);
602 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
605 char ebuffer[256] = WINPR_C_ARRAY_INIT;
606 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
607 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
617 line = StrSep(&line,
"\r");
618 line = StrSep(&line,
"\n");
640static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
641 char** password,
char** domain)
643 static const size_t password_size = 512;
644 const char* userAuth =
"Username: ";
645 const char* domainAuth =
"Domain: ";
646 const char* pwdAuth =
"Password: ";
647 BOOL pinOnly = FALSE;
648 BOOL queryAll = FALSE;
650 WINPR_ASSERT(instance);
651 WINPR_ASSERT(instance->context);
652 WINPR_ASSERT(instance->context->settings);
656 case AUTH_SMARTCARD_PIN:
657 pwdAuth =
"Smartcard-Pin: ";
661 pwdAuth =
"FIDO2 PIN: ";
674 userAuth =
"GatewayUsername: ";
675 domainAuth =
"GatewayDomain: ";
676 pwdAuth =
"GatewayPassword: ";
682 if (!username || !password || !domain)
687 const char* suggest = *username;
688 if (queryAll || !suggest)
690 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
698 const char* suggest = *domain;
699 if (queryAll || !suggest)
701 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
708 char* line = calloc(password_size,
sizeof(
char));
713 const BOOL fromStdin =
716 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
720 if (password_size > 0)
738BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
739 rdp_auth_reason reason)
741 WINPR_ASSERT(instance);
742 WINPR_ASSERT(username);
743 WINPR_ASSERT(password);
744 WINPR_ASSERT(domain);
754 case AUTH_SMARTCARD_PIN:
756 if ((*username) && (*password))
767 return client_cli_authenticate_raw(instance, reason, username, password, domain);
770BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
771 DWORD count, DWORD* choice, BOOL gateway)
773 unsigned long answer = 0;
776 printf(
"Multiple smartcards are available for use:\n");
777 for (DWORD i = 0; i < count; i++)
780 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
781 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
784 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
785 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
786 cert->issuer, cert->upn);
789 free(container_name);
794 char input[10] = WINPR_C_ARRAY_INIT;
796 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
797 gateway ?
"gateway authentication" :
"logon", count - 1);
798 (void)fflush(stdout);
799 if (!fgets(input, 10, stdin))
801 WLog_ERR(TAG,
"could not read from stdin");
805 answer = strtoul(input, &p, 10);
806 if ((*p ==
'\n' && p != input) && answer < count)
808 *choice = (UINT32)answer;
814#if defined(WITH_FREERDP_DEPRECATED)
815BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
819 WLog_INFO(TAG,
"Authentication via smartcard");
823 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
826BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
828 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
833static DWORD client_cli_accept_certificate(freerdp* instance)
837 WINPR_ASSERT(instance);
838 WINPR_ASSERT(instance->context);
840 const rdpSettings* settings = instance->context->settings;
841 WINPR_ASSERT(settings);
849 printf(
"Do you trust the above certificate? (Y/T/N) ");
850 (void)fflush(stdout);
851 answer = freerdp_interruptible_getc(instance->context, stdin);
853 if ((answer == EOF) || feof(stdin))
855 printf(
"\nError: Could not read answer from stdin.\n");
863 answer = freerdp_interruptible_getc(instance->context, stdin);
871 answer = freerdp_interruptible_getc(instance->context, stdin);
879 answer = freerdp_interruptible_getc(instance->context, stdin);
904#if defined(WITH_FREERDP_DEPRECATED)
905DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
906 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
908 WINPR_UNUSED(common_name);
909 WINPR_UNUSED(host_mismatch);
911 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
912 printf(
"Certificate details:\n");
913 printf(
"\tSubject: %s\n", subject);
914 printf(
"\tIssuer: %s\n", issuer);
915 printf(
"\tThumbprint: %s\n", fingerprint);
916 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
917 "the CA certificate in your certificate store, or the certificate has expired.\n"
918 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
919 return client_cli_accept_certificate(instance);
923WINPR_ATTR_MALLOC(free, 1)
924static
char* client_cli_pem_cert(const
char* pem)
926 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
930 char* fp = freerdp_certificate_get_fingerprint(cert);
931 char* start = freerdp_certificate_get_validity(cert, TRUE);
932 char* end = freerdp_certificate_get_validity(cert, FALSE);
933 freerdp_certificate_free(cert);
937 winpr_asprintf(&str, &slen,
940 "\tThumbprint: %s\n",
963DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
964 const char* common_name,
const char* subject,
965 const char* issuer,
const char* fingerprint, DWORD flags)
967 const char* type =
"RDP-Server";
969 WINPR_ASSERT(instance);
970 WINPR_ASSERT(instance->context);
971 WINPR_ASSERT(instance->context->settings);
973 if (flags & VERIFY_CERT_FLAG_GATEWAY)
974 type =
"RDP-Gateway";
976 if (flags & VERIFY_CERT_FLAG_REDIRECT)
977 type =
"RDP-Redirect";
979 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
980 printf(
"\tCommon Name: %s\n", common_name);
981 printf(
"\tSubject: %s\n", subject);
982 printf(
"\tIssuer: %s\n", issuer);
986 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
988 char* str = client_cli_pem_cert(fingerprint);
993 printf(
"\tThumbprint: %s\n", fingerprint);
995 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
996 "the CA certificate in your certificate store, or the certificate has expired.\n"
997 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
998 return client_cli_accept_certificate(instance);
1016#if defined(WITH_FREERDP_DEPRECATED)
1017DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
1018 const char* subject,
const char* issuer,
1019 const char* fingerprint,
const char* old_subject,
1020 const char* old_issuer,
const char* old_fingerprint)
1022 WINPR_UNUSED(common_name);
1024 printf(
"WARNING: This callback is deprecated, migrate to "
1025 "client_cli_verify_changed_certificate_ex\n");
1026 printf(
"!!! Certificate has changed !!!\n");
1028 printf(
"New Certificate details:\n");
1029 printf(
"\tSubject: %s\n", subject);
1030 printf(
"\tIssuer: %s\n", issuer);
1031 printf(
"\tThumbprint: %s\n", fingerprint);
1033 printf(
"Old Certificate details:\n");
1034 printf(
"\tSubject: %s\n", old_subject);
1035 printf(
"\tIssuer: %s\n", old_issuer);
1036 printf(
"\tThumbprint: %s\n", old_fingerprint);
1038 printf(
"The above X.509 certificate does not match the certificate used for previous "
1040 "This may indicate that the certificate has been tampered with.\n"
1041 "Please contact the administrator of the RDP server and clarify.\n");
1042 return client_cli_accept_certificate(instance);
1065DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
1066 const char* common_name,
const char* subject,
1067 const char* issuer,
const char* fingerprint,
1068 const char* old_subject,
const char* old_issuer,
1069 const char* old_fingerprint, DWORD flags)
1071 const char* type =
"RDP-Server";
1073 WINPR_ASSERT(instance);
1074 WINPR_ASSERT(instance->context);
1075 WINPR_ASSERT(instance->context->settings);
1077 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1078 type =
"RDP-Gateway";
1080 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1081 type =
"RDP-Redirect";
1083 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
1085 printf(
"New Certificate details:\n");
1086 printf(
"\tCommon Name: %s\n", common_name);
1087 printf(
"\tSubject: %s\n", subject);
1088 printf(
"\tIssuer: %s\n", issuer);
1092 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1094 char* str = client_cli_pem_cert(fingerprint);
1099 printf(
"\tThumbprint: %s\n", fingerprint);
1101 printf(
"Old Certificate details:\n");
1102 printf(
"\tSubject: %s\n", old_subject);
1103 printf(
"\tIssuer: %s\n", old_issuer);
1107 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1109 char* str = client_cli_pem_cert(old_fingerprint);
1114 printf(
"\tThumbprint: %s\n", old_fingerprint);
1116 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
1118 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
1119 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
1120 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
1121 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
1124 printf(
"The above X.509 certificate does not match the certificate used for previous "
1126 "This may indicate that the certificate has been tampered with.\n"
1127 "Please contact the administrator of the RDP server and clarify.\n");
1128 return client_cli_accept_certificate(instance);
1131BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1132 BOOL isConsentMandatory,
size_t length,
1133 const WCHAR* message)
1135 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
1137 WINPR_ASSERT(instance);
1138 WINPR_ASSERT(instance->context);
1139 WINPR_ASSERT(instance->context->settings);
1141 if (!isDisplayMandatory && !isConsentMandatory)
1144 printf(
"%s:\n", msgType);
1146 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR),
nullptr);
1149 printf(
"Failed to convert message!\n");
1152 printf(
"%s\n", msg);
1156 while (isConsentMandatory)
1158 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1159 (void)fflush(stdout);
1160 const int answer = freerdp_interruptible_getc(instance->context, stdin);
1162 if ((answer == EOF) || feof(stdin))
1164 printf(
"\nError: Could not read answer from stdin.\n");
1168 const int confirm = freerdp_interruptible_getc(instance->context, stdin);
1174 return confirm != EOF;
1189#if defined(WITH_AAD)
1191static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1192 const char* req_cnf,
char** token)
1194 WINPR_ASSERT(instance);
1195 WINPR_ASSERT(instance->context);
1198 char* url =
nullptr;
1199 char* token_request =
nullptr;
1201 WINPR_ASSERT(scope);
1202 WINPR_ASSERT(req_cnf);
1203 WINPR_ASSERT(token);
1208 WINPR_ASSERT(requireRdpClientContext(instance->context));
1209 if (!requireRdpClientContext(instance->context))
1212 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1213 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1215 printf(
"Browse to: %s\n", request);
1216 winpr_zfree(request);
1217 printf(
"Paste redirect URL here: \n");
1219 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1224 freerdp_client_extract_aad_code((rdpClientContext*)instance->context, url, size);
1228 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1229 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1235 rc = client_common_get_access_token(instance, token_request, token);
1238 winpr_zfree(token_request);
1240 return rc && (*token !=
nullptr);
1244static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1246 WINPR_ASSERT(instance);
1247 WINPR_ASSERT(instance->context);
1249 WINPR_ASSERT(requireRdpClientContext(instance->context));
1250 if (!requireRdpClientContext(instance->context))
1254 char* url =
nullptr;
1255 char* token_request =
nullptr;
1257 WINPR_ASSERT(token);
1263 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1264 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1267 printf(
"Browse to: %s\n", request);
1268 winpr_zfree(request);
1269 printf(
"Paste redirect URL here: \n");
1271 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1276 freerdp_client_extract_aad_code((rdpClientContext*)instance->context, url, size);
1279 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1280 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1287 rc = client_common_get_access_token(instance, token_request, token);
1290 free(token_request);
1292 return rc && (*token !=
nullptr);
1297static BOOL client_cli_get_access_token_va(freerdp* instance,
1298 WINPR_ATTR_UNUSED AccessTokenType tokenType,
1299 char** token, WINPR_ATTR_UNUSED
size_t count, va_list ap)
1301 WINPR_ASSERT(instance);
1302 WINPR_ASSERT(token);
1305#if !defined(WITH_AAD)
1306 WLog_ERR(TAG,
"Build does not support AAD authentication");
1310 WINPR_ASSERT(instance->context);
1319 case ACCESS_TOKEN_TYPE_AAD:
1324 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1333 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1336 const char* scope = va_arg(ap,
const char*);
1337 const char* req_cnf = va_arg(ap,
const char*);
1338 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1342 case ACCESS_TOKEN_TYPE_AVD:
1345 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1348 rc = client_cli_get_avd_access_token(instance, token);
1351 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%u], aborting", tokenType);
1362BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1365 va_list ap = WINPR_C_ARRAY_INIT;
1366 va_start(ap, count);
1367 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
1372BOOL client_common_get_access_token(WINPR_ATTR_UNUSED freerdp* instance,
1373 WINPR_ATTR_UNUSED
const char* request,
1374 WINPR_ATTR_UNUSED
char** token)
1376 WINPR_ASSERT(request);
1377 WINPR_ASSERT(token);
1383 BYTE* response =
nullptr;
1384 size_t response_length = 0;
1386 wLog* log = WLog_Get(TAG);
1388 const char* token_ep =
1389 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1390 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1392 WLog_ERR(TAG,
"access token request failed");
1396 if (resp_code != HTTP_STATUS_OK)
1398 char buffer[64] = WINPR_C_ARRAY_INIT;
1400 WLog_Print(log, WLOG_ERROR,
1401 "Server unwilling to provide access token; returned status code %s",
1402 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1403 if (response_length > 0)
1404 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1408 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1416 WLog_ERR(TAG,
"Build does not support AAD authentication");
1421SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1424 WINPR_UNUSED(instance);
1425 WINPR_ASSERT(instance->context);
1426 WINPR_UNUSED(userarg);
1427 WINPR_ASSERT(instance);
1430 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1432 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1438 if (strcmp(what,
"arm-transport") == 0)
1439 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1442 const rdpSettings* settings = instance->context->settings;
1446 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1455 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1456 "tech support for help if this keeps happening.",
1461 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1462 what, current + 1, max, delay);
1463 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1466BOOL client_auto_reconnect(freerdp* instance)
1468 return client_auto_reconnect_ex(instance,
nullptr);
1472static BOOL client_auto_reconnect_credentials_rejected(UINT32 error)
1476 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1477 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1478 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1479 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1480 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1481 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1482 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1483 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1491static BOOL client_auto_reconnect_do(freerdp* instance, BOOL retry, UINT32 numRetries,
1494 WINPR_ASSERT(instance);
1500 if ((maxRetries > 0) && (numRetries >= maxRetries))
1502 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1507 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1509 const SSIZE_T delay =
1510 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1515 if (freerdp_reconnect(instance))
1520 const UINT err = freerdp_get_last_error(instance->context);
1521 if (client_auto_reconnect_credentials_rejected(err))
1523 WLog_WARN(TAG,
"Autoreconnect aborted: credentials do not work [%s]",
1524 freerdp_get_last_error_name(err));
1527 if (err == FREERDP_ERROR_CONNECT_CANCELLED)
1529 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1533 for (SSIZE_T x = 0; x < delay / 10; x++)
1537 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1542static DWORD WINAPI handle_window_events(
void* parg)
1544 handle_window_events_t* arg = parg;
1547 while (arg->running)
1549 WINPR_ASSERT(arg->window_events);
1550 if (!arg->window_events(arg->instance))
1552 WLog_ERR(TAG,
"window_events failed!");
1559BOOL client_auto_reconnect_ex(freerdp* instance, window_events_fkt_t window_events)
1563 UINT32 numRetries = 0;
1564 rdpSettings* settings =
nullptr;
1569 WINPR_ASSERT(instance->context);
1571 settings = instance->context->settings;
1572 WINPR_ASSERT(settings);
1574 const UINT32 maxRetries =
1578 error = freerdp_error_info(instance);
1581 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1583 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1584 freerdp_get_error_info_string(error));
1586 case ERRINFO_SUCCESS:
1588 WLog_INFO(TAG,
"Network disconnect!");
1591 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1598 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1602 const UINT err = freerdp_get_last_error(instance->context);
1603 if (client_auto_reconnect_credentials_rejected(err))
1605 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1606 freerdp_get_last_error_name(err));
1609 if (err == FREERDP_ERROR_CONNECT_CANCELLED)
1611 WLog_WARN(TAG,
"Connection aborted by user");
1615 handle_window_events_t arg = { .instance = instance,
1616 .window_events = window_events,
1618 HANDLE thread =
nullptr;
1620 thread = CreateThread(
nullptr, 0, handle_window_events, &arg, 0,
nullptr);
1621 const BOOL rc = client_auto_reconnect_do(instance, retry, numRetries, maxRetries);
1624 arg.running = FALSE;
1625 WaitForSingleObject(thread, INFINITE);
1626 CloseHandle(thread);
1632static BOOL common_inject_keypress(rdpContext* context,
const char* buffer,
size_t size)
1634 WCHAR wbuffer[64] = WINPR_C_ARRAY_INIT;
1635 const SSIZE_T len = ConvertUtf8NToWChar(buffer, size, wbuffer, ARRAYSIZE(wbuffer));
1639 rdpInput* input = context->input;
1640 WINPR_ASSERT(input);
1642 for (SSIZE_T x = 0; x < len; x++)
1644 const WCHAR code = wbuffer[x];
1645 freerdp_input_send_unicode_keyboard_event(input, 0, code);
1647 freerdp_input_send_unicode_keyboard_event(input, KBD_FLAGS_RELEASE, code);
1653static BOOL common_process_pipe(rdpContext* context,
const char* pipe)
1655 int fd = open(pipe, O_NONBLOCK | O_RDONLY);
1658 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1659 WLog_ERR(TAG,
"pipe '%s' open returned %s [%d]", pipe,
1660 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1663 while (!freerdp_shall_disconnect_context(context))
1665 char buffer[64] = WINPR_C_ARRAY_INIT;
1667 ssize_t rd = read(fd, buffer,
sizeof(buffer) - 1);
1670 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1671 if ((errno == EAGAIN) || (errno == 0))
1678 WLog_ERR(TAG,
"pipe '%s' read returned %s [%d]", pipe,
1679 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1684 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1685 WLog_ERR(TAG,
"pipe '%s' read returned %s [%d]", pipe,
1686 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1691 if (!common_inject_keypress(context, buffer, WINPR_ASSERTING_INT_CAST(
size_t, rd)))
1699static void common_cleanup_pipe(WINPR_ATTR_UNUSED
int signum, WINPR_ATTR_UNUSED
const char* signame,
1702 const char* pipe = context;
1708static DWORD WINAPI common_handle_pipe(
void* arg)
1710 rdpClientContext* cctx = arg;
1713 rdpContext* context = &cctx->context;
1714 WINPR_ASSERT(context);
1716 rdpSettings* settings = context->settings;
1717 WINPR_ASSERT(settings);
1722 const int rc = mkfifo(pipe, S_IWUSR | S_IRUSR);
1725 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1726 WLog_ERR(TAG,
"Failed to create named pipe '%s': %s [%d]", pipe,
1727 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1731 void* ctx = WINPR_CAST_CONST_PTR_AWAY(pipe,
void*);
1732 if (freerdp_add_signal_cleanup_handler(ctx, common_cleanup_pipe))
1735 common_process_pipe(context, pipe);
1737 freerdp_del_signal_cleanup_handler(ctx, common_cleanup_pipe);
1746static BOOL commonPreConnect(freerdp* instance)
1748 WINPR_ASSERT(instance);
1749 WINPR_ASSERT(requireRdpClientContext(instance->context));
1751 rdpClientContext* cctx = (rdpClientContext*)instance->context;
1753 return IFCALLRESULT(TRUE, cctx->PreConnect, instance);
1756static BOOL commonPostConnect(freerdp* instance)
1758 WINPR_ASSERT(instance);
1759 WINPR_ASSERT(requireRdpClientContext(instance->context));
1761 rdpClientContext* cctx = (rdpClientContext*)instance->context;
1763 if (!IFCALLRESULT(TRUE, cctx->PostConnect, instance))
1771 cctx->pipethread = CreateThread(
nullptr, 0, common_handle_pipe, cctx, 0,
nullptr);
1772 if (!cctx->pipethread)
1775 WLog_WARN(TAG,
"/kbd:pipe:<filename> not supported on windows");
1782static void commonPostDisconnect(freerdp* instance)
1784 WINPR_ASSERT(instance);
1785 WINPR_ASSERT(requireRdpClientContext(instance->context));
1787 rdpClientContext* cctx = (rdpClientContext*)instance->context;
1790 if (cctx->pipethread)
1792 (void)WaitForSingleObject(cctx->pipethread, INFINITE);
1793 (void)CloseHandle(cctx->pipethread);
1794 cctx->pipethread =
nullptr;
1798 IFCALL(cctx->PostDisconnect, instance);
1803static void commonPostFinalDisconnect(freerdp* instance)
1805 WINPR_ASSERT(instance);
1806 WINPR_ASSERT(requireRdpClientContext(instance->context));
1808 rdpClientContext* cctx = (rdpClientContext*)instance->context;
1810 IFCALL(cctx->PostFinalDisconnect, instance);
1815BOOL freerdp_client_common_pre_connect(rdpContext* context)
1817 WINPR_ASSERT(context);
1819 if (requireRdpClientContext(context))
1821 rdpClientContext* cctx = (rdpClientContext*)context;
1822 freerdp* instance = context->instance;
1824 cctx->PreConnect = instance->PreConnect;
1825 cctx->PostConnect = instance->PostConnect;
1826 cctx->PostDisconnect = instance->PostDisconnect;
1827 cctx->PostFinalDisconnect = instance->PostFinalDisconnect;
1829 instance->PreConnect = commonPreConnect;
1830 instance->PostConnect = commonPostConnect;
1831 instance->PostDisconnect = commonPostDisconnect;
1832 instance->PostFinalDisconnect = commonPostFinalDisconnect;
1837int freerdp_client_common_stop(rdpContext* context)
1839 freerdp_abort_connect_context(context);
1841 if (requireRdpClientContext(context))
1844 rdpClientContext* cctx = (rdpClientContext*)context;
1848 (void)WaitForSingleObject(cctx->thread, INFINITE);
1849 (void)CloseHandle(cctx->thread);
1850 cctx->thread =
nullptr;
1852#if defined(WITH_AAD)
1853 aad_auth_helper_stop(cctx->aadHelper);
1854 cctx->aadHelper =
nullptr;
1861#if defined(CHANNEL_ENCOMSP_CLIENT)
1862BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1869 rdpClientContext* cctx = (rdpClientContext*)encomsp->custom;
1871 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1872 if (!cctx || !requireRdpClientContext(&cctx->context))
1875 state = cctx->controlToggle;
1876 cctx->controlToggle = !cctx->controlToggle;
1877 return freerdp_client_encomsp_set_control(encomsp, state);
1880BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1887 pdu.ParticipantId = encomsp->participantId;
1888 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1891 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1893 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1894 return rc == CHANNEL_RC_OK;
1898client_encomsp_participant_created(EncomspClientContext* context,
1903 if (!context || !context->custom || !participantCreated)
1904 return ERROR_INVALID_PARAMETER;
1906 rdpClientContext* cctx = (rdpClientContext*)context->custom;
1908 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1909 if (!cctx || !requireRdpClientContext(&cctx->context))
1910 return ERROR_INVALID_PARAMETER;
1912 rdpSettings* settings = cctx->context.settings;
1913 WINPR_ASSERT(settings);
1915 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1916 context->participantId = participantCreated->ParticipantId;
1919 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1920 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1922 if (!freerdp_client_encomsp_set_control(context, TRUE))
1923 return ERROR_INTERNAL_ERROR;
1929 return ERROR_INTERNAL_ERROR;
1932 return CHANNEL_RC_OK;
1935static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1938 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1939 if (!cctx || !requireRdpClientContext(&cctx->context))
1942 cctx->encomsp = encomsp;
1943 encomsp->custom = (
void*)cctx;
1944 encomsp->ParticipantCreated = client_encomsp_participant_created;
1947static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1951 encomsp->custom =
nullptr;
1952 encomsp->ParticipantCreated =
nullptr;
1957 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1958 if (requireRdpClientContext(&cctx->context))
1959 cctx->encomsp =
nullptr;
1964void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1965 const ChannelConnectedEventArgs* e)
1967 rdpClientContext* cctx = (rdpClientContext*)context;
1975#if defined(CHANNEL_AINPUT_CLIENT)
1976 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1979 WINPR_ASSERT(requireRdpClientContext(context));
1980 if (!requireRdpClientContext(context))
1982 cctx->ainput = (AInputClientContext*)e->pInterface;
1985#if defined(CHANNEL_RDPEI_CLIENT)
1986 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1988 WINPR_ASSERT(requireRdpClientContext(context));
1989 if (!requireRdpClientContext(context))
1991 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1994#if defined(CHANNEL_RDPGFX_CLIENT)
1995 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1997 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
2000#if defined(CHANNEL_GEOMETRY_CLIENT)
2001 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
2003 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
2006#if defined(CHANNEL_VIDEO_CLIENT)
2007 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
2009 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
2011 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
2013 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
2016#if defined(CHANNEL_ENCOMSP_CLIENT)
2017 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
2019 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
2024void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
2025 const ChannelDisconnectedEventArgs* e)
2027 rdpClientContext* cctx = (rdpClientContext*)context;
2035#if defined(CHANNEL_AINPUT_CLIENT)
2036 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
2038 WINPR_ASSERT(requireRdpClientContext(context));
2039 if (!requireRdpClientContext(context))
2041 cctx->ainput =
nullptr;
2044#if defined(CHANNEL_RDPEI_CLIENT)
2045 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
2047 WINPR_ASSERT(requireRdpClientContext(context));
2048 if (!requireRdpClientContext(context))
2050 cctx->rdpei =
nullptr;
2053#if defined(CHANNEL_RDPGFX_CLIENT)
2054 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
2056 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
2059#if defined(CHANNEL_GEOMETRY_CLIENT)
2060 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
2062 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
2065#if defined(CHANNEL_VIDEO_CLIENT)
2066 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
2068 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
2070 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
2072 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
2075#if defined(CHANNEL_ENCOMSP_CLIENT)
2076 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
2078 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
2083BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
2085 BOOL handled = FALSE;
2088 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2089 if (!cctx || !requireRdpClientContext(&cctx->context))
2092 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2093 if (state != CONNECTION_STATE_ACTIVE)
2096#if defined(CHANNEL_AINPUT_CLIENT)
2098 AInputClientContext* ainput = cctx->ainput;
2105 INT32 value = mflags & 0xFF;
2107 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
2108 value = -1 * (0x100 - value);
2114 if (mflags & PTR_FLAGS_WHEEL)
2116 flags |= AINPUT_FLAGS_WHEEL;
2120 if (mflags & PTR_FLAGS_HWHEEL)
2122 flags |= AINPUT_FLAGS_WHEEL;
2126 WINPR_ASSERT(ainput->AInputSendInputEvent);
2127 rc = ainput->AInputSendInputEvent(ainput, flags, x, y);
2128 if (rc == CHANNEL_RC_OK)
2134 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
2139#if defined(CHANNEL_AINPUT_CLIENT)
2141static inline BOOL ainput_send_diff_event(AInputClientContext* ainput, UINT64 flags, INT32 x,
2144 WINPR_ASSERT(ainput);
2145 WINPR_ASSERT(ainput->AInputSendInputEvent);
2147 const UINT rc = ainput->AInputSendInputEvent(ainput, flags, x, y);
2149 return rc == CHANNEL_RC_OK;
2154static bool button_pressed(
const rdpClientContext* cctx)
2157 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2158 if (!cctx || !requireRdpClientContext(&cctx->context))
2161 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
2163 const BOOL cur = cctx->pressed_buttons[x];
2170BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
2173 BOOL handled = FALSE;
2176 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2177 if (!cctx || !requireRdpClientContext(&cctx->context))
2180 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2181 if (state != CONNECTION_STATE_ACTIVE)
2184 if (mflags & PTR_FLAGS_BUTTON1)
2185 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
2186 if (mflags & PTR_FLAGS_BUTTON2)
2187 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
2188 if (mflags & PTR_FLAGS_BUTTON3)
2189 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
2191 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
2194 if (!button_pressed(cctx))
2198 const BOOL haveRelative =
2200 if (relative && haveRelative)
2202 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
2203 WINPR_ASSERTING_INT_CAST(int16_t, x),
2204 WINPR_ASSERTING_INT_CAST(int16_t, y));
2207#if defined(CHANNEL_AINPUT_CLIENT)
2209 AInputClientContext* ainput = cctx->ainput;
2214 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
2215 flags |= AINPUT_FLAGS_HAVE_REL;
2218 flags |= AINPUT_FLAGS_REL;
2220 if (mflags & PTR_FLAGS_DOWN)
2221 flags |= AINPUT_FLAGS_DOWN;
2222 if (mflags & PTR_FLAGS_BUTTON1)
2223 flags |= AINPUT_FLAGS_BUTTON1;
2224 if (mflags & PTR_FLAGS_BUTTON2)
2225 flags |= AINPUT_FLAGS_BUTTON2;
2226 if (mflags & PTR_FLAGS_BUTTON3)
2227 flags |= AINPUT_FLAGS_BUTTON3;
2228 if (mflags & PTR_FLAGS_MOVE)
2229 flags |= AINPUT_FLAGS_MOVE;
2230 handled = ainput_send_diff_event(ainput, flags, x, y);
2240 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2247 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2248 (UINT16)cctx->lastY);
2253BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
2256 BOOL handled = FALSE;
2258 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2260 if (!cctx || !requireRdpClientContext(&cctx->context))
2263 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2264 if (state != CONNECTION_STATE_ACTIVE)
2267 if (mflags & PTR_XFLAGS_BUTTON1)
2268 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
2269 if (mflags & PTR_XFLAGS_BUTTON2)
2270 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
2272 const BOOL haveRelative =
2274 if (relative && haveRelative)
2276 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
2277 WINPR_ASSERTING_INT_CAST(int16_t, x),
2278 WINPR_ASSERTING_INT_CAST(int16_t, y));
2281#if defined(CHANNEL_AINPUT_CLIENT)
2283 AInputClientContext* ainput = cctx->ainput;
2289 flags |= AINPUT_FLAGS_REL;
2290 if (mflags & PTR_XFLAGS_DOWN)
2291 flags |= AINPUT_FLAGS_DOWN;
2292 if (mflags & PTR_XFLAGS_BUTTON1)
2293 flags |= AINPUT_XFLAGS_BUTTON1;
2294 if (mflags & PTR_XFLAGS_BUTTON2)
2295 flags |= AINPUT_XFLAGS_BUTTON2;
2297 handled = ainput_send_diff_event(ainput, flags, x, y);
2307 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2314 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2315 (UINT16)cctx->lastY);
2322static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
2326 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2327 if (!cctx || !requireRdpClientContext(&cctx->context))
2330 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
2331 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
2332 WINPR_ASSERT(contact);
2333 WINPR_ASSERT(contact->x <= UINT16_MAX);
2334 WINPR_ASSERT(contact->y <= UINT16_MAX);
2336 switch (contact->count)
2339 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
2340 contact->x, contact->y);
2342 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
2343 contact->x, contact->y);
2345 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
2346 contact->x, contact->y);
2348 return freerdp_client_send_extended_button_event(
2349 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2351 return freerdp_client_send_extended_button_event(
2352 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2360static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2363 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2364 WINPR_ASSERT(contact);
2366 if (!cctx || !requireRdpClientContext(&cctx->context))
2369#if defined(CHANNEL_RDPEI_CLIENT)
2370 RdpeiClientContext* rdpei = cctx->rdpei;
2373 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2377 if (rdpei->TouchRawEvent)
2379 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
2380 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2381 ? CONTACT_DATA_PRESSURE_PRESENT
2385 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2386 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2387 RDPINPUT_CONTACT_FLAG_INCONTACT,
2388 contactFlags, contact->pressure);
2389 if (rc1 != CHANNEL_RC_OK)
2392 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
2393 &contactId, flags, contactFlags, contact->pressure);
2394 if (rc2 != CHANNEL_RC_OK)
2399 WINPR_ASSERT(rdpei->TouchEnd);
2400 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2401 if (rc != CHANNEL_RC_OK)
2406 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2407 "-DCHANNEL_RDPEI_CLIENT=ON");
2408 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2413static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2416 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2417 WINPR_ASSERT(contact);
2419 if (!cctx || !requireRdpClientContext(&cctx->context))
2422#if defined(CHANNEL_RDPEI_CLIENT)
2423 RdpeiClientContext* rdpei = cctx->rdpei;
2427 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2431 if (rdpei->TouchRawEvent)
2433 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
2434 RDPINPUT_CONTACT_FLAG_INCONTACT;
2435 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2436 ? CONTACT_DATA_PRESSURE_PRESENT
2438 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2439 flags, contactFlags, contact->pressure);
2440 if (rc != CHANNEL_RC_OK)
2445 WINPR_ASSERT(rdpei->TouchBegin);
2446 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
2447 if (rc != CHANNEL_RC_OK)
2453 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2454 "-DCHANNEL_RDPEI_CLIENT=ON");
2455 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2460static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
2464 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2466 if (!cctx || !requireRdpClientContext(&cctx->context))
2469 const UINT16 flags = PTR_FLAGS_MOVE;
2471 WINPR_ASSERT(contact);
2472 WINPR_ASSERT(contact->x <= UINT16_MAX);
2473 WINPR_ASSERT(contact->y <= UINT16_MAX);
2474 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
2478static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2481 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2482 WINPR_ASSERT(contact);
2484 if (!cctx || !requireRdpClientContext(&cctx->context))
2487#if defined(CHANNEL_RDPEI_CLIENT)
2488 RdpeiClientContext* rdpei = cctx->rdpei;
2491 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2495 if (rdpei->TouchRawEvent)
2497 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2498 RDPINPUT_CONTACT_FLAG_INCONTACT;
2499 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2500 ? CONTACT_DATA_PRESSURE_PRESENT
2502 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2503 flags, contactFlags, contact->pressure);
2504 if (rc != CHANNEL_RC_OK)
2509 WINPR_ASSERT(rdpei->TouchUpdate);
2510 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2511 if (rc != CHANNEL_RC_OK)
2517 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2518 "-DCHANNEL_RDPEI_CLIENT=ON");
2519 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2524static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2527 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2528 WINPR_ASSERT(contact);
2530 if (!cctx || !requireRdpClientContext(&cctx->context))
2533#if defined(CHANNEL_RDPEI_CLIENT)
2534 RdpeiClientContext* rdpei = cctx->rdpei;
2537 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2541 if (rdpei->TouchRawEvent)
2543 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2544 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2545 ? CONTACT_DATA_PRESSURE_PRESENT
2547 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2548 flags, contactFlags, contact->pressure);
2549 if (rc != CHANNEL_RC_OK)
2554 WINPR_ASSERT(rdpei->TouchUpdate);
2555 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2556 if (rc != CHANNEL_RC_OK)
2562 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2563 "-DCHANNEL_RDPEI_CLIENT=ON");
2564 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2569static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2570 UINT32 pressure, INT32 x, INT32 y,
2574 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2575 WINPR_ASSERT(pcontact);
2577 if (!cctx || !requireRdpClientContext(&cctx->context))
2580 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2584 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2585 if (newcontact || (contact->id == touchId))
2587 contact->id = touchId;
2588 contact->flags = flags;
2589 contact->pressure = pressure;
2592 contact->count = WINPR_ASSERTING_INT_CAST(UINT32, i + 1);
2594 *pcontact = *contact;
2596 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2609BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2610 UINT32 pressure, INT32 x, INT32 y)
2613 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2615 if (!cctx || !requireRdpClientContext(&cctx->context))
2619 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2622 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2623 if (state != CONNECTION_STATE_ACTIVE)
2628 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2631 switch (flags & mask)
2633 case FREERDP_TOUCH_DOWN:
2634 return freerdp_handle_touch_down(cctx, &contact);
2635 case FREERDP_TOUCH_UP:
2636 return freerdp_handle_touch_up(cctx, &contact);
2637 case FREERDP_TOUCH_MOTION:
2638 return freerdp_handle_touch_motion(cctx, &contact);
2639 case FREERDP_TOUCH_CANCEL:
2640 return freerdp_handle_touch_cancel(cctx, &contact);
2642 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2647BOOL freerdp_client_load_channels(freerdp* instance)
2649 WINPR_ASSERT(instance);
2650 WINPR_ASSERT(instance->context);
2652 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2654 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2660int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2662 const char* str_data = freerdp_get_logon_error_info_data(data);
2663 const char* str_type = freerdp_get_logon_error_info_type(type);
2665 if (!instance || !instance->context)
2668 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2673static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2677 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2679 if (!cctx || !requireRdpClientContext(&cctx->context))
2682 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2685 if (deviceid == pen->deviceid)
2696static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2699 static const INT32 null_deviceid = 0;
2702 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2703 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2705 if (!cctx || !requireRdpClientContext(&cctx->context))
2708 if (freerdp_client_is_pen(cctx, deviceid))
2710 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2721 pen->deviceid = deviceid;
2722 pen->max_pressure = pressure;
2725 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2729 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2733BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2736 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2738 if (!cctx || !requireRdpClientContext(&cctx->context))
2741 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2742 if (state != CONNECTION_STATE_ACTIVE)
2745#if defined(CHANNEL_RDPEI_CLIENT)
2746 if ((flags & FREERDP_PEN_REGISTER) != 0)
2748 va_list args = WINPR_C_ARRAY_INIT;
2750 va_start(args, deviceid);
2751 double pressure = va_arg(args,
double);
2753 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2759 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2763 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2765 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2767 RdpeiClientContext* rdpei = cctx->rdpei;
2768 WINPR_ASSERT(rdpei);
2770 UINT32 normalizedpressure = 1024;
2773 UINT16 rotation = 0;
2776 va_list args = WINPR_C_ARRAY_INIT;
2777 va_start(args, deviceid);
2779 x = va_arg(args, INT32);
2780 y = va_arg(args, INT32);
2781 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2783 const double pressure = va_arg(args,
double);
2784 const double np = (pressure * 1024.0) / pen->max_pressure;
2785 normalizedpressure = (UINT32)lround(np);
2786 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2787 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2789 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2791 const unsigned arg = va_arg(args,
unsigned);
2792 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2793 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2795 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2797 const int arg = va_arg(args,
int);
2798 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2799 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2801 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2803 const int arg = va_arg(args,
int);
2804 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2805 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2809 if ((flags & FREERDP_PEN_PRESS) != 0)
2813 flags = FREERDP_PEN_MOTION |
2814 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2815 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2816 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2818 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2820 if (!pen->pressed ||
2821 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2822 flags = FREERDP_PEN_MOTION |
2823 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2825 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2828 flags |= pen->flags;
2829 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2830 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2831 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2832 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2836 if ((flags & FREERDP_PEN_PRESS) != 0)
2838 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2839 pen->hovering = FALSE;
2840 pen->pressed = TRUE;
2842 WINPR_ASSERT(rdpei->PenBegin);
2843 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2844 normalizedpressure, rotation, tiltX, tiltY);
2845 return rc == CHANNEL_RC_OK;
2847 else if ((flags & FREERDP_PEN_MOTION) != 0)
2849 UINT rc = ERROR_INTERNAL_ERROR;
2852 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2855 WINPR_ASSERT(rdpei->PenUpdate);
2856 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2857 rotation, tiltX, tiltY);
2859 else if (pen->hovering)
2861 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2863 WINPR_ASSERT(rdpei->PenHoverUpdate);
2864 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2865 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2869 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2870 pen->hovering = TRUE;
2872 WINPR_ASSERT(rdpei->PenHoverBegin);
2873 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2874 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2876 return rc == CHANNEL_RC_OK;
2878 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2880 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2881 pen->pressed = FALSE;
2882 pen->hovering = TRUE;
2884 WINPR_ASSERT(rdpei->PenUpdate);
2885 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2886 normalizedpressure, rotation, tiltX, tiltY);
2887 if (rc != CHANNEL_RC_OK)
2889 WINPR_ASSERT(rdpei->PenEnd);
2890 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2891 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2892 return re == CHANNEL_RC_OK;
2895 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2897 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2898 "-DCHANNEL_RDPEI_CLIENT=ON");
2904BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2907 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2909 if (!cctx || !requireRdpClientContext(&cctx->context))
2912 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2913 if (state != CONNECTION_STATE_ACTIVE)
2916#if defined(CHANNEL_RDPEI_CLIENT)
2917 RdpeiClientContext* rdpei = cctx->rdpei;
2922 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2927 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2928 pen->hovering = FALSE;
2930 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2931 if (rc != CHANNEL_RC_OK)
2937 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2938 "-DCHANNEL_RDPEI_CLIENT=ON");
2943BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2946 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2948 if (!cctx || !requireRdpClientContext(&cctx->context))
2954 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2957 if (pen->deviceid == deviceid)
2964BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2967 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2969 if (!cctx || !requireRdpClientContext(&cctx->context))
2972 const rdpSettings* settings = cctx->context.settings;
2975 BOOL ainput = FALSE;
2976#if defined(CHANNEL_AINPUT_CLIENT)
2977 ainput = cctx->ainput !=
nullptr;
2980 return useRelative && (haveRelative || ainput);
2983#if defined(WITH_AAD)
2984WINPR_ATTR_MALLOC(free, 1)
2985static
char* get_redirect_uri(const rdpSettings* settings)
2987 char* redirect_uri =
nullptr;
2991 const char* redirect_fmt =
2994 const char* tenantid =
"common";
2998 if (tenantid && redirect_fmt)
3003 size_t redirect_len = 0;
3004 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
3010 const char* redirect_fmt =
3013 size_t redirect_len = 0;
3014 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
3016 return redirect_uri;
3021WINPR_ATTR_MALLOC(free, 1)
3022static
char* get_login_hint(const rdpSettings* settings, FreeRDP_Settings_Keys_String primary,
3023 FreeRDP_Settings_Keys_String secondary)
3025 const FreeRDP_Settings_Keys_String keys[] = { primary, secondary };
3026 for (
size_t x = 0; x < ARRAYSIZE(keys); x++)
3031 if (!user || !strchr(user,
'@') || strchr(user,
'\\'))
3034 char* encoded = winpr_str_url_encode(user, strlen(user));
3038 char* param =
nullptr;
3040 winpr_asprintf(¶m, &len,
"&login_hint=%s", encoded);
3047WINPR_ATTR_MALLOC(free, 1)
3048static
char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
3051 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3055 if (!cctx || !requireRdpClientContext(&cctx->context))
3058 const rdpSettings* settings = cctx->context.settings;
3060 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
3061 AAD_WELLKNOWN_authorization_endpoint);
3064 if (!client_id || !ep || !scope)
3067 char* redirect_uri = get_redirect_uri(settings);
3069 char* login_hint = get_login_hint(settings, FreeRDP_GatewayUsername, FreeRDP_Username);
3070 char* url =
nullptr;
3071 if (redirect_uri && login_hint)
3072 winpr_asprintf(&url, plen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s%s",
3073 ep, client_id, scope, redirect_uri, login_hint);
3079WINPR_ATTR_MALLOC(free, 1)
3080static
char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
3083 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3087 if (!cctx || !requireRdpClientContext(&cctx->context))
3090 const rdpSettings* settings = cctx->context.settings;
3092 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
3093 AAD_WELLKNOWN_authorization_endpoint);
3096 if (!client_id || !ep || !scope)
3099 char* redirect_uri = get_redirect_uri(settings);
3103 char* url =
nullptr;
3105 const char* code = va_arg(ap,
const char*);
3106 winpr_asprintf(&url, plen,
3107 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
3108 code, client_id, scope, redirect_uri);
3113WINPR_ATTR_MALLOC(free, 1)
3114static
char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
3117 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3121 if (!cctx || !requireRdpClientContext(&cctx->context))
3124 const rdpSettings* settings = cctx->context.settings;
3125 char* url =
nullptr;
3126 char* redirect_uri = get_redirect_uri(settings);
3128 char* login_hint = get_login_hint(settings, FreeRDP_Username, FreeRDP_GatewayUsername);
3131 if (!client_id || !redirect_uri || !login_hint)
3135 const char* scope = va_arg(ap,
const char*);
3140 const char* ep = freerdp_utils_aad_get_wellknown_string(
3141 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
3142 winpr_asprintf(&url, plen,
3143 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s%s", ep,
3144 client_id, scope, redirect_uri, login_hint);
3154WINPR_ATTR_MALLOC(free, 1)
3155static
char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
3158 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3162 if (!cctx || !requireRdpClientContext(&cctx->context))
3165 const rdpSettings* settings = cctx->context.settings;
3167 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
3168 AAD_WELLKNOWN_authorization_endpoint);
3169 const char* scope = va_arg(ap,
const char*);
3170 const char* code = va_arg(ap,
const char*);
3171 const char* req_cnf = va_arg(ap,
const char*);
3173 if (!client_id || !ep || !scope || !code || !req_cnf)
3176 char* redirect_uri = get_redirect_uri(settings);
3180 char* url =
nullptr;
3184 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
3185 code, client_id, scope, redirect_uri, req_cnf);
3191char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
3194 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3196 if (!cctx || !requireRdpClientContext(&cctx->context))
3199 char* str =
nullptr;
3202 va_list ap = WINPR_C_ARRAY_INIT;
3206#if defined(WITH_AAD)
3207 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
3208 if (freerdp_oauth2_reset(cctx->oauth2))
3209 str = aad_auth_request(cctx, ap, &len);
3211 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
3212 str = aad_token_request(cctx, ap, &len);
3214 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
3215 if (freerdp_oauth2_reset(cctx->oauth2))
3216 str = avd_auth_request(cctx, ap, &len);
3218 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
3219 str = avd_token_request(cctx, ap, &len);
3227 char* safestr = freerdp_oauth2_append_state(cctx->oauth2, str, len,
nullptr);
3232BOOL client_common_save_session_info(WINPR_ATTR_UNUSED rdpContext* context, UINT32 type,
3235 char buffer[128] = WINPR_C_ARRAY_INIT;
3236 WLog_INFO(TAG,
"%s [%s]", freerdp_session_logon_type_str(type),
3237 freerdp_session_logon_type_data_str(type, data, buffer,
sizeof(buffer)));
3241char* freerdp_client_extract_aad_code(rdpClientContext* cctx,
const char* data,
size_t length)
3244 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3246 if (!cctx || !requireRdpClientContext(&cctx->context))
3248 return freerdp_oauth2_extract_code(cctx->oauth2, data, length);
3252static BOOL client_helper_get_access_token_va(freerdp* instance,
3253 WINPR_ATTR_UNUSED AccessTokenType tokenType,
3254 WINPR_ATTR_UNUSED
char** token,
3255 WINPR_ATTR_UNUSED
size_t count, va_list ap)
3257 WINPR_ASSERT(instance);
3258 WINPR_ASSERT(token);
3262 WINPR_ASSERT(requireRdpClientContext(instance->context));
3264#if defined(WITH_AAD)
3265 rdpClientContext* cctx = (rdpClientContext*)instance->context;
3272 if (!aad_auth_helper_is_running(cctx->aadHelper))
3274 aad_auth_helper_stop(cctx->aadHelper);
3275 cctx->aadHelper = aad_auth_helper_start(cctx);
3276 if (!cctx->aadHelper)
3281 aad_auth_helper_get_access_token_v(cctx->aadHelper, tokenType, token, count, ap);
3284 if (!rc && !aad_auth_helper_is_running(cctx->aadHelper))
3286 aad_auth_helper_stop(cctx->aadHelper);
3287 cctx->aadHelper =
nullptr;
3291 WLog_ERR(TAG,
"Build does not support AAD authentication");
3296BOOL client_failsafe_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
3300 va_list ap = WINPR_C_ARRAY_INIT;
3301 va_start(ap, count);
3302 const BOOL rc = client_helper_get_access_token_va(instance, tokenType, token, count, ap);
3308 va_list ap = WINPR_C_ARRAY_INIT;
3309 va_start(ap, count);
3310 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
3316BOOL client_helper_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
3319 va_list ap = WINPR_C_ARRAY_INIT;
3320 va_start(ap, count);
3321 const BOOL rc = client_helper_get_access_token_va(instance, tokenType, token, count, ap);
3327static BOOL is_scancode_key(UINT32 scancode)
3331 case RDP_SCANCODE_SPACE:
3332 case RDP_SCANCODE_CAPSLOCK:
3333 case RDP_SCANCODE_LMENU:
3334 case RDP_SCANCODE_RMENU:
3335 case RDP_SCANCODE_LWIN:
3336 case RDP_SCANCODE_RWIN:
3337 case RDP_SCANCODE_RCONTROL:
3338 case RDP_SCANCODE_LCONTROL:
3339 case RDP_SCANCODE_F1:
3340 case RDP_SCANCODE_F2:
3341 case RDP_SCANCODE_F3:
3342 case RDP_SCANCODE_F4:
3343 case RDP_SCANCODE_F5:
3344 case RDP_SCANCODE_F6:
3345 case RDP_SCANCODE_F7:
3346 case RDP_SCANCODE_F8:
3347 case RDP_SCANCODE_F9:
3348 case RDP_SCANCODE_F10:
3349 case RDP_SCANCODE_F11:
3350 case RDP_SCANCODE_F12:
3351 case RDP_SCANCODE_F13:
3352 case RDP_SCANCODE_F14:
3353 case RDP_SCANCODE_F15:
3354 case RDP_SCANCODE_F16:
3355 case RDP_SCANCODE_F17:
3356 case RDP_SCANCODE_F18:
3357 case RDP_SCANCODE_F19:
3358 case RDP_SCANCODE_F20:
3359 case RDP_SCANCODE_F21:
3360 case RDP_SCANCODE_F22:
3361 case RDP_SCANCODE_F23:
3362 case RDP_SCANCODE_F24:
3363 case RDP_SCANCODE_HOME:
3364 case RDP_SCANCODE_END:
3365 case RDP_SCANCODE_UP:
3366 case RDP_SCANCODE_DOWN:
3367 case RDP_SCANCODE_LEFT:
3368 case RDP_SCANCODE_RIGHT:
3369 case RDP_SCANCODE_PRIOR:
3370 case RDP_SCANCODE_NEXT:
3371 case RDP_SCANCODE_INSERT:
3372 case RDP_SCANCODE_DELETE:
3373 case RDP_SCANCODE_NUMLOCK:
3374 case RDP_SCANCODE_NUMPAD0:
3375 case RDP_SCANCODE_NUMPAD1:
3376 case RDP_SCANCODE_NUMPAD2:
3377 case RDP_SCANCODE_NUMPAD3:
3378 case RDP_SCANCODE_NUMPAD4:
3379 case RDP_SCANCODE_NUMPAD5:
3380 case RDP_SCANCODE_NUMPAD6:
3381 case RDP_SCANCODE_NUMPAD7:
3382 case RDP_SCANCODE_NUMPAD8:
3383 case RDP_SCANCODE_NUMPAD9:
3384 case RDP_SCANCODE_SYSREQ:
3385 case RDP_SCANCODE_SLEEP:
3386 case RDP_SCANCODE_CONVERT_JP:
3387 case RDP_SCANCODE_NONCONVERT_JP:
3388 case RDP_SCANCODE_RETURN_KP:
3389 case RDP_SCANCODE_RETURN:
3390 case RDP_SCANCODE_VOLUME_MUTE:
3391 case RDP_SCANCODE_VOLUME_DOWN:
3392 case RDP_SCANCODE_VOLUME_UP:
3398BOOL freerdp_client_send_key_as_unicode(rdpClientContext* cctx, UINT16 flags,
const char* str,
3399 UINT32 scancode, FREERDP_CLIENT_KBD_MOD modmask)
3401 const BOOL asKey = is_scancode_key(scancode);
3402 const BOOL modPressed =
3403 (modmask & (FREERDP_CLIENT_KBD_MOD_LCONTROL | FREERDP_CLIENT_KBD_MOD_RCONTROL |
3404 FREERDP_CLIENT_KBD_MOD_LMENU | FREERDP_CLIENT_KBD_MOD_RMENU |
3405 FREERDP_CLIENT_KBD_MOD_LWIN | FREERDP_CLIENT_KBD_MOD_RWIN)) != 0;
3406 WCHAR wbuffer[32] = WINPR_C_ARRAY_INIT;
3408 if (!asKey && !modPressed)
3409 rc = ConvertUtf8ToWChar(str, wbuffer, ARRAYSIZE(wbuffer));
3412 return freerdp_input_send_keyboard_event_ex(
3413 cctx->context.input, (flags & KBD_FLAGS_RELEASE) == 0, FALSE, scancode);
3415 for (SSIZE_T x = 0; x < rc; x++)
3417 if (!freerdp_input_send_unicode_keyboard_event(cctx->context.input, flags, wbuffer[x]))
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 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.