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>
69#include <freerdp/utils/http.h>
70#include <freerdp/utils/aad.h>
74#include "sso_mib_tokens.h"
77#include <freerdp/log.h>
78#define TAG CLIENT_TAG("common")
80static void set_default_callbacks(freerdp* instance)
82 WINPR_ASSERT(instance);
83 instance->AuthenticateEx = client_cli_authenticate_ex;
84 instance->ChooseSmartcard = client_cli_choose_smartcard;
85 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
86 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
87 instance->PresentGatewayMessage = client_cli_present_gateway_message;
88 instance->LogonErrorInfo = client_cli_logon_error_info;
89 instance->GetAccessToken = client_cli_get_access_token;
90 instance->RetryDialog = client_common_retry_dialog;
93static void client_cli_user_notification(
void* context,
const UserNotificationEventArgs* e)
95 WINPR_UNUSED(context);
97 if (!e->message || e->message[0] ==
'\0')
99 (void)fprintf(stderr,
"[%s] Touch the security key\n", e->e.Sender);
100 (void)fflush(stderr);
103static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
105 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
107 WINPR_ASSERT(instance);
108 WINPR_ASSERT(context);
110 instance->LoadChannels = freerdp_client_load_channels;
111 set_default_callbacks(instance);
113 pEntryPoints = instance->pClientEntryPoints;
114 WINPR_ASSERT(pEntryPoints);
116 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
119static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
121 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
123 WINPR_ASSERT(instance);
124 WINPR_ASSERT(context);
126 pEntryPoints = instance->pClientEntryPoints;
127 WINPR_ASSERT(pEntryPoints);
128 IFCALL(pEntryPoints->ClientFree, instance, context);
133rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
135 freerdp* instance =
nullptr;
136 rdpContext* context =
nullptr;
141 if (!IFCALLRESULT(TRUE, pEntryPoints->GlobalInit))
144 instance = freerdp_new();
149 instance->ContextSize = pEntryPoints->ContextSize;
150 instance->ContextNew = freerdp_client_common_new;
151 instance->ContextFree = freerdp_client_common_free;
152 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
154 if (!instance->pClientEntryPoints)
157 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
159 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
162 context = instance->context;
163 context->instance = instance;
165#if defined(WITH_CLIENT_CHANNELS)
166 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
173 free(instance->pClientEntryPoints);
175 freerdp_free(instance);
179void freerdp_client_context_free(rdpContext* context)
181 freerdp* instance =
nullptr;
186 instance = context->instance;
190 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
191 freerdp_context_free(instance);
194 IFCALL(pEntryPoints->GlobalUninit);
196 free(instance->pClientEntryPoints);
197 freerdp_free(instance);
201int freerdp_client_start(rdpContext* context)
203 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
205 if (!context || !context->instance || !context->instance->pClientEntryPoints)
206 return ERROR_BAD_ARGUMENTS;
210 set_default_callbacks(context->instance);
214 PubSub_SubscribeUserNotification(context->pubSub, client_cli_user_notification);
221 rdpClientContext* client_context = (rdpClientContext*)context;
222 client_context->mibClientWrapper = sso_mib_new(context);
223 if (!client_context->mibClientWrapper)
224 return ERROR_INTERNAL_ERROR;
227 pEntryPoints = context->instance->pClientEntryPoints;
228 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
231int freerdp_client_stop(rdpContext* context)
233 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
235 if (!context || !context->instance || !context->instance->pClientEntryPoints)
236 return ERROR_BAD_ARGUMENTS;
238 pEntryPoints = context->instance->pClientEntryPoints;
239 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
242 PubSub_UnsubscribeUserNotification(context->pubSub, client_cli_user_notification);
245 rdpClientContext* client_context = (rdpClientContext*)context;
246 sso_mib_free(client_context->mibClientWrapper);
247 client_context->mibClientWrapper =
nullptr;
252freerdp* freerdp_client_get_instance(rdpContext* context)
254 if (!context || !context->instance)
257 return context->instance;
260HANDLE freerdp_client_get_thread(rdpContext* context)
265 return ((rdpClientContext*)context)->thread;
268static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
293 settings, FreeRDP_GatewayPassword,
331int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
335 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown,
336 nullptr, 0,
nullptr,
nullptr);
339int freerdp_client_settings_parse_command_line_ex(
341 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
351 status = freerdp_client_settings_parse_command_line_arguments_ex(
352 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
359 if (!freerdp_client_settings_post_process(settings))
362 const char* name = argv[0];
363 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
364 freerdp_get_build_config());
368int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
370 rdpFile* file =
nullptr;
372 file = freerdp_client_rdp_file_new();
377 if (!freerdp_client_parse_rdp_file(file, filename))
380 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
385 freerdp_client_rdp_file_free(file);
389int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
392 rdpFile* file =
nullptr;
394 file = freerdp_client_rdp_file_new();
399 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
400 freerdp_client_populate_settings_from_rdp_file(file, settings))
405 freerdp_client_rdp_file_free(file);
409int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
412 rdpFile* file =
nullptr;
414 file = freerdp_client_rdp_file_new();
419 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
422 if (!freerdp_client_write_rdp_file(file, filename, unicode))
427 freerdp_client_rdp_file_free(file);
431int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
435 char* filename =
nullptr;
436 char* password =
nullptr;
437 rdpAssistanceFile* file =
nullptr;
439 if (!settings || !argv || (argc < 2))
444 for (
int x = 2; x < argc; x++)
446 const char* key = strstr(argv[x],
"assistance:");
449 password = strchr(key,
':') + 1;
452 file = freerdp_assistance_file_new();
457 status = freerdp_assistance_parse_file(file, filename, password);
462 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
467 freerdp_assistance_file_free(file);
471static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
474 WINPR_ASSERT(instance);
476 WINPR_ASSERT(result);
480 (void)fflush(stdout);
482 char* line =
nullptr;
483 if (suggestion && strlen(suggestion) > 0)
485 line = _strdup(suggestion);
486 size = strlen(suggestion);
489 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
492 char ebuffer[256] = WINPR_C_ARRAY_INIT;
493 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
494 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
504 line = StrSep(&line,
"\r");
505 line = StrSep(&line,
"\n");
526static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
527 char** password,
char** domain)
529 static const size_t password_size = 512;
530 const char* userAuth =
"Username: ";
531 const char* domainAuth =
"Domain: ";
532 const char* pwdAuth =
"Password: ";
533 BOOL pinOnly = FALSE;
534 BOOL queryAll = FALSE;
536 WINPR_ASSERT(instance);
537 WINPR_ASSERT(instance->context);
538 WINPR_ASSERT(instance->context->settings);
542 case AUTH_SMARTCARD_PIN:
543 pwdAuth =
"Smartcard-Pin: ";
547 pwdAuth =
"FIDO2 PIN: ";
560 userAuth =
"GatewayUsername: ";
561 domainAuth =
"GatewayDomain: ";
562 pwdAuth =
"GatewayPassword: ";
568 if (!username || !password || !domain)
573 const char* suggest = *username;
574 if (queryAll || !suggest)
576 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
584 const char* suggest = *domain;
585 if (queryAll || !suggest)
587 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
594 char* line = calloc(password_size,
sizeof(
char));
599 const BOOL fromStdin =
602 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
606 if (password_size > 0)
624BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
625 rdp_auth_reason reason)
627 WINPR_ASSERT(instance);
628 WINPR_ASSERT(username);
629 WINPR_ASSERT(password);
630 WINPR_ASSERT(domain);
640 case AUTH_SMARTCARD_PIN:
642 if ((*username) && (*password))
653 return client_cli_authenticate_raw(instance, reason, username, password, domain);
656BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
657 DWORD count, DWORD* choice, BOOL gateway)
659 unsigned long answer = 0;
662 printf(
"Multiple smartcards are available for use:\n");
663 for (DWORD i = 0; i < count; i++)
666 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
667 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
670 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
671 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
672 cert->issuer, cert->upn);
675 free(container_name);
680 char input[10] = WINPR_C_ARRAY_INIT;
682 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
683 gateway ?
"gateway authentication" :
"logon", count - 1);
684 (void)fflush(stdout);
685 if (!fgets(input, 10, stdin))
687 WLog_ERR(TAG,
"could not read from stdin");
691 answer = strtoul(input, &p, 10);
692 if ((*p ==
'\n' && p != input) && answer < count)
694 *choice = (UINT32)answer;
700#if defined(WITH_FREERDP_DEPRECATED)
701BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
705 WLog_INFO(TAG,
"Authentication via smartcard");
709 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
712BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
714 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
718static DWORD client_cli_accept_certificate(freerdp* instance)
722 WINPR_ASSERT(instance);
723 WINPR_ASSERT(instance->context);
725 const rdpSettings* settings = instance->context->settings;
726 WINPR_ASSERT(settings);
734 printf(
"Do you trust the above certificate? (Y/T/N) ");
735 (void)fflush(stdout);
736 answer = freerdp_interruptible_getc(instance->context, stdin);
738 if ((answer == EOF) || feof(stdin))
740 printf(
"\nError: Could not read answer from stdin.\n");
748 answer = freerdp_interruptible_getc(instance->context, stdin);
755 answer = freerdp_interruptible_getc(instance->context, stdin);
762 answer = freerdp_interruptible_getc(instance->context, stdin);
788#if defined(WITH_FREERDP_DEPRECATED)
789DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
790 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
792 WINPR_UNUSED(common_name);
793 WINPR_UNUSED(host_mismatch);
795 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
796 printf(
"Certificate details:\n");
797 printf(
"\tSubject: %s\n", subject);
798 printf(
"\tIssuer: %s\n", issuer);
799 printf(
"\tThumbprint: %s\n", fingerprint);
800 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
801 "the CA certificate in your certificate store, or the certificate has expired.\n"
802 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
803 return client_cli_accept_certificate(instance);
807static char* client_cli_pem_cert(
const char* pem)
809 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
813 char* fp = freerdp_certificate_get_fingerprint(cert);
814 char* start = freerdp_certificate_get_validity(cert, TRUE);
815 char* end = freerdp_certificate_get_validity(cert, FALSE);
816 freerdp_certificate_free(cert);
820 winpr_asprintf(&str, &slen,
823 "\tThumbprint: %s\n",
846DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
847 const char* common_name,
const char* subject,
848 const char* issuer,
const char* fingerprint, DWORD flags)
850 const char* type =
"RDP-Server";
852 WINPR_ASSERT(instance);
853 WINPR_ASSERT(instance->context);
854 WINPR_ASSERT(instance->context->settings);
856 if (flags & VERIFY_CERT_FLAG_GATEWAY)
857 type =
"RDP-Gateway";
859 if (flags & VERIFY_CERT_FLAG_REDIRECT)
860 type =
"RDP-Redirect";
862 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
863 printf(
"\tCommon Name: %s\n", common_name);
864 printf(
"\tSubject: %s\n", subject);
865 printf(
"\tIssuer: %s\n", issuer);
869 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
871 char* str = client_cli_pem_cert(fingerprint);
876 printf(
"\tThumbprint: %s\n", fingerprint);
878 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
879 "the CA certificate in your certificate store, or the certificate has expired.\n"
880 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
881 return client_cli_accept_certificate(instance);
899#if defined(WITH_FREERDP_DEPRECATED)
900DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
901 const char* subject,
const char* issuer,
902 const char* fingerprint,
const char* old_subject,
903 const char* old_issuer,
const char* old_fingerprint)
905 WINPR_UNUSED(common_name);
907 printf(
"WARNING: This callback is deprecated, migrate to "
908 "client_cli_verify_changed_certificate_ex\n");
909 printf(
"!!! Certificate has changed !!!\n");
911 printf(
"New Certificate details:\n");
912 printf(
"\tSubject: %s\n", subject);
913 printf(
"\tIssuer: %s\n", issuer);
914 printf(
"\tThumbprint: %s\n", fingerprint);
916 printf(
"Old Certificate details:\n");
917 printf(
"\tSubject: %s\n", old_subject);
918 printf(
"\tIssuer: %s\n", old_issuer);
919 printf(
"\tThumbprint: %s\n", old_fingerprint);
921 printf(
"The above X.509 certificate does not match the certificate used for previous "
923 "This may indicate that the certificate has been tampered with.\n"
924 "Please contact the administrator of the RDP server and clarify.\n");
925 return client_cli_accept_certificate(instance);
948DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
949 const char* common_name,
const char* subject,
950 const char* issuer,
const char* fingerprint,
951 const char* old_subject,
const char* old_issuer,
952 const char* old_fingerprint, DWORD flags)
954 const char* type =
"RDP-Server";
956 WINPR_ASSERT(instance);
957 WINPR_ASSERT(instance->context);
958 WINPR_ASSERT(instance->context->settings);
960 if (flags & VERIFY_CERT_FLAG_GATEWAY)
961 type =
"RDP-Gateway";
963 if (flags & VERIFY_CERT_FLAG_REDIRECT)
964 type =
"RDP-Redirect";
966 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
968 printf(
"New Certificate details:\n");
969 printf(
"\tCommon Name: %s\n", common_name);
970 printf(
"\tSubject: %s\n", subject);
971 printf(
"\tIssuer: %s\n", issuer);
975 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
977 char* str = client_cli_pem_cert(fingerprint);
982 printf(
"\tThumbprint: %s\n", fingerprint);
984 printf(
"Old Certificate details:\n");
985 printf(
"\tSubject: %s\n", old_subject);
986 printf(
"\tIssuer: %s\n", old_issuer);
990 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
992 char* str = client_cli_pem_cert(old_fingerprint);
997 printf(
"\tThumbprint: %s\n", old_fingerprint);
999 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
1001 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
1002 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
1003 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
1004 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
1007 printf(
"The above X.509 certificate does not match the certificate used for previous "
1009 "This may indicate that the certificate has been tampered with.\n"
1010 "Please contact the administrator of the RDP server and clarify.\n");
1011 return client_cli_accept_certificate(instance);
1014BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1015 BOOL isConsentMandatory,
size_t length,
1016 const WCHAR* message)
1018 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
1020 WINPR_ASSERT(instance);
1021 WINPR_ASSERT(instance->context);
1022 WINPR_ASSERT(instance->context->settings);
1024 if (!isDisplayMandatory && !isConsentMandatory)
1027 printf(
"%s:\n", msgType);
1029 printf(
"%.*S\n", (
int)length, message);
1032 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR),
nullptr);
1035 printf(
"Failed to convert message!\n");
1038 printf(
"%s\n", msg);
1043 while (isConsentMandatory)
1045 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1046 (void)fflush(stdout);
1047 const int answer = freerdp_interruptible_getc(instance->context, stdin);
1049 if ((answer == EOF) || feof(stdin))
1051 printf(
"\nError: Could not read answer from stdin.\n");
1055 const int confirm = freerdp_interruptible_getc(instance->context, stdin);
1078static const char* extract_authorization_code(
char* url)
1082 for (
char* p = strchr(url,
'?'); p++ !=
nullptr; p = strchr(p,
'&'))
1084 if (strncmp(p,
"code=", 5) != 0)
1087 char* end =
nullptr;
1090 end = strchr(p,
'&');
1100#if defined(WITH_AAD)
1101static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1102 const char* req_cnf,
char** token)
1104 WINPR_ASSERT(instance);
1105 WINPR_ASSERT(instance->context);
1108 char* url =
nullptr;
1109 char* token_request =
nullptr;
1111 WINPR_ASSERT(scope);
1112 WINPR_ASSERT(req_cnf);
1113 WINPR_ASSERT(token);
1118 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1119 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1121 printf(
"Browse to: %s\n", request);
1123 printf(
"Paste redirect URL here: \n");
1125 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1129 const char* code = extract_authorization_code(url);
1133 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1134 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1139 rc = client_common_get_access_token(instance, token_request, token);
1142 free(token_request);
1144 return rc && (*token !=
nullptr);
1147static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1149 WINPR_ASSERT(instance);
1150 WINPR_ASSERT(instance->context);
1153 char* url =
nullptr;
1154 char* token_request =
nullptr;
1156 WINPR_ASSERT(token);
1162 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1163 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1166 printf(
"Browse to: %s\n", request);
1168 printf(
"Paste redirect URL here: \n");
1170 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1174 const char* code = extract_authorization_code(url);
1177 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1178 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1184 rc = client_common_get_access_token(instance, token_request, token);
1187 free(token_request);
1189 return rc && (*token !=
nullptr);
1193BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1196 WINPR_ASSERT(instance);
1197 WINPR_ASSERT(token);
1199#if !defined(WITH_AAD)
1200 WLog_ERR(TAG,
"Build does not support AAD authentication");
1204 WINPR_ASSERT(instance->context);
1213 case ACCESS_TOKEN_TYPE_AAD:
1218 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1225 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1228 va_list ap = WINPR_C_ARRAY_INIT;
1229 va_start(ap, count);
1230 const char* scope = va_arg(ap,
const char*);
1231 const char* req_cnf = va_arg(ap,
const char*);
1232 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1236 case ACCESS_TOKEN_TYPE_AVD:
1239 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1242 rc = client_cli_get_avd_access_token(instance, token);
1245 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%u], aborting", tokenType);
1256BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1259 WINPR_ASSERT(request);
1260 WINPR_ASSERT(token);
1264 BYTE* response =
nullptr;
1265 size_t response_length = 0;
1267 wLog* log = WLog_Get(TAG);
1269 const char* token_ep =
1270 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1271 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1273 WLog_ERR(TAG,
"access token request failed");
1277 if (resp_code != HTTP_STATUS_OK)
1279 char buffer[64] = WINPR_C_ARRAY_INIT;
1281 WLog_Print(log, WLOG_ERROR,
1282 "Server unwilling to provide access token; returned status code %s",
1283 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1284 if (response_length > 0)
1285 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1289 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1301SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1304 WINPR_UNUSED(instance);
1305 WINPR_ASSERT(instance->context);
1306 WINPR_UNUSED(userarg);
1307 WINPR_ASSERT(instance);
1310 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1312 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1318 if (strcmp(what,
"arm-transport") == 0)
1319 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1322 const rdpSettings* settings = instance->context->settings;
1326 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1335 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1336 "tech support for help if this keeps happening.",
1341 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1342 what, current + 1, max, delay);
1343 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1346BOOL client_auto_reconnect(freerdp* instance)
1348 return client_auto_reconnect_ex(instance,
nullptr);
1351BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1355 UINT32 numRetries = 0;
1356 rdpSettings* settings =
nullptr;
1361 WINPR_ASSERT(instance->context);
1363 settings = instance->context->settings;
1364 WINPR_ASSERT(settings);
1366 const UINT32 maxRetries =
1370 error = freerdp_error_info(instance);
1373 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1375 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1376 freerdp_get_error_info_string(error));
1378 case ERRINFO_SUCCESS:
1380 WLog_INFO(TAG,
"Network disconnect!");
1383 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1390 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1394 const UINT err = freerdp_get_last_error(instance->context);
1397 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1398 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1399 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1400 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1401 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1402 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1403 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1404 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1405 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1406 freerdp_get_last_error_name(err));
1408 case FREERDP_ERROR_CONNECT_CANCELLED:
1409 WLog_WARN(TAG,
"Connection aborted by user");
1419 if ((maxRetries > 0) && (numRetries >= maxRetries))
1421 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1426 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1428 const SSIZE_T delay =
1429 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1434 if (freerdp_reconnect(instance))
1437 switch (freerdp_get_last_error(instance->context))
1439 case FREERDP_ERROR_CONNECT_CANCELLED:
1440 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1445 for (SSIZE_T x = 0; x < delay / 10; x++)
1447 if (!IFCALLRESULT(TRUE, window_events, instance))
1449 WLog_ERR(TAG,
"window_events failed!");
1457 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1461int freerdp_client_common_stop(rdpContext* context)
1463 rdpClientContext* cctx = (rdpClientContext*)context;
1466 freerdp_abort_connect_context(&cctx->context);
1470 (void)WaitForSingleObject(cctx->thread, INFINITE);
1471 (void)CloseHandle(cctx->thread);
1472 cctx->thread =
nullptr;
1478#if defined(CHANNEL_ENCOMSP_CLIENT)
1479BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1481 rdpClientContext* cctx =
nullptr;
1487 cctx = (rdpClientContext*)encomsp->custom;
1489 state = cctx->controlToggle;
1490 cctx->controlToggle = !cctx->controlToggle;
1491 return freerdp_client_encomsp_set_control(encomsp, state);
1494BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1501 pdu.ParticipantId = encomsp->participantId;
1502 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1505 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1507 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1508 return rc == CHANNEL_RC_OK;
1512client_encomsp_participant_created(EncomspClientContext* context,
1515 rdpClientContext* cctx =
nullptr;
1516 rdpSettings* settings =
nullptr;
1519 if (!context || !context->custom || !participantCreated)
1520 return ERROR_INVALID_PARAMETER;
1522 cctx = (rdpClientContext*)context->custom;
1525 settings = cctx->context.settings;
1526 WINPR_ASSERT(settings);
1528 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1529 context->participantId = participantCreated->ParticipantId;
1532 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1533 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1535 if (!freerdp_client_encomsp_set_control(context, TRUE))
1536 return ERROR_INTERNAL_ERROR;
1542 return ERROR_INTERNAL_ERROR;
1545 return CHANNEL_RC_OK;
1548static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1550 cctx->encomsp = encomsp;
1551 encomsp->custom = (
void*)cctx;
1552 encomsp->ParticipantCreated = client_encomsp_participant_created;
1555static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1559 encomsp->custom =
nullptr;
1560 encomsp->ParticipantCreated =
nullptr;
1564 cctx->encomsp =
nullptr;
1568void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1569 const ChannelConnectedEventArgs* e)
1571 rdpClientContext* cctx = (rdpClientContext*)context;
1579#if defined(CHANNEL_AINPUT_CLIENT)
1580 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1581 cctx->ainput = (AInputClientContext*)e->pInterface;
1583#if defined(CHANNEL_RDPEI_CLIENT)
1584 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1586 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1589#if defined(CHANNEL_RDPGFX_CLIENT)
1590 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1592 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1595#if defined(CHANNEL_GEOMETRY_CLIENT)
1596 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1598 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1601#if defined(CHANNEL_VIDEO_CLIENT)
1602 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1604 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1606 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1608 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1611#if defined(CHANNEL_ENCOMSP_CLIENT)
1612 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1614 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1619void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1620 const ChannelDisconnectedEventArgs* e)
1622 rdpClientContext* cctx = (rdpClientContext*)context;
1630#if defined(CHANNEL_AINPUT_CLIENT)
1631 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1632 cctx->ainput =
nullptr;
1634#if defined(CHANNEL_RDPEI_CLIENT)
1635 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1637 cctx->rdpei =
nullptr;
1640#if defined(CHANNEL_RDPGFX_CLIENT)
1641 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1643 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1646#if defined(CHANNEL_GEOMETRY_CLIENT)
1647 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1649 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1652#if defined(CHANNEL_VIDEO_CLIENT)
1653 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1655 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1657 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1659 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1662#if defined(CHANNEL_ENCOMSP_CLIENT)
1663 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1665 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1670BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1672 BOOL handled = FALSE;
1676 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1677 if (state != CONNECTION_STATE_ACTIVE)
1680#if defined(CHANNEL_AINPUT_CLIENT)
1687 INT32 value = mflags & 0xFF;
1689 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1690 value = -1 * (0x100 - value);
1696 if (mflags & PTR_FLAGS_WHEEL)
1698 flags |= AINPUT_FLAGS_WHEEL;
1702 if (mflags & PTR_FLAGS_HWHEEL)
1704 flags |= AINPUT_FLAGS_WHEEL;
1708 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1709 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1710 if (rc == CHANNEL_RC_OK)
1716 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1721#if defined(CHANNEL_AINPUT_CLIENT)
1722static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1727 WINPR_ASSERT(cctx->ainput);
1728 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1730 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1732 return rc == CHANNEL_RC_OK;
1736static bool button_pressed(
const rdpClientContext* cctx)
1739 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1741 const BOOL cur = cctx->pressed_buttons[x];
1748BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1751 BOOL handled = FALSE;
1754 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1755 if (state != CONNECTION_STATE_ACTIVE)
1758 if (mflags & PTR_FLAGS_BUTTON1)
1759 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1760 if (mflags & PTR_FLAGS_BUTTON2)
1761 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1762 if (mflags & PTR_FLAGS_BUTTON3)
1763 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1765 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1768 if (!button_pressed(cctx))
1772 const BOOL haveRelative =
1774 if (relative && haveRelative)
1776 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1777 WINPR_ASSERTING_INT_CAST(int16_t, x),
1778 WINPR_ASSERTING_INT_CAST(int16_t, y));
1781#if defined(CHANNEL_AINPUT_CLIENT)
1786 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1787 flags |= AINPUT_FLAGS_HAVE_REL;
1790 flags |= AINPUT_FLAGS_REL;
1792 if (mflags & PTR_FLAGS_DOWN)
1793 flags |= AINPUT_FLAGS_DOWN;
1794 if (mflags & PTR_FLAGS_BUTTON1)
1795 flags |= AINPUT_FLAGS_BUTTON1;
1796 if (mflags & PTR_FLAGS_BUTTON2)
1797 flags |= AINPUT_FLAGS_BUTTON2;
1798 if (mflags & PTR_FLAGS_BUTTON3)
1799 flags |= AINPUT_FLAGS_BUTTON3;
1800 if (mflags & PTR_FLAGS_MOVE)
1801 flags |= AINPUT_FLAGS_MOVE;
1802 handled = ainput_send_diff_event(cctx, flags, x, y);
1812 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1819 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1820 (UINT16)cctx->lastY);
1825BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1828 BOOL handled = FALSE;
1831 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1832 if (state != CONNECTION_STATE_ACTIVE)
1835 if (mflags & PTR_XFLAGS_BUTTON1)
1836 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1837 if (mflags & PTR_XFLAGS_BUTTON2)
1838 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1840 const BOOL haveRelative =
1842 if (relative && haveRelative)
1844 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1845 WINPR_ASSERTING_INT_CAST(int16_t, x),
1846 WINPR_ASSERTING_INT_CAST(int16_t, y));
1849#if defined(CHANNEL_AINPUT_CLIENT)
1855 flags |= AINPUT_FLAGS_REL;
1856 if (mflags & PTR_XFLAGS_DOWN)
1857 flags |= AINPUT_FLAGS_DOWN;
1858 if (mflags & PTR_XFLAGS_BUTTON1)
1859 flags |= AINPUT_XFLAGS_BUTTON1;
1860 if (mflags & PTR_XFLAGS_BUTTON2)
1861 flags |= AINPUT_XFLAGS_BUTTON2;
1863 handled = ainput_send_diff_event(cctx, flags, x, y);
1873 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1880 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1881 (UINT16)cctx->lastY);
1887static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
1890 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
1891 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
1892 WINPR_ASSERT(contact);
1893 WINPR_ASSERT(contact->x <= UINT16_MAX);
1894 WINPR_ASSERT(contact->y <= UINT16_MAX);
1896 switch (contact->count)
1899 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
1900 contact->x, contact->y);
1902 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
1903 contact->x, contact->y);
1905 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
1906 contact->x, contact->y);
1908 return freerdp_client_send_extended_button_event(
1909 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1911 return freerdp_client_send_extended_button_event(
1912 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1919static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1922 WINPR_ASSERT(contact);
1924#if defined(CHANNEL_RDPEI_CLIENT)
1925 RdpeiClientContext* rdpei = cctx->rdpei;
1928 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1932 if (rdpei->TouchRawEvent)
1934 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1935 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1936 ? CONTACT_DATA_PRESSURE_PRESENT
1940 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1941 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1942 RDPINPUT_CONTACT_FLAG_INCONTACT,
1943 contactFlags, contact->pressure);
1944 if (rc1 != CHANNEL_RC_OK)
1947 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
1948 &contactId, flags, contactFlags, contact->pressure);
1949 if (rc2 != CHANNEL_RC_OK)
1954 WINPR_ASSERT(rdpei->TouchEnd);
1955 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1956 if (rc != CHANNEL_RC_OK)
1961 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1962 "-DCHANNEL_RDPEI_CLIENT=ON");
1963 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1967static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1970 WINPR_ASSERT(contact);
1972#if defined(CHANNEL_RDPEI_CLIENT)
1973 RdpeiClientContext* rdpei = cctx->rdpei;
1977 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1981 if (rdpei->TouchRawEvent)
1983 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1984 RDPINPUT_CONTACT_FLAG_INCONTACT;
1985 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1986 ? CONTACT_DATA_PRESSURE_PRESENT
1988 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1989 flags, contactFlags, contact->pressure);
1990 if (rc != CHANNEL_RC_OK)
1995 WINPR_ASSERT(rdpei->TouchBegin);
1996 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1997 if (rc != CHANNEL_RC_OK)
2003 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2004 "-DCHANNEL_RDPEI_CLIENT=ON");
2005 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2009static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
2012 const UINT16 flags = PTR_FLAGS_MOVE;
2014 WINPR_ASSERT(contact);
2015 WINPR_ASSERT(contact->x <= UINT16_MAX);
2016 WINPR_ASSERT(contact->y <= UINT16_MAX);
2017 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
2020static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2023 WINPR_ASSERT(contact);
2025#if defined(CHANNEL_RDPEI_CLIENT)
2026 RdpeiClientContext* rdpei = cctx->rdpei;
2029 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2033 if (rdpei->TouchRawEvent)
2035 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2036 RDPINPUT_CONTACT_FLAG_INCONTACT;
2037 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2038 ? CONTACT_DATA_PRESSURE_PRESENT
2040 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2041 flags, contactFlags, contact->pressure);
2042 if (rc != CHANNEL_RC_OK)
2047 WINPR_ASSERT(rdpei->TouchUpdate);
2048 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2049 if (rc != CHANNEL_RC_OK)
2055 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2056 "-DCHANNEL_RDPEI_CLIENT=ON");
2057 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2061static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2064 WINPR_ASSERT(contact);
2066#if defined(CHANNEL_RDPEI_CLIENT)
2067 RdpeiClientContext* rdpei = cctx->rdpei;
2070 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2074 if (rdpei->TouchRawEvent)
2076 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2077 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2078 ? CONTACT_DATA_PRESSURE_PRESENT
2080 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2081 flags, contactFlags, contact->pressure);
2082 if (rc != CHANNEL_RC_OK)
2087 WINPR_ASSERT(rdpei->TouchUpdate);
2088 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2089 if (rc != CHANNEL_RC_OK)
2095 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2096 "-DCHANNEL_RDPEI_CLIENT=ON");
2097 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2101static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2102 UINT32 pressure, INT32 x, INT32 y,
2106 WINPR_ASSERT(pcontact);
2108 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2112 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2113 if (newcontact || (contact->id == touchId))
2115 contact->id = touchId;
2116 contact->flags = flags;
2117 contact->pressure = pressure;
2121 *pcontact = *contact;
2123 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2136BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2137 UINT32 pressure, INT32 x, INT32 y)
2140 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2143 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2144 if (state != CONNECTION_STATE_ACTIVE)
2149 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2152 switch (flags & mask)
2154 case FREERDP_TOUCH_DOWN:
2155 return freerdp_handle_touch_down(cctx, &contact);
2156 case FREERDP_TOUCH_UP:
2157 return freerdp_handle_touch_up(cctx, &contact);
2158 case FREERDP_TOUCH_MOTION:
2159 return freerdp_handle_touch_motion(cctx, &contact);
2160 case FREERDP_TOUCH_CANCEL:
2161 return freerdp_handle_touch_cancel(cctx, &contact);
2163 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2168BOOL freerdp_client_load_channels(freerdp* instance)
2170 WINPR_ASSERT(instance);
2171 WINPR_ASSERT(instance->context);
2173 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2175 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2181int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2183 const char* str_data = freerdp_get_logon_error_info_data(data);
2184 const char* str_type = freerdp_get_logon_error_info_type(type);
2186 if (!instance || !instance->context)
2189 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2193static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2198 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2201 if (deviceid == pen->deviceid)
2211static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2214 static const INT32 null_deviceid = 0;
2217 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2218 if (freerdp_client_is_pen(cctx, deviceid))
2220 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2231 pen->deviceid = deviceid;
2232 pen->max_pressure = pressure;
2235 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2239 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2243BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2245 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2246 if (state != CONNECTION_STATE_ACTIVE)
2249#if defined(CHANNEL_RDPEI_CLIENT)
2250 if ((flags & FREERDP_PEN_REGISTER) != 0)
2252 va_list args = WINPR_C_ARRAY_INIT;
2254 va_start(args, deviceid);
2255 double pressure = va_arg(args,
double);
2257 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2263 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2267 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2269 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2271 RdpeiClientContext* rdpei = cctx->rdpei;
2272 WINPR_ASSERT(rdpei);
2274 UINT32 normalizedpressure = 1024;
2277 UINT16 rotation = 0;
2280 va_list args = WINPR_C_ARRAY_INIT;
2281 va_start(args, deviceid);
2283 x = va_arg(args, INT32);
2284 y = va_arg(args, INT32);
2285 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2287 const double pressure = va_arg(args,
double);
2288 const double np = (pressure * 1024.0) / pen->max_pressure;
2289 normalizedpressure = (UINT32)lround(np);
2290 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2291 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2293 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2295 const unsigned arg = va_arg(args,
unsigned);
2296 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2297 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2299 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2301 const int arg = va_arg(args,
int);
2302 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2303 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2305 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2307 const int arg = va_arg(args,
int);
2308 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2309 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2313 if ((flags & FREERDP_PEN_PRESS) != 0)
2317 flags = FREERDP_PEN_MOTION |
2318 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2319 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2320 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2322 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2324 if (!pen->pressed ||
2325 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2326 flags = FREERDP_PEN_MOTION |
2327 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2329 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2332 flags |= pen->flags;
2333 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2334 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2335 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2336 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2340 if ((flags & FREERDP_PEN_PRESS) != 0)
2342 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2343 pen->hovering = FALSE;
2344 pen->pressed = TRUE;
2346 WINPR_ASSERT(rdpei->PenBegin);
2347 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2348 normalizedpressure, rotation, tiltX, tiltY);
2349 return rc == CHANNEL_RC_OK;
2351 else if ((flags & FREERDP_PEN_MOTION) != 0)
2353 UINT rc = ERROR_INTERNAL_ERROR;
2356 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2359 WINPR_ASSERT(rdpei->PenUpdate);
2360 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2361 rotation, tiltX, tiltY);
2363 else if (pen->hovering)
2365 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2367 WINPR_ASSERT(rdpei->PenHoverUpdate);
2368 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2369 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2373 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2374 pen->hovering = TRUE;
2376 WINPR_ASSERT(rdpei->PenHoverBegin);
2377 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2378 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2380 return rc == CHANNEL_RC_OK;
2382 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2384 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2385 pen->pressed = FALSE;
2386 pen->hovering = TRUE;
2388 WINPR_ASSERT(rdpei->PenUpdate);
2389 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2390 normalizedpressure, rotation, tiltX, tiltY);
2391 if (rc != CHANNEL_RC_OK)
2393 WINPR_ASSERT(rdpei->PenEnd);
2394 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2395 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2396 return re == CHANNEL_RC_OK;
2399 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2401 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2402 "-DCHANNEL_RDPEI_CLIENT=ON");
2408BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2412 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2413 if (state != CONNECTION_STATE_ACTIVE)
2416#if defined(CHANNEL_RDPEI_CLIENT)
2417 RdpeiClientContext* rdpei = cctx->rdpei;
2422 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2427 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2428 pen->hovering = FALSE;
2430 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2431 if (rc != CHANNEL_RC_OK)
2437 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2438 "-DCHANNEL_RDPEI_CLIENT=ON");
2443BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2450 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2453 if (pen->deviceid == deviceid)
2460BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2464 const rdpSettings* settings = cctx->context.settings;
2467 BOOL ainput = FALSE;
2468#if defined(CHANNEL_AINPUT_CLIENT)
2469 ainput = cctx->ainput !=
nullptr;
2472 return useRelative && (haveRelative || ainput);
2475#if defined(WITH_AAD)
2476WINPR_ATTR_MALLOC(free, 1)
2478static
char* get_redirect_uri(const rdpSettings* settings)
2480 char* redirect_uri =
nullptr;
2484 const char* redirect_fmt =
2487 const char* tenantid =
"common";
2491 if (tenantid && redirect_fmt)
2496 size_t redirect_len = 0;
2497 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2503 const char* redirect_fmt =
2506 size_t redirect_len = 0;
2507 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2509 return redirect_uri;
2512static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2514 const rdpSettings* settings = cctx->context.settings;
2516 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2517 AAD_WELLKNOWN_authorization_endpoint);
2520 if (!client_id || !ep || !scope)
2523 char* redirect_uri = get_redirect_uri(settings);
2527 char* url =
nullptr;
2529 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2530 client_id, scope, redirect_uri);
2535static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2537 const rdpSettings* settings = cctx->context.settings;
2539 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2540 AAD_WELLKNOWN_authorization_endpoint);
2543 if (!client_id || !ep || !scope)
2546 char* redirect_uri = get_redirect_uri(settings);
2550 char* url =
nullptr;
2553 const char* code = va_arg(ap,
const char*);
2554 winpr_asprintf(&url, &urllen,
2555 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2556 code, client_id, scope, redirect_uri);
2561static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2563 const rdpSettings* settings = cctx->context.settings;
2564 char* url =
nullptr;
2566 char* redirect_uri = get_redirect_uri(settings);
2569 if (!client_id || !redirect_uri)
2573 const char* scope = va_arg(ap,
const char*);
2578 const char* ep = freerdp_utils_aad_get_wellknown_string(
2579 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2580 winpr_asprintf(&url, &urllen,
2581 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2582 client_id, scope, redirect_uri);
2591static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2593 const rdpSettings* settings = cctx->context.settings;
2595 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2596 AAD_WELLKNOWN_authorization_endpoint);
2597 const char* scope = va_arg(ap,
const char*);
2598 const char* code = va_arg(ap,
const char*);
2599 const char* req_cnf = va_arg(ap,
const char*);
2601 if (!client_id || !ep || !scope || !code || !req_cnf)
2604 char* redirect_uri = get_redirect_uri(settings);
2608 char* url =
nullptr;
2613 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2614 code, client_id, scope, redirect_uri, req_cnf);
2620char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2623 char* str =
nullptr;
2625 va_list ap = WINPR_C_ARRAY_INIT;
2629#if defined(WITH_AAD)
2630 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2631 str = aad_auth_request(cctx, ap);
2633 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2634 str = aad_token_request(cctx, ap);
2636 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2637 str = avd_auth_request(cctx, ap);
2639 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2640 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.