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_context(instance->context, token_ep, request, &resp_code, &response,
1393 WLog_ERR(TAG,
"access token request failed");
1397 if (resp_code != HTTP_STATUS_OK)
1399 char buffer[64] = WINPR_C_ARRAY_INIT;
1401 WLog_Print(log, WLOG_ERROR,
1402 "Server unwilling to provide access token; returned status code %s",
1403 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1404 if (response_length > 0)
1405 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1409 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1417 WLog_ERR(TAG,
"Build does not support AAD authentication");
1422SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1425 WINPR_UNUSED(instance);
1426 WINPR_ASSERT(instance->context);
1427 WINPR_UNUSED(userarg);
1428 WINPR_ASSERT(instance);
1431 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1433 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1439 if (strcmp(what,
"arm-transport") == 0)
1440 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1443 const rdpSettings* settings = instance->context->settings;
1447 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1456 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1457 "tech support for help if this keeps happening.",
1462 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1463 what, current + 1, max, delay);
1464 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1467BOOL client_auto_reconnect(freerdp* instance)
1469 return client_auto_reconnect_ex(instance,
nullptr);
1473static BOOL client_auto_reconnect_credentials_rejected(UINT32 error)
1477 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1478 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1479 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1480 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1481 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1482 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1483 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1484 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1492static BOOL client_auto_reconnect_do(freerdp* instance, BOOL retry, UINT32 numRetries,
1495 WINPR_ASSERT(instance);
1501 if ((maxRetries > 0) && (numRetries >= maxRetries))
1503 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1508 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1510 const SSIZE_T delay =
1511 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1516 if (freerdp_reconnect(instance))
1521 const UINT err = freerdp_get_last_error(instance->context);
1522 if (client_auto_reconnect_credentials_rejected(err))
1524 WLog_WARN(TAG,
"Autoreconnect aborted: credentials do not work [%s]",
1525 freerdp_get_last_error_name(err));
1528 if (err == FREERDP_ERROR_CONNECT_CANCELLED)
1530 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1534 for (SSIZE_T x = 0; x < delay / 10; x++)
1538 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1543static DWORD WINAPI handle_window_events(
void* parg)
1545 handle_window_events_t* arg = parg;
1548 while (arg->running)
1550 WINPR_ASSERT(arg->window_events);
1551 if (!arg->window_events(arg->instance))
1553 WLog_ERR(TAG,
"window_events failed!");
1560BOOL client_auto_reconnect_ex(freerdp* instance, window_events_fkt_t window_events)
1564 UINT32 numRetries = 0;
1565 rdpSettings* settings =
nullptr;
1570 WINPR_ASSERT(instance->context);
1572 settings = instance->context->settings;
1573 WINPR_ASSERT(settings);
1575 const UINT32 maxRetries =
1579 error = freerdp_error_info(instance);
1582 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1584 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1585 freerdp_get_error_info_string(error));
1587 case ERRINFO_SUCCESS:
1589 WLog_INFO(TAG,
"Network disconnect!");
1592 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1599 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1603 const UINT err = freerdp_get_last_error(instance->context);
1604 if (client_auto_reconnect_credentials_rejected(err))
1606 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1607 freerdp_get_last_error_name(err));
1610 if (err == FREERDP_ERROR_CONNECT_CANCELLED)
1612 WLog_WARN(TAG,
"Connection aborted by user");
1616 handle_window_events_t arg = { .instance = instance,
1617 .window_events = window_events,
1619 HANDLE thread =
nullptr;
1621 thread = CreateThread(
nullptr, 0, handle_window_events, &arg, 0,
nullptr);
1622 const BOOL rc = client_auto_reconnect_do(instance, retry, numRetries, maxRetries);
1625 arg.running = FALSE;
1626 WaitForSingleObject(thread, INFINITE);
1627 CloseHandle(thread);
1633static BOOL common_inject_keypress(rdpContext* context,
const char* buffer,
size_t size)
1635 WCHAR wbuffer[64] = WINPR_C_ARRAY_INIT;
1636 const SSIZE_T len = ConvertUtf8NToWChar(buffer, size, wbuffer, ARRAYSIZE(wbuffer));
1640 rdpInput* input = context->input;
1641 WINPR_ASSERT(input);
1643 for (SSIZE_T x = 0; x < len; x++)
1645 const WCHAR code = wbuffer[x];
1646 freerdp_input_send_unicode_keyboard_event(input, 0, code);
1648 freerdp_input_send_unicode_keyboard_event(input, KBD_FLAGS_RELEASE, code);
1654static BOOL common_process_pipe(rdpContext* context,
const char* pipe)
1656 int fd = open(pipe, O_NONBLOCK | O_RDONLY);
1659 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1660 WLog_ERR(TAG,
"pipe '%s' open returned %s [%d]", pipe,
1661 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1664 while (!freerdp_shall_disconnect_context(context))
1666 char buffer[64] = WINPR_C_ARRAY_INIT;
1668 ssize_t rd = read(fd, buffer,
sizeof(buffer) - 1);
1671 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1672 if ((errno == EAGAIN) || (errno == 0))
1679 WLog_ERR(TAG,
"pipe '%s' read returned %s [%d]", pipe,
1680 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1685 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1686 WLog_ERR(TAG,
"pipe '%s' read returned %s [%d]", pipe,
1687 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1692 if (!common_inject_keypress(context, buffer, WINPR_ASSERTING_INT_CAST(
size_t, rd)))
1700static void common_cleanup_pipe(WINPR_ATTR_UNUSED
int signum, WINPR_ATTR_UNUSED
const char* signame,
1703 const char* pipe = context;
1709static DWORD WINAPI common_handle_pipe(
void* arg)
1711 rdpClientContext* cctx = arg;
1714 rdpContext* context = &cctx->context;
1715 WINPR_ASSERT(context);
1717 rdpSettings* settings = context->settings;
1718 WINPR_ASSERT(settings);
1723 const int rc = mkfifo(pipe, S_IWUSR | S_IRUSR);
1726 char ebuffer[256] = WINPR_C_ARRAY_INIT;
1727 WLog_ERR(TAG,
"Failed to create named pipe '%s': %s [%d]", pipe,
1728 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
1732 void* ctx = WINPR_CAST_CONST_PTR_AWAY(pipe,
void*);
1733 if (freerdp_add_signal_cleanup_handler(ctx, common_cleanup_pipe))
1736 common_process_pipe(context, pipe);
1738 freerdp_del_signal_cleanup_handler(ctx, common_cleanup_pipe);
1747static BOOL commonPreConnect(freerdp* instance)
1749 WINPR_ASSERT(instance);
1750 WINPR_ASSERT(requireRdpClientContext(instance->context));
1752 rdpClientContext* cctx = (rdpClientContext*)instance->context;
1754 return IFCALLRESULT(TRUE, cctx->PreConnect, instance);
1757static BOOL commonPostConnect(freerdp* instance)
1759 WINPR_ASSERT(instance);
1760 WINPR_ASSERT(requireRdpClientContext(instance->context));
1762 rdpClientContext* cctx = (rdpClientContext*)instance->context;
1764 if (!IFCALLRESULT(TRUE, cctx->PostConnect, instance))
1772 cctx->pipethread = CreateThread(
nullptr, 0, common_handle_pipe, cctx, 0,
nullptr);
1773 if (!cctx->pipethread)
1776 WLog_WARN(TAG,
"/kbd:pipe:<filename> not supported on windows");
1783static void commonPostDisconnect(freerdp* instance)
1785 WINPR_ASSERT(instance);
1786 WINPR_ASSERT(requireRdpClientContext(instance->context));
1788 rdpClientContext* cctx = (rdpClientContext*)instance->context;
1791 if (cctx->pipethread)
1793 (void)WaitForSingleObject(cctx->pipethread, INFINITE);
1794 (void)CloseHandle(cctx->pipethread);
1795 cctx->pipethread =
nullptr;
1799 IFCALL(cctx->PostDisconnect, instance);
1804static void commonPostFinalDisconnect(freerdp* instance)
1806 WINPR_ASSERT(instance);
1807 WINPR_ASSERT(requireRdpClientContext(instance->context));
1809 rdpClientContext* cctx = (rdpClientContext*)instance->context;
1811 IFCALL(cctx->PostFinalDisconnect, instance);
1816BOOL freerdp_client_common_pre_connect(rdpContext* context)
1818 WINPR_ASSERT(context);
1820 if (requireRdpClientContext(context))
1822 rdpClientContext* cctx = (rdpClientContext*)context;
1823 freerdp* instance = context->instance;
1825 cctx->PreConnect = instance->PreConnect;
1826 cctx->PostConnect = instance->PostConnect;
1827 cctx->PostDisconnect = instance->PostDisconnect;
1828 cctx->PostFinalDisconnect = instance->PostFinalDisconnect;
1830 instance->PreConnect = commonPreConnect;
1831 instance->PostConnect = commonPostConnect;
1832 instance->PostDisconnect = commonPostDisconnect;
1833 instance->PostFinalDisconnect = commonPostFinalDisconnect;
1838int freerdp_client_common_stop(rdpContext* context)
1840 freerdp_abort_connect_context(context);
1842 if (requireRdpClientContext(context))
1845 rdpClientContext* cctx = (rdpClientContext*)context;
1849 (void)WaitForSingleObject(cctx->thread, INFINITE);
1850 (void)CloseHandle(cctx->thread);
1851 cctx->thread =
nullptr;
1853#if defined(WITH_AAD)
1854 aad_auth_helper_stop(cctx->aadHelper);
1855 cctx->aadHelper =
nullptr;
1862#if defined(CHANNEL_ENCOMSP_CLIENT)
1863BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1870 rdpClientContext* cctx = (rdpClientContext*)encomsp->custom;
1872 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1873 if (!cctx || !requireRdpClientContext(&cctx->context))
1876 state = cctx->controlToggle;
1877 cctx->controlToggle = !cctx->controlToggle;
1878 return freerdp_client_encomsp_set_control(encomsp, state);
1881BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1888 pdu.ParticipantId = encomsp->participantId;
1889 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1892 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1894 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1895 return rc == CHANNEL_RC_OK;
1899client_encomsp_participant_created(EncomspClientContext* context,
1904 if (!context || !context->custom || !participantCreated)
1905 return ERROR_INVALID_PARAMETER;
1907 rdpClientContext* cctx = (rdpClientContext*)context->custom;
1909 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1910 if (!cctx || !requireRdpClientContext(&cctx->context))
1911 return ERROR_INVALID_PARAMETER;
1913 rdpSettings* settings = cctx->context.settings;
1914 WINPR_ASSERT(settings);
1916 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1917 context->participantId = participantCreated->ParticipantId;
1920 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1921 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1923 if (!freerdp_client_encomsp_set_control(context, TRUE))
1924 return ERROR_INTERNAL_ERROR;
1930 return ERROR_INTERNAL_ERROR;
1933 return CHANNEL_RC_OK;
1936static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1939 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1940 if (!cctx || !requireRdpClientContext(&cctx->context))
1943 cctx->encomsp = encomsp;
1944 encomsp->custom = (
void*)cctx;
1945 encomsp->ParticipantCreated = client_encomsp_participant_created;
1948static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1952 encomsp->custom =
nullptr;
1953 encomsp->ParticipantCreated =
nullptr;
1958 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1959 if (requireRdpClientContext(&cctx->context))
1960 cctx->encomsp =
nullptr;
1965void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1966 const ChannelConnectedEventArgs* e)
1968 rdpClientContext* cctx = (rdpClientContext*)context;
1976#if defined(CHANNEL_AINPUT_CLIENT)
1977 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1980 WINPR_ASSERT(requireRdpClientContext(context));
1981 if (!requireRdpClientContext(context))
1983 cctx->ainput = (AInputClientContext*)e->pInterface;
1986#if defined(CHANNEL_RDPEI_CLIENT)
1987 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1989 WINPR_ASSERT(requireRdpClientContext(context));
1990 if (!requireRdpClientContext(context))
1992 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1995#if defined(CHANNEL_RDPGFX_CLIENT)
1996 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1998 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
2001#if defined(CHANNEL_GEOMETRY_CLIENT)
2002 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
2004 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
2007#if defined(CHANNEL_VIDEO_CLIENT)
2008 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
2010 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
2012 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
2014 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
2017#if defined(CHANNEL_ENCOMSP_CLIENT)
2018 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
2020 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
2025void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
2026 const ChannelDisconnectedEventArgs* e)
2028 rdpClientContext* cctx = (rdpClientContext*)context;
2036#if defined(CHANNEL_AINPUT_CLIENT)
2037 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
2039 WINPR_ASSERT(requireRdpClientContext(context));
2040 if (!requireRdpClientContext(context))
2042 cctx->ainput =
nullptr;
2045#if defined(CHANNEL_RDPEI_CLIENT)
2046 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
2048 WINPR_ASSERT(requireRdpClientContext(context));
2049 if (!requireRdpClientContext(context))
2051 cctx->rdpei =
nullptr;
2054#if defined(CHANNEL_RDPGFX_CLIENT)
2055 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
2057 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
2060#if defined(CHANNEL_GEOMETRY_CLIENT)
2061 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
2063 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
2066#if defined(CHANNEL_VIDEO_CLIENT)
2067 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
2069 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
2071 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
2073 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
2076#if defined(CHANNEL_ENCOMSP_CLIENT)
2077 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
2079 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
2084BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
2086 BOOL handled = FALSE;
2089 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2090 if (!cctx || !requireRdpClientContext(&cctx->context))
2093 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2094 if (state != CONNECTION_STATE_ACTIVE)
2097#if defined(CHANNEL_AINPUT_CLIENT)
2099 AInputClientContext* ainput = cctx->ainput;
2106 INT32 value = mflags & 0xFF;
2108 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
2109 value = -1 * (0x100 - value);
2115 if (mflags & PTR_FLAGS_WHEEL)
2117 flags |= AINPUT_FLAGS_WHEEL;
2121 if (mflags & PTR_FLAGS_HWHEEL)
2123 flags |= AINPUT_FLAGS_WHEEL;
2127 WINPR_ASSERT(ainput->AInputSendInputEvent);
2128 rc = ainput->AInputSendInputEvent(ainput, flags, x, y);
2129 if (rc == CHANNEL_RC_OK)
2135 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
2140#if defined(CHANNEL_AINPUT_CLIENT)
2142static inline BOOL ainput_send_diff_event(AInputClientContext* ainput, UINT64 flags, INT32 x,
2145 WINPR_ASSERT(ainput);
2146 WINPR_ASSERT(ainput->AInputSendInputEvent);
2148 const UINT rc = ainput->AInputSendInputEvent(ainput, flags, x, y);
2150 return rc == CHANNEL_RC_OK;
2155static bool button_pressed(
const rdpClientContext* cctx)
2158 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2159 if (!cctx || !requireRdpClientContext(&cctx->context))
2162 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
2164 const BOOL cur = cctx->pressed_buttons[x];
2171BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
2174 BOOL handled = FALSE;
2177 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2178 if (!cctx || !requireRdpClientContext(&cctx->context))
2181 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2182 if (state != CONNECTION_STATE_ACTIVE)
2185 if (mflags & PTR_FLAGS_BUTTON1)
2186 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
2187 if (mflags & PTR_FLAGS_BUTTON2)
2188 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
2189 if (mflags & PTR_FLAGS_BUTTON3)
2190 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
2192 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
2195 if (!button_pressed(cctx))
2199 const BOOL haveRelative =
2201 if (relative && haveRelative)
2203 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
2204 WINPR_ASSERTING_INT_CAST(int16_t, x),
2205 WINPR_ASSERTING_INT_CAST(int16_t, y));
2208#if defined(CHANNEL_AINPUT_CLIENT)
2210 AInputClientContext* ainput = cctx->ainput;
2215 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
2216 flags |= AINPUT_FLAGS_HAVE_REL;
2219 flags |= AINPUT_FLAGS_REL;
2221 if (mflags & PTR_FLAGS_DOWN)
2222 flags |= AINPUT_FLAGS_DOWN;
2223 if (mflags & PTR_FLAGS_BUTTON1)
2224 flags |= AINPUT_FLAGS_BUTTON1;
2225 if (mflags & PTR_FLAGS_BUTTON2)
2226 flags |= AINPUT_FLAGS_BUTTON2;
2227 if (mflags & PTR_FLAGS_BUTTON3)
2228 flags |= AINPUT_FLAGS_BUTTON3;
2229 if (mflags & PTR_FLAGS_MOVE)
2230 flags |= AINPUT_FLAGS_MOVE;
2231 handled = ainput_send_diff_event(ainput, flags, x, y);
2241 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2248 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2249 (UINT16)cctx->lastY);
2254BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
2257 BOOL handled = FALSE;
2259 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2261 if (!cctx || !requireRdpClientContext(&cctx->context))
2264 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2265 if (state != CONNECTION_STATE_ACTIVE)
2268 if (mflags & PTR_XFLAGS_BUTTON1)
2269 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
2270 if (mflags & PTR_XFLAGS_BUTTON2)
2271 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
2273 const BOOL haveRelative =
2275 if (relative && haveRelative)
2277 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
2278 WINPR_ASSERTING_INT_CAST(int16_t, x),
2279 WINPR_ASSERTING_INT_CAST(int16_t, y));
2282#if defined(CHANNEL_AINPUT_CLIENT)
2284 AInputClientContext* ainput = cctx->ainput;
2290 flags |= AINPUT_FLAGS_REL;
2291 if (mflags & PTR_XFLAGS_DOWN)
2292 flags |= AINPUT_FLAGS_DOWN;
2293 if (mflags & PTR_XFLAGS_BUTTON1)
2294 flags |= AINPUT_XFLAGS_BUTTON1;
2295 if (mflags & PTR_XFLAGS_BUTTON2)
2296 flags |= AINPUT_XFLAGS_BUTTON2;
2298 handled = ainput_send_diff_event(ainput, flags, x, y);
2308 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2315 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2316 (UINT16)cctx->lastY);
2323static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
2327 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2328 if (!cctx || !requireRdpClientContext(&cctx->context))
2331 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
2332 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
2333 WINPR_ASSERT(contact);
2334 WINPR_ASSERT(contact->x <= UINT16_MAX);
2335 WINPR_ASSERT(contact->y <= UINT16_MAX);
2337 switch (contact->count)
2340 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
2341 contact->x, contact->y);
2343 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
2344 contact->x, contact->y);
2346 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
2347 contact->x, contact->y);
2349 return freerdp_client_send_extended_button_event(
2350 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2352 return freerdp_client_send_extended_button_event(
2353 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2361static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2364 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2365 WINPR_ASSERT(contact);
2367 if (!cctx || !requireRdpClientContext(&cctx->context))
2370#if defined(CHANNEL_RDPEI_CLIENT)
2371 RdpeiClientContext* rdpei = cctx->rdpei;
2374 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2378 if (rdpei->TouchRawEvent)
2380 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
2381 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2382 ? CONTACT_DATA_PRESSURE_PRESENT
2386 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2387 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2388 RDPINPUT_CONTACT_FLAG_INCONTACT,
2389 contactFlags, contact->pressure);
2390 if (rc1 != CHANNEL_RC_OK)
2393 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
2394 &contactId, flags, contactFlags, contact->pressure);
2395 if (rc2 != CHANNEL_RC_OK)
2400 WINPR_ASSERT(rdpei->TouchEnd);
2401 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2402 if (rc != CHANNEL_RC_OK)
2407 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2408 "-DCHANNEL_RDPEI_CLIENT=ON");
2409 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2414static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2417 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2418 WINPR_ASSERT(contact);
2420 if (!cctx || !requireRdpClientContext(&cctx->context))
2423#if defined(CHANNEL_RDPEI_CLIENT)
2424 RdpeiClientContext* rdpei = cctx->rdpei;
2428 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2432 if (rdpei->TouchRawEvent)
2434 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
2435 RDPINPUT_CONTACT_FLAG_INCONTACT;
2436 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2437 ? CONTACT_DATA_PRESSURE_PRESENT
2439 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2440 flags, contactFlags, contact->pressure);
2441 if (rc != CHANNEL_RC_OK)
2446 WINPR_ASSERT(rdpei->TouchBegin);
2447 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
2448 if (rc != CHANNEL_RC_OK)
2454 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2455 "-DCHANNEL_RDPEI_CLIENT=ON");
2456 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2461static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
2465 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2467 if (!cctx || !requireRdpClientContext(&cctx->context))
2470 const UINT16 flags = PTR_FLAGS_MOVE;
2472 WINPR_ASSERT(contact);
2473 WINPR_ASSERT(contact->x <= UINT16_MAX);
2474 WINPR_ASSERT(contact->y <= UINT16_MAX);
2475 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
2479static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2482 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2483 WINPR_ASSERT(contact);
2485 if (!cctx || !requireRdpClientContext(&cctx->context))
2488#if defined(CHANNEL_RDPEI_CLIENT)
2489 RdpeiClientContext* rdpei = cctx->rdpei;
2492 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2496 if (rdpei->TouchRawEvent)
2498 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2499 RDPINPUT_CONTACT_FLAG_INCONTACT;
2500 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2501 ? CONTACT_DATA_PRESSURE_PRESENT
2503 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2504 flags, contactFlags, contact->pressure);
2505 if (rc != CHANNEL_RC_OK)
2510 WINPR_ASSERT(rdpei->TouchUpdate);
2511 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2512 if (rc != CHANNEL_RC_OK)
2518 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2519 "-DCHANNEL_RDPEI_CLIENT=ON");
2520 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2525static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2528 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2529 WINPR_ASSERT(contact);
2531 if (!cctx || !requireRdpClientContext(&cctx->context))
2534#if defined(CHANNEL_RDPEI_CLIENT)
2535 RdpeiClientContext* rdpei = cctx->rdpei;
2538 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2542 if (rdpei->TouchRawEvent)
2544 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2545 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2546 ? CONTACT_DATA_PRESSURE_PRESENT
2548 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2549 flags, contactFlags, contact->pressure);
2550 if (rc != CHANNEL_RC_OK)
2555 WINPR_ASSERT(rdpei->TouchUpdate);
2556 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2557 if (rc != CHANNEL_RC_OK)
2563 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2564 "-DCHANNEL_RDPEI_CLIENT=ON");
2565 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2570static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2571 UINT32 pressure, INT32 x, INT32 y,
2575 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2576 WINPR_ASSERT(pcontact);
2578 if (!cctx || !requireRdpClientContext(&cctx->context))
2581 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2585 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2586 if (newcontact || (contact->id == touchId))
2588 contact->id = touchId;
2589 contact->flags = flags;
2590 contact->pressure = pressure;
2593 contact->count = WINPR_ASSERTING_INT_CAST(UINT32, i + 1);
2595 *pcontact = *contact;
2597 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2610BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2611 UINT32 pressure, INT32 x, INT32 y)
2614 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2616 if (!cctx || !requireRdpClientContext(&cctx->context))
2620 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2623 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2624 if (state != CONNECTION_STATE_ACTIVE)
2629 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2632 switch (flags & mask)
2634 case FREERDP_TOUCH_DOWN:
2635 return freerdp_handle_touch_down(cctx, &contact);
2636 case FREERDP_TOUCH_UP:
2637 return freerdp_handle_touch_up(cctx, &contact);
2638 case FREERDP_TOUCH_MOTION:
2639 return freerdp_handle_touch_motion(cctx, &contact);
2640 case FREERDP_TOUCH_CANCEL:
2641 return freerdp_handle_touch_cancel(cctx, &contact);
2643 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2648BOOL freerdp_client_load_channels(freerdp* instance)
2650 WINPR_ASSERT(instance);
2651 WINPR_ASSERT(instance->context);
2653 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2655 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2661int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2663 const char* str_data = freerdp_get_logon_error_info_data(data);
2664 const char* str_type = freerdp_get_logon_error_info_type(type);
2666 if (!instance || !instance->context)
2669 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2674static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2678 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2680 if (!cctx || !requireRdpClientContext(&cctx->context))
2683 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2686 if (deviceid == pen->deviceid)
2697static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2700 static const INT32 null_deviceid = 0;
2703 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2704 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2706 if (!cctx || !requireRdpClientContext(&cctx->context))
2709 if (freerdp_client_is_pen(cctx, deviceid))
2711 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2722 pen->deviceid = deviceid;
2723 pen->max_pressure = pressure;
2726 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2730 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2734BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2737 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2739 if (!cctx || !requireRdpClientContext(&cctx->context))
2742 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2743 if (state != CONNECTION_STATE_ACTIVE)
2746#if defined(CHANNEL_RDPEI_CLIENT)
2747 if ((flags & FREERDP_PEN_REGISTER) != 0)
2749 va_list args = WINPR_C_ARRAY_INIT;
2751 va_start(args, deviceid);
2752 double pressure = va_arg(args,
double);
2754 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2760 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2764 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2766 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2768 RdpeiClientContext* rdpei = cctx->rdpei;
2769 WINPR_ASSERT(rdpei);
2771 UINT32 normalizedpressure = 1024;
2774 UINT16 rotation = 0;
2777 va_list args = WINPR_C_ARRAY_INIT;
2778 va_start(args, deviceid);
2780 x = va_arg(args, INT32);
2781 y = va_arg(args, INT32);
2782 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2784 const double pressure = va_arg(args,
double);
2785 const double np = (pressure * 1024.0) / pen->max_pressure;
2786 normalizedpressure = (UINT32)lround(np);
2787 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2788 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2790 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2792 const unsigned arg = va_arg(args,
unsigned);
2793 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2794 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2796 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2798 const int arg = va_arg(args,
int);
2799 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2800 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2802 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2804 const int arg = va_arg(args,
int);
2805 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2806 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2810 if ((flags & FREERDP_PEN_PRESS) != 0)
2814 flags = FREERDP_PEN_MOTION |
2815 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2816 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2817 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2819 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2821 if (!pen->pressed ||
2822 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2823 flags = FREERDP_PEN_MOTION |
2824 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2826 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2829 flags |= pen->flags;
2830 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2831 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2832 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2833 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2837 if ((flags & FREERDP_PEN_PRESS) != 0)
2839 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2840 pen->hovering = FALSE;
2841 pen->pressed = TRUE;
2843 WINPR_ASSERT(rdpei->PenBegin);
2844 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2845 normalizedpressure, rotation, tiltX, tiltY);
2846 return rc == CHANNEL_RC_OK;
2848 else if ((flags & FREERDP_PEN_MOTION) != 0)
2850 UINT rc = ERROR_INTERNAL_ERROR;
2853 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2856 WINPR_ASSERT(rdpei->PenUpdate);
2857 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2858 rotation, tiltX, tiltY);
2860 else if (pen->hovering)
2862 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2864 WINPR_ASSERT(rdpei->PenHoverUpdate);
2865 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2866 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2870 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2871 pen->hovering = TRUE;
2873 WINPR_ASSERT(rdpei->PenHoverBegin);
2874 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2875 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2877 return rc == CHANNEL_RC_OK;
2879 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2881 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2882 pen->pressed = FALSE;
2883 pen->hovering = TRUE;
2885 WINPR_ASSERT(rdpei->PenUpdate);
2886 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2887 normalizedpressure, rotation, tiltX, tiltY);
2888 if (rc != CHANNEL_RC_OK)
2890 WINPR_ASSERT(rdpei->PenEnd);
2891 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2892 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2893 return re == CHANNEL_RC_OK;
2896 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2898 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2899 "-DCHANNEL_RDPEI_CLIENT=ON");
2905BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2908 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2910 if (!cctx || !requireRdpClientContext(&cctx->context))
2913 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2914 if (state != CONNECTION_STATE_ACTIVE)
2917#if defined(CHANNEL_RDPEI_CLIENT)
2918 RdpeiClientContext* rdpei = cctx->rdpei;
2923 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2928 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2929 pen->hovering = FALSE;
2931 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2932 if (rc != CHANNEL_RC_OK)
2938 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2939 "-DCHANNEL_RDPEI_CLIENT=ON");
2944BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2947 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2949 if (!cctx || !requireRdpClientContext(&cctx->context))
2955 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2958 if (pen->deviceid == deviceid)
2965BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2968 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2970 if (!cctx || !requireRdpClientContext(&cctx->context))
2973 const rdpSettings* settings = cctx->context.settings;
2976 BOOL ainput = FALSE;
2977#if defined(CHANNEL_AINPUT_CLIENT)
2978 ainput = cctx->ainput !=
nullptr;
2981 return useRelative && (haveRelative || ainput);
2984#if defined(WITH_AAD)
2985WINPR_ATTR_MALLOC(free, 1)
2986static
char* get_redirect_uri(const rdpSettings* settings)
2988 char* redirect_uri =
nullptr;
2992 const char* redirect_fmt =
2995 const char* tenantid =
"common";
2999 if (tenantid && redirect_fmt)
3004 size_t redirect_len = 0;
3005 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
3011 const char* redirect_fmt =
3014 size_t redirect_len = 0;
3015 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
3017 return redirect_uri;
3022WINPR_ATTR_MALLOC(free, 1)
3023static
char* get_login_hint(const rdpSettings* settings, FreeRDP_Settings_Keys_String primary,
3024 FreeRDP_Settings_Keys_String secondary)
3026 const FreeRDP_Settings_Keys_String keys[] = { primary, secondary };
3027 for (
size_t x = 0; x < ARRAYSIZE(keys); x++)
3032 if (!user || !strchr(user,
'@') || strchr(user,
'\\'))
3035 char* encoded = winpr_str_url_encode(user, strlen(user));
3039 char* param =
nullptr;
3041 winpr_asprintf(¶m, &len,
"&login_hint=%s", encoded);
3048WINPR_ATTR_MALLOC(free, 1)
3049static
char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
3052 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3056 if (!cctx || !requireRdpClientContext(&cctx->context))
3059 const rdpSettings* settings = cctx->context.settings;
3061 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
3062 AAD_WELLKNOWN_authorization_endpoint);
3065 if (!client_id || !ep || !scope)
3068 char* redirect_uri = get_redirect_uri(settings);
3070 char* login_hint = get_login_hint(settings, FreeRDP_GatewayUsername, FreeRDP_Username);
3071 char* url =
nullptr;
3072 if (redirect_uri && login_hint)
3073 winpr_asprintf(&url, plen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s%s",
3074 ep, client_id, scope, redirect_uri, login_hint);
3080WINPR_ATTR_MALLOC(free, 1)
3081static
char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
3084 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3088 if (!cctx || !requireRdpClientContext(&cctx->context))
3091 const rdpSettings* settings = cctx->context.settings;
3093 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
3094 AAD_WELLKNOWN_authorization_endpoint);
3097 if (!client_id || !ep || !scope)
3100 char* redirect_uri = get_redirect_uri(settings);
3104 char* url =
nullptr;
3106 const char* code = va_arg(ap,
const char*);
3107 winpr_asprintf(&url, plen,
3108 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
3109 code, client_id, scope, redirect_uri);
3114WINPR_ATTR_MALLOC(free, 1)
3115static
char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
3118 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3122 if (!cctx || !requireRdpClientContext(&cctx->context))
3125 const rdpSettings* settings = cctx->context.settings;
3126 char* url =
nullptr;
3127 char* redirect_uri = get_redirect_uri(settings);
3129 char* login_hint = get_login_hint(settings, FreeRDP_Username, FreeRDP_GatewayUsername);
3132 if (!client_id || !redirect_uri || !login_hint)
3136 const char* scope = va_arg(ap,
const char*);
3141 const char* ep = freerdp_utils_aad_get_wellknown_string(
3142 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
3143 winpr_asprintf(&url, plen,
3144 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s%s", ep,
3145 client_id, scope, redirect_uri, login_hint);
3155WINPR_ATTR_MALLOC(free, 1)
3156static
char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
3159 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3163 if (!cctx || !requireRdpClientContext(&cctx->context))
3166 const rdpSettings* settings = cctx->context.settings;
3168 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
3169 AAD_WELLKNOWN_authorization_endpoint);
3170 const char* scope = va_arg(ap,
const char*);
3171 const char* code = va_arg(ap,
const char*);
3172 const char* req_cnf = va_arg(ap,
const char*);
3174 if (!client_id || !ep || !scope || !code || !req_cnf)
3177 char* redirect_uri = get_redirect_uri(settings);
3181 char* url =
nullptr;
3185 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
3186 code, client_id, scope, redirect_uri, req_cnf);
3192char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
3195 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3197 if (!cctx || !requireRdpClientContext(&cctx->context))
3200 char* str =
nullptr;
3203 va_list ap = WINPR_C_ARRAY_INIT;
3207#if defined(WITH_AAD)
3208 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
3209 if (freerdp_oauth2_reset(cctx->oauth2))
3210 str = aad_auth_request(cctx, ap, &len);
3212 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
3213 str = aad_token_request(cctx, ap, &len);
3215 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
3216 if (freerdp_oauth2_reset(cctx->oauth2))
3217 str = avd_auth_request(cctx, ap, &len);
3219 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
3220 str = avd_token_request(cctx, ap, &len);
3228 char* safestr = freerdp_oauth2_append_state(cctx->oauth2, str, len,
nullptr);
3233BOOL client_common_save_session_info(WINPR_ATTR_UNUSED rdpContext* context, UINT32 type,
3236 char buffer[128] = WINPR_C_ARRAY_INIT;
3237 WLog_INFO(TAG,
"%s [%s]", freerdp_session_logon_type_str(type),
3238 freerdp_session_logon_type_data_str(type, data, buffer,
sizeof(buffer)));
3242char* freerdp_client_extract_aad_code(rdpClientContext* cctx,
const char* data,
size_t length)
3245 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3247 if (!cctx || !requireRdpClientContext(&cctx->context))
3249 return freerdp_oauth2_extract_code(cctx->oauth2, data, length);
3253static BOOL client_helper_get_access_token_va(freerdp* instance,
3254 WINPR_ATTR_UNUSED AccessTokenType tokenType,
3255 WINPR_ATTR_UNUSED
char** token,
3256 WINPR_ATTR_UNUSED
size_t count, va_list ap)
3258 WINPR_ASSERT(instance);
3259 WINPR_ASSERT(token);
3263 WINPR_ASSERT(requireRdpClientContext(instance->context));
3265#if defined(WITH_AAD)
3266 rdpClientContext* cctx = (rdpClientContext*)instance->context;
3273 if (!aad_auth_helper_is_running(cctx->aadHelper))
3275 aad_auth_helper_stop(cctx->aadHelper);
3276 cctx->aadHelper = aad_auth_helper_start(cctx);
3277 if (!cctx->aadHelper)
3282 aad_auth_helper_get_access_token_v(cctx->aadHelper, tokenType, token, count, ap);
3285 if (!rc && !aad_auth_helper_is_running(cctx->aadHelper))
3287 aad_auth_helper_stop(cctx->aadHelper);
3288 cctx->aadHelper =
nullptr;
3292 WLog_ERR(TAG,
"Build does not support AAD authentication");
3297BOOL client_failsafe_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
3301 va_list ap = WINPR_C_ARRAY_INIT;
3302 va_start(ap, count);
3303 const BOOL rc = client_helper_get_access_token_va(instance, tokenType, token, count, ap);
3309 va_list ap = WINPR_C_ARRAY_INIT;
3310 va_start(ap, count);
3311 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
3317BOOL client_helper_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
3320 va_list ap = WINPR_C_ARRAY_INIT;
3321 va_start(ap, count);
3322 const BOOL rc = client_helper_get_access_token_va(instance, tokenType, token, count, ap);
3328static BOOL is_scancode_key(UINT32 scancode)
3332 case RDP_SCANCODE_SPACE:
3333 case RDP_SCANCODE_CAPSLOCK:
3334 case RDP_SCANCODE_LMENU:
3335 case RDP_SCANCODE_RMENU:
3336 case RDP_SCANCODE_LWIN:
3337 case RDP_SCANCODE_RWIN:
3338 case RDP_SCANCODE_RCONTROL:
3339 case RDP_SCANCODE_LCONTROL:
3340 case RDP_SCANCODE_F1:
3341 case RDP_SCANCODE_F2:
3342 case RDP_SCANCODE_F3:
3343 case RDP_SCANCODE_F4:
3344 case RDP_SCANCODE_F5:
3345 case RDP_SCANCODE_F6:
3346 case RDP_SCANCODE_F7:
3347 case RDP_SCANCODE_F8:
3348 case RDP_SCANCODE_F9:
3349 case RDP_SCANCODE_F10:
3350 case RDP_SCANCODE_F11:
3351 case RDP_SCANCODE_F12:
3352 case RDP_SCANCODE_F13:
3353 case RDP_SCANCODE_F14:
3354 case RDP_SCANCODE_F15:
3355 case RDP_SCANCODE_F16:
3356 case RDP_SCANCODE_F17:
3357 case RDP_SCANCODE_F18:
3358 case RDP_SCANCODE_F19:
3359 case RDP_SCANCODE_F20:
3360 case RDP_SCANCODE_F21:
3361 case RDP_SCANCODE_F22:
3362 case RDP_SCANCODE_F23:
3363 case RDP_SCANCODE_F24:
3364 case RDP_SCANCODE_HOME:
3365 case RDP_SCANCODE_END:
3366 case RDP_SCANCODE_UP:
3367 case RDP_SCANCODE_DOWN:
3368 case RDP_SCANCODE_LEFT:
3369 case RDP_SCANCODE_RIGHT:
3370 case RDP_SCANCODE_PRIOR:
3371 case RDP_SCANCODE_NEXT:
3372 case RDP_SCANCODE_INSERT:
3373 case RDP_SCANCODE_DELETE:
3374 case RDP_SCANCODE_NUMLOCK:
3375 case RDP_SCANCODE_NUMPAD0:
3376 case RDP_SCANCODE_NUMPAD1:
3377 case RDP_SCANCODE_NUMPAD2:
3378 case RDP_SCANCODE_NUMPAD3:
3379 case RDP_SCANCODE_NUMPAD4:
3380 case RDP_SCANCODE_NUMPAD5:
3381 case RDP_SCANCODE_NUMPAD6:
3382 case RDP_SCANCODE_NUMPAD7:
3383 case RDP_SCANCODE_NUMPAD8:
3384 case RDP_SCANCODE_NUMPAD9:
3385 case RDP_SCANCODE_SYSREQ:
3386 case RDP_SCANCODE_SLEEP:
3387 case RDP_SCANCODE_CONVERT_JP:
3388 case RDP_SCANCODE_NONCONVERT_JP:
3389 case RDP_SCANCODE_RETURN_KP:
3390 case RDP_SCANCODE_RETURN:
3391 case RDP_SCANCODE_VOLUME_MUTE:
3392 case RDP_SCANCODE_VOLUME_DOWN:
3393 case RDP_SCANCODE_VOLUME_UP:
3399BOOL freerdp_client_send_key_as_unicode(rdpClientContext* cctx, UINT16 flags,
const char* str,
3400 UINT32 scancode, UINT32 modmask)
3402 const BOOL asKey = is_scancode_key(scancode);
3403 const BOOL modPressed =
3404 (modmask & (FREERDP_CLIENT_KBD_MOD_LCONTROL | FREERDP_CLIENT_KBD_MOD_RCONTROL |
3405 FREERDP_CLIENT_KBD_MOD_LMENU | FREERDP_CLIENT_KBD_MOD_RMENU |
3406 FREERDP_CLIENT_KBD_MOD_LWIN | FREERDP_CLIENT_KBD_MOD_RWIN)) != 0;
3407 WCHAR wbuffer[32] = WINPR_C_ARRAY_INIT;
3409 if (!asKey && !modPressed)
3410 rc = ConvertUtf8ToWChar(str, wbuffer, ARRAYSIZE(wbuffer));
3413 return freerdp_input_send_keyboard_event_ex(
3414 cctx->context.input, (flags & KBD_FLAGS_RELEASE) == 0, FALSE, scancode);
3416 for (SSIZE_T x = 0; x < rc; x++)
3418 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.