21#include <winpr/cast.h>
23#include <freerdp/config.h>
31#include <freerdp/client.h>
33#include <freerdp/freerdp.h>
34#include <freerdp/addin.h>
35#include <freerdp/assistance.h>
36#include <freerdp/client/file.h>
37#include <freerdp/utils/passphrase.h>
38#include <freerdp/client/cmdline.h>
39#include <freerdp/client/channels.h>
40#include <freerdp/event.h>
41#include <freerdp/utils/smartcardlogon.h>
43#if defined(CHANNEL_AINPUT_CLIENT)
44#include <freerdp/client/ainput.h>
45#include <freerdp/channels/ainput.h>
48#if defined(CHANNEL_VIDEO_CLIENT)
49#include <freerdp/client/video.h>
50#include <freerdp/channels/video.h>
53#if defined(CHANNEL_RDPGFX_CLIENT)
54#include <freerdp/client/rdpgfx.h>
55#include <freerdp/channels/rdpgfx.h>
56#include <freerdp/gdi/gfx.h>
59#if defined(CHANNEL_GEOMETRY_CLIENT)
60#include <freerdp/client/geometry.h>
61#include <freerdp/channels/geometry.h>
64#if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
65#include <freerdp/gdi/video.h>
68#include <freerdp/channels/rdpewa.h>
71#include <freerdp/utils/http.h>
72#include <freerdp/utils/aad.h>
76#include "sso_mib_tokens.h"
79#include <freerdp/log.h>
80#define TAG CLIENT_TAG("common")
82static void set_default_callbacks(freerdp* instance)
84 WINPR_ASSERT(instance);
85 instance->AuthenticateEx = client_cli_authenticate_ex;
86 instance->ChooseSmartcard = client_cli_choose_smartcard;
87 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
88 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
89 instance->PresentGatewayMessage = client_cli_present_gateway_message;
90 instance->LogonErrorInfo = client_cli_logon_error_info;
91 instance->GetAccessToken = client_cli_get_access_token;
92 instance->RetryDialog = client_common_retry_dialog;
95static void client_cli_user_notification(
void* context,
const UserNotificationEventArgs* e)
97 WINPR_UNUSED(context);
99 if (strcmp(e->e.Sender, RDPEWA_CHANNEL_NAME) != 0)
102 if (!e->message || e->message[0] ==
'\0')
104 (void)fprintf(stderr,
"[%s] Touch the security key\n", e->e.Sender);
105 (void)fflush(stderr);
108static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
110 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
112 WINPR_ASSERT(instance);
113 WINPR_ASSERT(context);
115 instance->LoadChannels = freerdp_client_load_channels;
116 set_default_callbacks(instance);
118 pEntryPoints = instance->pClientEntryPoints;
119 WINPR_ASSERT(pEntryPoints);
121 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
124static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
126 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
128 WINPR_ASSERT(instance);
129 WINPR_ASSERT(context);
131 pEntryPoints = instance->pClientEntryPoints;
132 WINPR_ASSERT(pEntryPoints);
133 IFCALL(pEntryPoints->ClientFree, instance, context);
138rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
140 freerdp* instance =
nullptr;
141 rdpContext* context =
nullptr;
146 if (!IFCALLRESULT(TRUE, pEntryPoints->GlobalInit))
149 instance = freerdp_new();
154 instance->ContextSize = pEntryPoints->ContextSize;
155 instance->ContextNew = freerdp_client_common_new;
156 instance->ContextFree = freerdp_client_common_free;
157 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
159 if (!instance->pClientEntryPoints)
162 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
164 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
167 context = instance->context;
168 context->instance = instance;
170#if defined(WITH_CLIENT_CHANNELS)
171 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
178 free(instance->pClientEntryPoints);
180 freerdp_free(instance);
184void freerdp_client_context_free(rdpContext* context)
186 freerdp* instance =
nullptr;
191 instance = context->instance;
195 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
196 freerdp_context_free(instance);
199 IFCALL(pEntryPoints->GlobalUninit);
201 free(instance->pClientEntryPoints);
202 freerdp_free(instance);
206int freerdp_client_start(rdpContext* context)
208 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
210 if (!context || !context->instance || !context->instance->pClientEntryPoints)
211 return ERROR_BAD_ARGUMENTS;
215 set_default_callbacks(context->instance);
219 PubSub_SubscribeUserNotification(context->pubSub, client_cli_user_notification);
226 rdpClientContext* client_context = (rdpClientContext*)context;
227 client_context->mibClientWrapper = sso_mib_new(context);
228 if (!client_context->mibClientWrapper)
229 return ERROR_INTERNAL_ERROR;
232 pEntryPoints = context->instance->pClientEntryPoints;
233 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
236int freerdp_client_stop(rdpContext* context)
238 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
240 if (!context || !context->instance || !context->instance->pClientEntryPoints)
241 return ERROR_BAD_ARGUMENTS;
243 pEntryPoints = context->instance->pClientEntryPoints;
244 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
247 PubSub_UnsubscribeUserNotification(context->pubSub, client_cli_user_notification);
250 rdpClientContext* client_context = (rdpClientContext*)context;
251 sso_mib_free(client_context->mibClientWrapper);
252 client_context->mibClientWrapper =
nullptr;
257freerdp* freerdp_client_get_instance(rdpContext* context)
259 if (!context || !context->instance)
262 return context->instance;
265HANDLE freerdp_client_get_thread(rdpContext* context)
270 return ((rdpClientContext*)context)->thread;
273static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
298 settings, FreeRDP_GatewayPassword,
336int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
340 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown,
341 nullptr, 0,
nullptr,
nullptr);
344int freerdp_client_settings_parse_command_line_ex(
346 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
356 status = freerdp_client_settings_parse_command_line_arguments_ex(
357 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
364 if (!freerdp_client_settings_post_process(settings))
367 const char* name = argv[0];
368 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
369 freerdp_get_build_config());
373int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
375 rdpFile* file =
nullptr;
377 file = freerdp_client_rdp_file_new();
382 if (!freerdp_client_parse_rdp_file(file, filename))
385 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
390 freerdp_client_rdp_file_free(file);
394int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
397 rdpFile* file =
nullptr;
399 file = freerdp_client_rdp_file_new();
404 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
405 freerdp_client_populate_settings_from_rdp_file(file, settings))
410 freerdp_client_rdp_file_free(file);
414int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
417 rdpFile* file =
nullptr;
419 file = freerdp_client_rdp_file_new();
424 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
427 if (!freerdp_client_write_rdp_file(file, filename, unicode))
432 freerdp_client_rdp_file_free(file);
436int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
440 char* filename =
nullptr;
441 char* password =
nullptr;
442 rdpAssistanceFile* file =
nullptr;
444 if (!settings || !argv || (argc < 2))
449 for (
int x = 2; x < argc; x++)
451 const char* key = strstr(argv[x],
"assistance:");
455 char* sep = strchr(key,
':');
463 file = freerdp_assistance_file_new();
468 status = freerdp_assistance_parse_file(file, filename, password);
473 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
478 freerdp_assistance_file_free(file);
482static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
485 WINPR_ASSERT(instance);
487 WINPR_ASSERT(result);
491 (void)fflush(stdout);
493 char* line =
nullptr;
494 if (suggestion && strlen(suggestion) > 0)
496 line = _strdup(suggestion);
497 size = strlen(suggestion);
500 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
503 char ebuffer[256] = WINPR_C_ARRAY_INIT;
504 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
505 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
515 line = StrSep(&line,
"\r");
516 line = StrSep(&line,
"\n");
537static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
538 char** password,
char** domain)
540 static const size_t password_size = 512;
541 const char* userAuth =
"Username: ";
542 const char* domainAuth =
"Domain: ";
543 const char* pwdAuth =
"Password: ";
544 BOOL pinOnly = FALSE;
545 BOOL queryAll = FALSE;
547 WINPR_ASSERT(instance);
548 WINPR_ASSERT(instance->context);
549 WINPR_ASSERT(instance->context->settings);
553 case AUTH_SMARTCARD_PIN:
554 pwdAuth =
"Smartcard-Pin: ";
558 pwdAuth =
"FIDO2 PIN: ";
571 userAuth =
"GatewayUsername: ";
572 domainAuth =
"GatewayDomain: ";
573 pwdAuth =
"GatewayPassword: ";
579 if (!username || !password || !domain)
584 const char* suggest = *username;
585 if (queryAll || !suggest)
587 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
595 const char* suggest = *domain;
596 if (queryAll || !suggest)
598 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
605 char* line = calloc(password_size,
sizeof(
char));
610 const BOOL fromStdin =
613 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
617 if (password_size > 0)
635BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
636 rdp_auth_reason reason)
638 WINPR_ASSERT(instance);
639 WINPR_ASSERT(username);
640 WINPR_ASSERT(password);
641 WINPR_ASSERT(domain);
651 case AUTH_SMARTCARD_PIN:
653 if ((*username) && (*password))
664 return client_cli_authenticate_raw(instance, reason, username, password, domain);
667BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
668 DWORD count, DWORD* choice, BOOL gateway)
670 unsigned long answer = 0;
673 printf(
"Multiple smartcards are available for use:\n");
674 for (DWORD i = 0; i < count; i++)
677 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
678 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
681 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
682 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
683 cert->issuer, cert->upn);
686 free(container_name);
691 char input[10] = WINPR_C_ARRAY_INIT;
693 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
694 gateway ?
"gateway authentication" :
"logon", count - 1);
695 (void)fflush(stdout);
696 if (!fgets(input, 10, stdin))
698 WLog_ERR(TAG,
"could not read from stdin");
702 answer = strtoul(input, &p, 10);
703 if ((*p ==
'\n' && p != input) && answer < count)
705 *choice = (UINT32)answer;
711#if defined(WITH_FREERDP_DEPRECATED)
712BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
716 WLog_INFO(TAG,
"Authentication via smartcard");
720 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
723BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
725 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
729static DWORD client_cli_accept_certificate(freerdp* instance)
733 WINPR_ASSERT(instance);
734 WINPR_ASSERT(instance->context);
736 const rdpSettings* settings = instance->context->settings;
737 WINPR_ASSERT(settings);
745 printf(
"Do you trust the above certificate? (Y/T/N) ");
746 (void)fflush(stdout);
747 answer = freerdp_interruptible_getc(instance->context, stdin);
749 if ((answer == EOF) || feof(stdin))
751 printf(
"\nError: Could not read answer from stdin.\n");
759 answer = freerdp_interruptible_getc(instance->context, stdin);
766 answer = freerdp_interruptible_getc(instance->context, stdin);
773 answer = freerdp_interruptible_getc(instance->context, stdin);
799#if defined(WITH_FREERDP_DEPRECATED)
800DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
801 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
803 WINPR_UNUSED(common_name);
804 WINPR_UNUSED(host_mismatch);
806 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
807 printf(
"Certificate details:\n");
808 printf(
"\tSubject: %s\n", subject);
809 printf(
"\tIssuer: %s\n", issuer);
810 printf(
"\tThumbprint: %s\n", fingerprint);
811 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
812 "the CA certificate in your certificate store, or the certificate has expired.\n"
813 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
814 return client_cli_accept_certificate(instance);
818static char* client_cli_pem_cert(
const char* pem)
820 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
824 char* fp = freerdp_certificate_get_fingerprint(cert);
825 char* start = freerdp_certificate_get_validity(cert, TRUE);
826 char* end = freerdp_certificate_get_validity(cert, FALSE);
827 freerdp_certificate_free(cert);
831 winpr_asprintf(&str, &slen,
834 "\tThumbprint: %s\n",
857DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
858 const char* common_name,
const char* subject,
859 const char* issuer,
const char* fingerprint, DWORD flags)
861 const char* type =
"RDP-Server";
863 WINPR_ASSERT(instance);
864 WINPR_ASSERT(instance->context);
865 WINPR_ASSERT(instance->context->settings);
867 if (flags & VERIFY_CERT_FLAG_GATEWAY)
868 type =
"RDP-Gateway";
870 if (flags & VERIFY_CERT_FLAG_REDIRECT)
871 type =
"RDP-Redirect";
873 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
874 printf(
"\tCommon Name: %s\n", common_name);
875 printf(
"\tSubject: %s\n", subject);
876 printf(
"\tIssuer: %s\n", issuer);
880 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
882 char* str = client_cli_pem_cert(fingerprint);
887 printf(
"\tThumbprint: %s\n", fingerprint);
889 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
890 "the CA certificate in your certificate store, or the certificate has expired.\n"
891 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
892 return client_cli_accept_certificate(instance);
910#if defined(WITH_FREERDP_DEPRECATED)
911DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
912 const char* subject,
const char* issuer,
913 const char* fingerprint,
const char* old_subject,
914 const char* old_issuer,
const char* old_fingerprint)
916 WINPR_UNUSED(common_name);
918 printf(
"WARNING: This callback is deprecated, migrate to "
919 "client_cli_verify_changed_certificate_ex\n");
920 printf(
"!!! Certificate has changed !!!\n");
922 printf(
"New Certificate details:\n");
923 printf(
"\tSubject: %s\n", subject);
924 printf(
"\tIssuer: %s\n", issuer);
925 printf(
"\tThumbprint: %s\n", fingerprint);
927 printf(
"Old Certificate details:\n");
928 printf(
"\tSubject: %s\n", old_subject);
929 printf(
"\tIssuer: %s\n", old_issuer);
930 printf(
"\tThumbprint: %s\n", old_fingerprint);
932 printf(
"The above X.509 certificate does not match the certificate used for previous "
934 "This may indicate that the certificate has been tampered with.\n"
935 "Please contact the administrator of the RDP server and clarify.\n");
936 return client_cli_accept_certificate(instance);
959DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
960 const char* common_name,
const char* subject,
961 const char* issuer,
const char* fingerprint,
962 const char* old_subject,
const char* old_issuer,
963 const char* old_fingerprint, DWORD flags)
965 const char* type =
"RDP-Server";
967 WINPR_ASSERT(instance);
968 WINPR_ASSERT(instance->context);
969 WINPR_ASSERT(instance->context->settings);
971 if (flags & VERIFY_CERT_FLAG_GATEWAY)
972 type =
"RDP-Gateway";
974 if (flags & VERIFY_CERT_FLAG_REDIRECT)
975 type =
"RDP-Redirect";
977 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
979 printf(
"New Certificate details:\n");
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(
"Old Certificate details:\n");
996 printf(
"\tSubject: %s\n", old_subject);
997 printf(
"\tIssuer: %s\n", old_issuer);
1001 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1003 char* str = client_cli_pem_cert(old_fingerprint);
1008 printf(
"\tThumbprint: %s\n", old_fingerprint);
1010 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
1012 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
1013 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
1014 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
1015 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
1018 printf(
"The above X.509 certificate does not match the certificate used for previous "
1020 "This may indicate that the certificate has been tampered with.\n"
1021 "Please contact the administrator of the RDP server and clarify.\n");
1022 return client_cli_accept_certificate(instance);
1025BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1026 BOOL isConsentMandatory,
size_t length,
1027 const WCHAR* message)
1029 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
1031 WINPR_ASSERT(instance);
1032 WINPR_ASSERT(instance->context);
1033 WINPR_ASSERT(instance->context->settings);
1035 if (!isDisplayMandatory && !isConsentMandatory)
1038 printf(
"%s:\n", msgType);
1040 printf(
"%.*S\n", (
int)length, message);
1043 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR),
nullptr);
1046 printf(
"Failed to convert message!\n");
1049 printf(
"%s\n", msg);
1054 while (isConsentMandatory)
1056 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1057 (void)fflush(stdout);
1058 const int answer = freerdp_interruptible_getc(instance->context, stdin);
1060 if ((answer == EOF) || feof(stdin))
1062 printf(
"\nError: Could not read answer from stdin.\n");
1066 const int confirm = freerdp_interruptible_getc(instance->context, stdin);
1089static const char* extract_authorization_code(
char* url)
1093 for (
char* p = strchr(url,
'?'); p++ !=
nullptr; p = strchr(p,
'&'))
1095 if (strncmp(p,
"code=", 5) != 0)
1098 char* end =
nullptr;
1101 end = strchr(p,
'&');
1111#if defined(WITH_AAD)
1112static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1113 const char* req_cnf,
char** token)
1115 WINPR_ASSERT(instance);
1116 WINPR_ASSERT(instance->context);
1119 char* url =
nullptr;
1120 char* token_request =
nullptr;
1122 WINPR_ASSERT(scope);
1123 WINPR_ASSERT(req_cnf);
1124 WINPR_ASSERT(token);
1129 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1130 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1132 printf(
"Browse to: %s\n", request);
1134 printf(
"Paste redirect URL here: \n");
1136 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1140 const char* code = extract_authorization_code(url);
1144 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1145 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1150 rc = client_common_get_access_token(instance, token_request, token);
1153 free(token_request);
1155 return rc && (*token !=
nullptr);
1158static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1160 WINPR_ASSERT(instance);
1161 WINPR_ASSERT(instance->context);
1164 char* url =
nullptr;
1165 char* token_request =
nullptr;
1167 WINPR_ASSERT(token);
1173 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1174 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1177 printf(
"Browse to: %s\n", request);
1179 printf(
"Paste redirect URL here: \n");
1181 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1185 const char* code = extract_authorization_code(url);
1188 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1189 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1195 rc = client_common_get_access_token(instance, token_request, token);
1198 free(token_request);
1200 return rc && (*token !=
nullptr);
1204BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1207 WINPR_ASSERT(instance);
1208 WINPR_ASSERT(token);
1210#if !defined(WITH_AAD)
1211 WLog_ERR(TAG,
"Build does not support AAD authentication");
1215 WINPR_ASSERT(instance->context);
1224 case ACCESS_TOKEN_TYPE_AAD:
1229 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1238 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1241 va_list ap = WINPR_C_ARRAY_INIT;
1242 va_start(ap, count);
1243 const char* scope = va_arg(ap,
const char*);
1244 const char* req_cnf = va_arg(ap,
const char*);
1245 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1250 case ACCESS_TOKEN_TYPE_AVD:
1253 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1256 rc = client_cli_get_avd_access_token(instance, token);
1259 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%u], aborting", tokenType);
1270BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1273 WINPR_ASSERT(request);
1274 WINPR_ASSERT(token);
1278 BYTE* response =
nullptr;
1279 size_t response_length = 0;
1281 wLog* log = WLog_Get(TAG);
1283 const char* token_ep =
1284 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1285 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1287 WLog_ERR(TAG,
"access token request failed");
1291 if (resp_code != HTTP_STATUS_OK)
1293 char buffer[64] = WINPR_C_ARRAY_INIT;
1295 WLog_Print(log, WLOG_ERROR,
1296 "Server unwilling to provide access token; returned status code %s",
1297 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1298 if (response_length > 0)
1299 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1303 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1315SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1318 WINPR_UNUSED(instance);
1319 WINPR_ASSERT(instance->context);
1320 WINPR_UNUSED(userarg);
1321 WINPR_ASSERT(instance);
1324 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1326 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1332 if (strcmp(what,
"arm-transport") == 0)
1333 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1336 const rdpSettings* settings = instance->context->settings;
1340 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1349 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1350 "tech support for help if this keeps happening.",
1355 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1356 what, current + 1, max, delay);
1357 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1360BOOL client_auto_reconnect(freerdp* instance)
1362 return client_auto_reconnect_ex(instance,
nullptr);
1365BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1369 UINT32 numRetries = 0;
1370 rdpSettings* settings =
nullptr;
1375 WINPR_ASSERT(instance->context);
1377 settings = instance->context->settings;
1378 WINPR_ASSERT(settings);
1380 const UINT32 maxRetries =
1384 error = freerdp_error_info(instance);
1387 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1389 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1390 freerdp_get_error_info_string(error));
1392 case ERRINFO_SUCCESS:
1394 WLog_INFO(TAG,
"Network disconnect!");
1397 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1404 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1408 const UINT err = freerdp_get_last_error(instance->context);
1411 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1412 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1413 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1414 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1415 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1416 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1417 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1418 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1419 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1420 freerdp_get_last_error_name(err));
1422 case FREERDP_ERROR_CONNECT_CANCELLED:
1423 WLog_WARN(TAG,
"Connection aborted by user");
1433 if ((maxRetries > 0) && (numRetries >= maxRetries))
1435 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1440 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1442 const SSIZE_T delay =
1443 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1448 if (freerdp_reconnect(instance))
1451 switch (freerdp_get_last_error(instance->context))
1453 case FREERDP_ERROR_CONNECT_CANCELLED:
1454 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1459 for (SSIZE_T x = 0; x < delay / 10; x++)
1461 if (!IFCALLRESULT(TRUE, window_events, instance))
1463 WLog_ERR(TAG,
"window_events failed!");
1471 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1475int freerdp_client_common_stop(rdpContext* context)
1477 rdpClientContext* cctx = (rdpClientContext*)context;
1480 freerdp_abort_connect_context(&cctx->context);
1484 (void)WaitForSingleObject(cctx->thread, INFINITE);
1485 (void)CloseHandle(cctx->thread);
1486 cctx->thread =
nullptr;
1492#if defined(CHANNEL_ENCOMSP_CLIENT)
1493BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1495 rdpClientContext* cctx =
nullptr;
1501 cctx = (rdpClientContext*)encomsp->custom;
1503 state = cctx->controlToggle;
1504 cctx->controlToggle = !cctx->controlToggle;
1505 return freerdp_client_encomsp_set_control(encomsp, state);
1508BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1515 pdu.ParticipantId = encomsp->participantId;
1516 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1519 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1521 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1522 return rc == CHANNEL_RC_OK;
1526client_encomsp_participant_created(EncomspClientContext* context,
1529 rdpClientContext* cctx =
nullptr;
1530 rdpSettings* settings =
nullptr;
1533 if (!context || !context->custom || !participantCreated)
1534 return ERROR_INVALID_PARAMETER;
1536 cctx = (rdpClientContext*)context->custom;
1539 settings = cctx->context.settings;
1540 WINPR_ASSERT(settings);
1542 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1543 context->participantId = participantCreated->ParticipantId;
1546 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1547 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1549 if (!freerdp_client_encomsp_set_control(context, TRUE))
1550 return ERROR_INTERNAL_ERROR;
1556 return ERROR_INTERNAL_ERROR;
1559 return CHANNEL_RC_OK;
1562static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1564 cctx->encomsp = encomsp;
1565 encomsp->custom = (
void*)cctx;
1566 encomsp->ParticipantCreated = client_encomsp_participant_created;
1569static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1573 encomsp->custom =
nullptr;
1574 encomsp->ParticipantCreated =
nullptr;
1578 cctx->encomsp =
nullptr;
1582void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1583 const ChannelConnectedEventArgs* e)
1585 rdpClientContext* cctx = (rdpClientContext*)context;
1593#if defined(CHANNEL_AINPUT_CLIENT)
1594 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1595 cctx->ainput = (AInputClientContext*)e->pInterface;
1597#if defined(CHANNEL_RDPEI_CLIENT)
1598 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1600 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1603#if defined(CHANNEL_RDPGFX_CLIENT)
1604 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1606 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1609#if defined(CHANNEL_GEOMETRY_CLIENT)
1610 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1612 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1615#if defined(CHANNEL_VIDEO_CLIENT)
1616 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1618 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1620 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1622 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1625#if defined(CHANNEL_ENCOMSP_CLIENT)
1626 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1628 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1633void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1634 const ChannelDisconnectedEventArgs* e)
1636 rdpClientContext* cctx = (rdpClientContext*)context;
1644#if defined(CHANNEL_AINPUT_CLIENT)
1645 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1646 cctx->ainput =
nullptr;
1648#if defined(CHANNEL_RDPEI_CLIENT)
1649 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1651 cctx->rdpei =
nullptr;
1654#if defined(CHANNEL_RDPGFX_CLIENT)
1655 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1657 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1660#if defined(CHANNEL_GEOMETRY_CLIENT)
1661 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1663 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1666#if defined(CHANNEL_VIDEO_CLIENT)
1667 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1669 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1671 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1673 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1676#if defined(CHANNEL_ENCOMSP_CLIENT)
1677 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1679 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1684BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1686 BOOL handled = FALSE;
1690 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1691 if (state != CONNECTION_STATE_ACTIVE)
1694#if defined(CHANNEL_AINPUT_CLIENT)
1701 INT32 value = mflags & 0xFF;
1703 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1704 value = -1 * (0x100 - value);
1710 if (mflags & PTR_FLAGS_WHEEL)
1712 flags |= AINPUT_FLAGS_WHEEL;
1716 if (mflags & PTR_FLAGS_HWHEEL)
1718 flags |= AINPUT_FLAGS_WHEEL;
1722 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1723 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1724 if (rc == CHANNEL_RC_OK)
1730 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1735#if defined(CHANNEL_AINPUT_CLIENT)
1736static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1741 WINPR_ASSERT(cctx->ainput);
1742 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1744 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1746 return rc == CHANNEL_RC_OK;
1750static bool button_pressed(
const rdpClientContext* cctx)
1753 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1755 const BOOL cur = cctx->pressed_buttons[x];
1762BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1765 BOOL handled = FALSE;
1768 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1769 if (state != CONNECTION_STATE_ACTIVE)
1772 if (mflags & PTR_FLAGS_BUTTON1)
1773 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1774 if (mflags & PTR_FLAGS_BUTTON2)
1775 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1776 if (mflags & PTR_FLAGS_BUTTON3)
1777 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1779 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1782 if (!button_pressed(cctx))
1786 const BOOL haveRelative =
1788 if (relative && haveRelative)
1790 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1791 WINPR_ASSERTING_INT_CAST(int16_t, x),
1792 WINPR_ASSERTING_INT_CAST(int16_t, y));
1795#if defined(CHANNEL_AINPUT_CLIENT)
1800 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1801 flags |= AINPUT_FLAGS_HAVE_REL;
1804 flags |= AINPUT_FLAGS_REL;
1806 if (mflags & PTR_FLAGS_DOWN)
1807 flags |= AINPUT_FLAGS_DOWN;
1808 if (mflags & PTR_FLAGS_BUTTON1)
1809 flags |= AINPUT_FLAGS_BUTTON1;
1810 if (mflags & PTR_FLAGS_BUTTON2)
1811 flags |= AINPUT_FLAGS_BUTTON2;
1812 if (mflags & PTR_FLAGS_BUTTON3)
1813 flags |= AINPUT_FLAGS_BUTTON3;
1814 if (mflags & PTR_FLAGS_MOVE)
1815 flags |= AINPUT_FLAGS_MOVE;
1816 handled = ainput_send_diff_event(cctx, flags, x, y);
1826 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1833 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1834 (UINT16)cctx->lastY);
1839BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1842 BOOL handled = FALSE;
1845 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1846 if (state != CONNECTION_STATE_ACTIVE)
1849 if (mflags & PTR_XFLAGS_BUTTON1)
1850 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1851 if (mflags & PTR_XFLAGS_BUTTON2)
1852 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1854 const BOOL haveRelative =
1856 if (relative && haveRelative)
1858 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1859 WINPR_ASSERTING_INT_CAST(int16_t, x),
1860 WINPR_ASSERTING_INT_CAST(int16_t, y));
1863#if defined(CHANNEL_AINPUT_CLIENT)
1869 flags |= AINPUT_FLAGS_REL;
1870 if (mflags & PTR_XFLAGS_DOWN)
1871 flags |= AINPUT_FLAGS_DOWN;
1872 if (mflags & PTR_XFLAGS_BUTTON1)
1873 flags |= AINPUT_XFLAGS_BUTTON1;
1874 if (mflags & PTR_XFLAGS_BUTTON2)
1875 flags |= AINPUT_XFLAGS_BUTTON2;
1877 handled = ainput_send_diff_event(cctx, flags, x, y);
1887 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1894 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1895 (UINT16)cctx->lastY);
1901static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
1904 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
1905 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
1906 WINPR_ASSERT(contact);
1907 WINPR_ASSERT(contact->x <= UINT16_MAX);
1908 WINPR_ASSERT(contact->y <= UINT16_MAX);
1910 switch (contact->count)
1913 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
1914 contact->x, contact->y);
1916 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
1917 contact->x, contact->y);
1919 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
1920 contact->x, contact->y);
1922 return freerdp_client_send_extended_button_event(
1923 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1925 return freerdp_client_send_extended_button_event(
1926 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1933static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1936 WINPR_ASSERT(contact);
1938#if defined(CHANNEL_RDPEI_CLIENT)
1939 RdpeiClientContext* rdpei = cctx->rdpei;
1942 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1946 if (rdpei->TouchRawEvent)
1948 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1949 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1950 ? CONTACT_DATA_PRESSURE_PRESENT
1954 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1955 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1956 RDPINPUT_CONTACT_FLAG_INCONTACT,
1957 contactFlags, contact->pressure);
1958 if (rc1 != CHANNEL_RC_OK)
1961 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
1962 &contactId, flags, contactFlags, contact->pressure);
1963 if (rc2 != CHANNEL_RC_OK)
1968 WINPR_ASSERT(rdpei->TouchEnd);
1969 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1970 if (rc != CHANNEL_RC_OK)
1975 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1976 "-DCHANNEL_RDPEI_CLIENT=ON");
1977 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1981static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1984 WINPR_ASSERT(contact);
1986#if defined(CHANNEL_RDPEI_CLIENT)
1987 RdpeiClientContext* rdpei = cctx->rdpei;
1991 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1995 if (rdpei->TouchRawEvent)
1997 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1998 RDPINPUT_CONTACT_FLAG_INCONTACT;
1999 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2000 ? CONTACT_DATA_PRESSURE_PRESENT
2002 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2003 flags, contactFlags, contact->pressure);
2004 if (rc != CHANNEL_RC_OK)
2009 WINPR_ASSERT(rdpei->TouchBegin);
2010 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
2011 if (rc != CHANNEL_RC_OK)
2017 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2018 "-DCHANNEL_RDPEI_CLIENT=ON");
2019 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2023static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
2026 const UINT16 flags = PTR_FLAGS_MOVE;
2028 WINPR_ASSERT(contact);
2029 WINPR_ASSERT(contact->x <= UINT16_MAX);
2030 WINPR_ASSERT(contact->y <= UINT16_MAX);
2031 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
2034static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2037 WINPR_ASSERT(contact);
2039#if defined(CHANNEL_RDPEI_CLIENT)
2040 RdpeiClientContext* rdpei = cctx->rdpei;
2043 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2047 if (rdpei->TouchRawEvent)
2049 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2050 RDPINPUT_CONTACT_FLAG_INCONTACT;
2051 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2052 ? CONTACT_DATA_PRESSURE_PRESENT
2054 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2055 flags, contactFlags, contact->pressure);
2056 if (rc != CHANNEL_RC_OK)
2061 WINPR_ASSERT(rdpei->TouchUpdate);
2062 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2063 if (rc != CHANNEL_RC_OK)
2069 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2070 "-DCHANNEL_RDPEI_CLIENT=ON");
2071 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2075static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2078 WINPR_ASSERT(contact);
2080#if defined(CHANNEL_RDPEI_CLIENT)
2081 RdpeiClientContext* rdpei = cctx->rdpei;
2084 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2088 if (rdpei->TouchRawEvent)
2090 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2091 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2092 ? CONTACT_DATA_PRESSURE_PRESENT
2094 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2095 flags, contactFlags, contact->pressure);
2096 if (rc != CHANNEL_RC_OK)
2101 WINPR_ASSERT(rdpei->TouchUpdate);
2102 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2103 if (rc != CHANNEL_RC_OK)
2109 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2110 "-DCHANNEL_RDPEI_CLIENT=ON");
2111 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2115static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2116 UINT32 pressure, INT32 x, INT32 y,
2120 WINPR_ASSERT(pcontact);
2122 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2126 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2127 if (newcontact || (contact->id == touchId))
2129 contact->id = touchId;
2130 contact->flags = flags;
2131 contact->pressure = pressure;
2135 *pcontact = *contact;
2137 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2150BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2151 UINT32 pressure, INT32 x, INT32 y)
2154 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2157 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2158 if (state != CONNECTION_STATE_ACTIVE)
2163 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2166 switch (flags & mask)
2168 case FREERDP_TOUCH_DOWN:
2169 return freerdp_handle_touch_down(cctx, &contact);
2170 case FREERDP_TOUCH_UP:
2171 return freerdp_handle_touch_up(cctx, &contact);
2172 case FREERDP_TOUCH_MOTION:
2173 return freerdp_handle_touch_motion(cctx, &contact);
2174 case FREERDP_TOUCH_CANCEL:
2175 return freerdp_handle_touch_cancel(cctx, &contact);
2177 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2182BOOL freerdp_client_load_channels(freerdp* instance)
2184 WINPR_ASSERT(instance);
2185 WINPR_ASSERT(instance->context);
2187 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2189 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2195int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2197 const char* str_data = freerdp_get_logon_error_info_data(data);
2198 const char* str_type = freerdp_get_logon_error_info_type(type);
2200 if (!instance || !instance->context)
2203 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2207static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2212 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2215 if (deviceid == pen->deviceid)
2225static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2228 static const INT32 null_deviceid = 0;
2231 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2232 if (freerdp_client_is_pen(cctx, deviceid))
2234 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2245 pen->deviceid = deviceid;
2246 pen->max_pressure = pressure;
2249 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2253 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2257BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2259 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2260 if (state != CONNECTION_STATE_ACTIVE)
2263#if defined(CHANNEL_RDPEI_CLIENT)
2264 if ((flags & FREERDP_PEN_REGISTER) != 0)
2266 va_list args = WINPR_C_ARRAY_INIT;
2268 va_start(args, deviceid);
2269 double pressure = va_arg(args,
double);
2271 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2277 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2281 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2283 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2285 RdpeiClientContext* rdpei = cctx->rdpei;
2286 WINPR_ASSERT(rdpei);
2288 UINT32 normalizedpressure = 1024;
2291 UINT16 rotation = 0;
2294 va_list args = WINPR_C_ARRAY_INIT;
2295 va_start(args, deviceid);
2297 x = va_arg(args, INT32);
2298 y = va_arg(args, INT32);
2299 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2301 const double pressure = va_arg(args,
double);
2302 const double np = (pressure * 1024.0) / pen->max_pressure;
2303 normalizedpressure = (UINT32)lround(np);
2304 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2305 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2307 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2309 const unsigned arg = va_arg(args,
unsigned);
2310 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2311 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2313 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2315 const int arg = va_arg(args,
int);
2316 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2317 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2319 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2321 const int arg = va_arg(args,
int);
2322 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2323 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2327 if ((flags & FREERDP_PEN_PRESS) != 0)
2331 flags = FREERDP_PEN_MOTION |
2332 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2333 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2334 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2336 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2338 if (!pen->pressed ||
2339 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2340 flags = FREERDP_PEN_MOTION |
2341 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2343 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2346 flags |= pen->flags;
2347 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2348 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2349 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2350 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2354 if ((flags & FREERDP_PEN_PRESS) != 0)
2356 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2357 pen->hovering = FALSE;
2358 pen->pressed = TRUE;
2360 WINPR_ASSERT(rdpei->PenBegin);
2361 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2362 normalizedpressure, rotation, tiltX, tiltY);
2363 return rc == CHANNEL_RC_OK;
2365 else if ((flags & FREERDP_PEN_MOTION) != 0)
2367 UINT rc = ERROR_INTERNAL_ERROR;
2370 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2373 WINPR_ASSERT(rdpei->PenUpdate);
2374 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2375 rotation, tiltX, tiltY);
2377 else if (pen->hovering)
2379 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2381 WINPR_ASSERT(rdpei->PenHoverUpdate);
2382 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2383 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2387 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2388 pen->hovering = TRUE;
2390 WINPR_ASSERT(rdpei->PenHoverBegin);
2391 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2392 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2394 return rc == CHANNEL_RC_OK;
2396 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2398 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2399 pen->pressed = FALSE;
2400 pen->hovering = TRUE;
2402 WINPR_ASSERT(rdpei->PenUpdate);
2403 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2404 normalizedpressure, rotation, tiltX, tiltY);
2405 if (rc != CHANNEL_RC_OK)
2407 WINPR_ASSERT(rdpei->PenEnd);
2408 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2409 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2410 return re == CHANNEL_RC_OK;
2413 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2415 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2416 "-DCHANNEL_RDPEI_CLIENT=ON");
2422BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2426 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2427 if (state != CONNECTION_STATE_ACTIVE)
2430#if defined(CHANNEL_RDPEI_CLIENT)
2431 RdpeiClientContext* rdpei = cctx->rdpei;
2436 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2441 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2442 pen->hovering = FALSE;
2444 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2445 if (rc != CHANNEL_RC_OK)
2451 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2452 "-DCHANNEL_RDPEI_CLIENT=ON");
2457BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2464 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2467 if (pen->deviceid == deviceid)
2474BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2478 const rdpSettings* settings = cctx->context.settings;
2481 BOOL ainput = FALSE;
2482#if defined(CHANNEL_AINPUT_CLIENT)
2483 ainput = cctx->ainput !=
nullptr;
2486 return useRelative && (haveRelative || ainput);
2489#if defined(WITH_AAD)
2490WINPR_ATTR_MALLOC(free, 1)
2491static
char* get_redirect_uri(const rdpSettings* settings)
2493 char* redirect_uri =
nullptr;
2497 const char* redirect_fmt =
2500 const char* tenantid =
"common";
2504 if (tenantid && redirect_fmt)
2509 size_t redirect_len = 0;
2510 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2516 const char* redirect_fmt =
2519 size_t redirect_len = 0;
2520 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2522 return redirect_uri;
2525static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2527 const rdpSettings* settings = cctx->context.settings;
2529 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2530 AAD_WELLKNOWN_authorization_endpoint);
2533 if (!client_id || !ep || !scope)
2536 char* redirect_uri = get_redirect_uri(settings);
2540 char* url =
nullptr;
2542 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2543 client_id, scope, redirect_uri);
2548static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2550 const rdpSettings* settings = cctx->context.settings;
2552 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2553 AAD_WELLKNOWN_authorization_endpoint);
2556 if (!client_id || !ep || !scope)
2559 char* redirect_uri = get_redirect_uri(settings);
2563 char* url =
nullptr;
2566 const char* code = va_arg(ap,
const char*);
2567 winpr_asprintf(&url, &urllen,
2568 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2569 code, client_id, scope, redirect_uri);
2574static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2576 const rdpSettings* settings = cctx->context.settings;
2577 char* url =
nullptr;
2579 char* redirect_uri = get_redirect_uri(settings);
2582 if (!client_id || !redirect_uri)
2586 const char* scope = va_arg(ap,
const char*);
2591 const char* ep = freerdp_utils_aad_get_wellknown_string(
2592 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2593 winpr_asprintf(&url, &urllen,
2594 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2595 client_id, scope, redirect_uri);
2604static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2606 const rdpSettings* settings = cctx->context.settings;
2608 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2609 AAD_WELLKNOWN_authorization_endpoint);
2610 const char* scope = va_arg(ap,
const char*);
2611 const char* code = va_arg(ap,
const char*);
2612 const char* req_cnf = va_arg(ap,
const char*);
2614 if (!client_id || !ep || !scope || !code || !req_cnf)
2617 char* redirect_uri = get_redirect_uri(settings);
2621 char* url =
nullptr;
2626 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2627 code, client_id, scope, redirect_uri, req_cnf);
2633char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2636 char* str =
nullptr;
2638 va_list ap = WINPR_C_ARRAY_INIT;
2642#if defined(WITH_AAD)
2643 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2644 str = aad_auth_request(cctx, ap);
2646 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2647 str = aad_token_request(cctx, ap);
2649 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2650 str = avd_auth_request(cctx, ap);
2652 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2653 str = avd_token_request(cctx, ap);
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.