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>
42#include <freerdp/session.h>
44#if defined(CHANNEL_AINPUT_CLIENT)
45#include <freerdp/client/ainput.h>
46#include <freerdp/channels/ainput.h>
49#if defined(CHANNEL_VIDEO_CLIENT)
50#include <freerdp/client/video.h>
51#include <freerdp/channels/video.h>
54#if defined(CHANNEL_RDPGFX_CLIENT)
55#include <freerdp/client/rdpgfx.h>
56#include <freerdp/channels/rdpgfx.h>
57#include <freerdp/gdi/gfx.h>
60#if defined(CHANNEL_GEOMETRY_CLIENT)
61#include <freerdp/client/geometry.h>
62#include <freerdp/channels/geometry.h>
65#if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
66#include <freerdp/gdi/video.h>
69#include <freerdp/channels/rdpewa.h>
72#include <freerdp/utils/http.h>
73#include <freerdp/utils/aad.h>
77#include "sso_mib_tokens.h"
80#include <freerdp/log.h>
81#define TAG CLIENT_TAG("common")
83static void set_default_callbacks(freerdp* instance)
85 WINPR_ASSERT(instance);
86 instance->AuthenticateEx = client_cli_authenticate_ex;
87 instance->ChooseSmartcard = client_cli_choose_smartcard;
88 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
89 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
90 instance->PresentGatewayMessage = client_cli_present_gateway_message;
91 instance->LogonErrorInfo = client_cli_logon_error_info;
92 instance->GetAccessToken = client_cli_get_access_token;
93 instance->RetryDialog = client_common_retry_dialog;
95 WINPR_ASSERT(instance->context);
96 WINPR_ASSERT(instance->context->update);
97 instance->context->update->SaveSessionInfo = client_common_save_session_info;
100static void client_cli_user_notification(
void* context,
const UserNotificationEventArgs* e)
102 WINPR_UNUSED(context);
104 if (strcmp(e->e.Sender, RDPEWA_CHANNEL_NAME) != 0)
107 if (!e->message || e->message[0] ==
'\0')
109 (void)fprintf(stderr,
"[%s] Touch the security key\n", e->e.Sender);
110 (void)fflush(stderr);
113static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
115 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
117 WINPR_ASSERT(instance);
118 WINPR_ASSERT(context);
120 instance->LoadChannels = freerdp_client_load_channels;
121 set_default_callbacks(instance);
123 pEntryPoints = instance->pClientEntryPoints;
124 WINPR_ASSERT(pEntryPoints);
126 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
129static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
131 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
133 WINPR_ASSERT(instance);
134 WINPR_ASSERT(context);
136 pEntryPoints = instance->pClientEntryPoints;
137 WINPR_ASSERT(pEntryPoints);
138 IFCALL(pEntryPoints->ClientFree, instance, context);
143rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
145 freerdp* instance =
nullptr;
146 rdpContext* context =
nullptr;
151 if (!IFCALLRESULT(TRUE, pEntryPoints->GlobalInit))
154 instance = freerdp_new();
159 instance->ContextSize = pEntryPoints->ContextSize;
160 instance->ContextNew = freerdp_client_common_new;
161 instance->ContextFree = freerdp_client_common_free;
162 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
164 if (!instance->pClientEntryPoints)
167 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
169 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
172 context = instance->context;
173 context->instance = instance;
175#if defined(WITH_CLIENT_CHANNELS)
176 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
183 free(instance->pClientEntryPoints);
185 freerdp_free(instance);
189void freerdp_client_context_free(rdpContext* context)
191 freerdp* instance =
nullptr;
196 instance = context->instance;
200 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
201 freerdp_context_free(instance);
204 IFCALL(pEntryPoints->GlobalUninit);
206 free(instance->pClientEntryPoints);
207 freerdp_free(instance);
211int freerdp_client_start(rdpContext* context)
213 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
215 if (!context || !context->instance || !context->instance->pClientEntryPoints)
216 return ERROR_BAD_ARGUMENTS;
220 set_default_callbacks(context->instance);
224 PubSub_SubscribeUserNotification(context->pubSub, client_cli_user_notification);
231 rdpClientContext* client_context = (rdpClientContext*)context;
232 client_context->mibClientWrapper = sso_mib_new(context);
233 if (!client_context->mibClientWrapper)
234 return ERROR_INTERNAL_ERROR;
237 pEntryPoints = context->instance->pClientEntryPoints;
238 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
241int freerdp_client_stop(rdpContext* context)
243 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
245 if (!context || !context->instance || !context->instance->pClientEntryPoints)
246 return ERROR_BAD_ARGUMENTS;
248 pEntryPoints = context->instance->pClientEntryPoints;
249 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
252 PubSub_UnsubscribeUserNotification(context->pubSub, client_cli_user_notification);
255 rdpClientContext* client_context = (rdpClientContext*)context;
256 sso_mib_free(client_context->mibClientWrapper);
257 client_context->mibClientWrapper =
nullptr;
262freerdp* freerdp_client_get_instance(rdpContext* context)
264 if (!context || !context->instance)
267 return context->instance;
270HANDLE freerdp_client_get_thread(rdpContext* context)
275 return ((rdpClientContext*)context)->thread;
278static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
303 settings, FreeRDP_GatewayPassword,
341int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
345 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown,
346 nullptr, 0,
nullptr,
nullptr);
349int freerdp_client_settings_parse_command_line_ex(
351 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
361 status = freerdp_client_settings_parse_command_line_arguments_ex(
362 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
369 if (!freerdp_client_settings_post_process(settings))
372 const char* name = argv[0];
373 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
374 freerdp_get_build_config());
378int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
380 rdpFile* file =
nullptr;
382 file = freerdp_client_rdp_file_new();
387 if (!freerdp_client_parse_rdp_file(file, filename))
390 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
395 freerdp_client_rdp_file_free(file);
399int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
402 rdpFile* file =
nullptr;
404 file = freerdp_client_rdp_file_new();
409 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
410 freerdp_client_populate_settings_from_rdp_file(file, settings))
415 freerdp_client_rdp_file_free(file);
419int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
422 rdpFile* file =
nullptr;
424 file = freerdp_client_rdp_file_new();
429 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
432 if (!freerdp_client_write_rdp_file(file, filename, unicode))
437 freerdp_client_rdp_file_free(file);
441int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
445 char* filename =
nullptr;
446 char* password =
nullptr;
447 rdpAssistanceFile* file =
nullptr;
449 if (!settings || !argv || (argc < 2))
454 for (
int x = 2; x < argc; x++)
456 const char* key = strstr(argv[x],
"assistance:");
460 char* sep = strchr(key,
':');
468 file = freerdp_assistance_file_new();
473 status = freerdp_assistance_parse_file(file, filename, password);
478 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
483 freerdp_assistance_file_free(file);
487static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
490 WINPR_ASSERT(instance);
492 WINPR_ASSERT(result);
496 (void)fflush(stdout);
498 char* line =
nullptr;
499 if (suggestion && strlen(suggestion) > 0)
501 line = _strdup(suggestion);
502 size = strlen(suggestion);
505 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
508 char ebuffer[256] = WINPR_C_ARRAY_INIT;
509 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
510 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
520 line = StrSep(&line,
"\r");
521 line = StrSep(&line,
"\n");
542static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
543 char** password,
char** domain)
545 static const size_t password_size = 512;
546 const char* userAuth =
"Username: ";
547 const char* domainAuth =
"Domain: ";
548 const char* pwdAuth =
"Password: ";
549 BOOL pinOnly = FALSE;
550 BOOL queryAll = FALSE;
552 WINPR_ASSERT(instance);
553 WINPR_ASSERT(instance->context);
554 WINPR_ASSERT(instance->context->settings);
558 case AUTH_SMARTCARD_PIN:
559 pwdAuth =
"Smartcard-Pin: ";
563 pwdAuth =
"FIDO2 PIN: ";
576 userAuth =
"GatewayUsername: ";
577 domainAuth =
"GatewayDomain: ";
578 pwdAuth =
"GatewayPassword: ";
584 if (!username || !password || !domain)
589 const char* suggest = *username;
590 if (queryAll || !suggest)
592 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
600 const char* suggest = *domain;
601 if (queryAll || !suggest)
603 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
610 char* line = calloc(password_size,
sizeof(
char));
615 const BOOL fromStdin =
618 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
622 if (password_size > 0)
640BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
641 rdp_auth_reason reason)
643 WINPR_ASSERT(instance);
644 WINPR_ASSERT(username);
645 WINPR_ASSERT(password);
646 WINPR_ASSERT(domain);
656 case AUTH_SMARTCARD_PIN:
658 if ((*username) && (*password))
669 return client_cli_authenticate_raw(instance, reason, username, password, domain);
672BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
673 DWORD count, DWORD* choice, BOOL gateway)
675 unsigned long answer = 0;
678 printf(
"Multiple smartcards are available for use:\n");
679 for (DWORD i = 0; i < count; i++)
682 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
683 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
686 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
687 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
688 cert->issuer, cert->upn);
691 free(container_name);
696 char input[10] = WINPR_C_ARRAY_INIT;
698 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
699 gateway ?
"gateway authentication" :
"logon", count - 1);
700 (void)fflush(stdout);
701 if (!fgets(input, 10, stdin))
703 WLog_ERR(TAG,
"could not read from stdin");
707 answer = strtoul(input, &p, 10);
708 if ((*p ==
'\n' && p != input) && answer < count)
710 *choice = (UINT32)answer;
716#if defined(WITH_FREERDP_DEPRECATED)
717BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
721 WLog_INFO(TAG,
"Authentication via smartcard");
725 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
728BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
730 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
734static DWORD client_cli_accept_certificate(freerdp* instance)
738 WINPR_ASSERT(instance);
739 WINPR_ASSERT(instance->context);
741 const rdpSettings* settings = instance->context->settings;
742 WINPR_ASSERT(settings);
750 printf(
"Do you trust the above certificate? (Y/T/N) ");
751 (void)fflush(stdout);
752 answer = freerdp_interruptible_getc(instance->context, stdin);
754 if ((answer == EOF) || feof(stdin))
756 printf(
"\nError: Could not read answer from stdin.\n");
764 answer = freerdp_interruptible_getc(instance->context, stdin);
771 answer = freerdp_interruptible_getc(instance->context, stdin);
778 answer = freerdp_interruptible_getc(instance->context, stdin);
804#if defined(WITH_FREERDP_DEPRECATED)
805DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
806 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
808 WINPR_UNUSED(common_name);
809 WINPR_UNUSED(host_mismatch);
811 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
812 printf(
"Certificate details:\n");
813 printf(
"\tSubject: %s\n", subject);
814 printf(
"\tIssuer: %s\n", issuer);
815 printf(
"\tThumbprint: %s\n", fingerprint);
816 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
817 "the CA certificate in your certificate store, or the certificate has expired.\n"
818 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
819 return client_cli_accept_certificate(instance);
823static char* client_cli_pem_cert(
const char* pem)
825 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
829 char* fp = freerdp_certificate_get_fingerprint(cert);
830 char* start = freerdp_certificate_get_validity(cert, TRUE);
831 char* end = freerdp_certificate_get_validity(cert, FALSE);
832 freerdp_certificate_free(cert);
836 winpr_asprintf(&str, &slen,
839 "\tThumbprint: %s\n",
862DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
863 const char* common_name,
const char* subject,
864 const char* issuer,
const char* fingerprint, DWORD flags)
866 const char* type =
"RDP-Server";
868 WINPR_ASSERT(instance);
869 WINPR_ASSERT(instance->context);
870 WINPR_ASSERT(instance->context->settings);
872 if (flags & VERIFY_CERT_FLAG_GATEWAY)
873 type =
"RDP-Gateway";
875 if (flags & VERIFY_CERT_FLAG_REDIRECT)
876 type =
"RDP-Redirect";
878 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
879 printf(
"\tCommon Name: %s\n", common_name);
880 printf(
"\tSubject: %s\n", subject);
881 printf(
"\tIssuer: %s\n", issuer);
885 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
887 char* str = client_cli_pem_cert(fingerprint);
892 printf(
"\tThumbprint: %s\n", fingerprint);
894 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
895 "the CA certificate in your certificate store, or the certificate has expired.\n"
896 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
897 return client_cli_accept_certificate(instance);
915#if defined(WITH_FREERDP_DEPRECATED)
916DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
917 const char* subject,
const char* issuer,
918 const char* fingerprint,
const char* old_subject,
919 const char* old_issuer,
const char* old_fingerprint)
921 WINPR_UNUSED(common_name);
923 printf(
"WARNING: This callback is deprecated, migrate to "
924 "client_cli_verify_changed_certificate_ex\n");
925 printf(
"!!! Certificate has changed !!!\n");
927 printf(
"New Certificate details:\n");
928 printf(
"\tSubject: %s\n", subject);
929 printf(
"\tIssuer: %s\n", issuer);
930 printf(
"\tThumbprint: %s\n", fingerprint);
932 printf(
"Old Certificate details:\n");
933 printf(
"\tSubject: %s\n", old_subject);
934 printf(
"\tIssuer: %s\n", old_issuer);
935 printf(
"\tThumbprint: %s\n", old_fingerprint);
937 printf(
"The above X.509 certificate does not match the certificate used for previous "
939 "This may indicate that the certificate has been tampered with.\n"
940 "Please contact the administrator of the RDP server and clarify.\n");
941 return client_cli_accept_certificate(instance);
964DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
965 const char* common_name,
const char* subject,
966 const char* issuer,
const char* fingerprint,
967 const char* old_subject,
const char* old_issuer,
968 const char* old_fingerprint, DWORD flags)
970 const char* type =
"RDP-Server";
972 WINPR_ASSERT(instance);
973 WINPR_ASSERT(instance->context);
974 WINPR_ASSERT(instance->context->settings);
976 if (flags & VERIFY_CERT_FLAG_GATEWAY)
977 type =
"RDP-Gateway";
979 if (flags & VERIFY_CERT_FLAG_REDIRECT)
980 type =
"RDP-Redirect";
982 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
984 printf(
"New Certificate details:\n");
985 printf(
"\tCommon Name: %s\n", common_name);
986 printf(
"\tSubject: %s\n", subject);
987 printf(
"\tIssuer: %s\n", issuer);
991 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
993 char* str = client_cli_pem_cert(fingerprint);
998 printf(
"\tThumbprint: %s\n", fingerprint);
1000 printf(
"Old Certificate details:\n");
1001 printf(
"\tSubject: %s\n", old_subject);
1002 printf(
"\tIssuer: %s\n", old_issuer);
1006 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1008 char* str = client_cli_pem_cert(old_fingerprint);
1013 printf(
"\tThumbprint: %s\n", old_fingerprint);
1015 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
1017 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
1018 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
1019 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
1020 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
1023 printf(
"The above X.509 certificate does not match the certificate used for previous "
1025 "This may indicate that the certificate has been tampered with.\n"
1026 "Please contact the administrator of the RDP server and clarify.\n");
1027 return client_cli_accept_certificate(instance);
1030BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1031 BOOL isConsentMandatory,
size_t length,
1032 const WCHAR* message)
1034 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
1036 WINPR_ASSERT(instance);
1037 WINPR_ASSERT(instance->context);
1038 WINPR_ASSERT(instance->context->settings);
1040 if (!isDisplayMandatory && !isConsentMandatory)
1043 printf(
"%s:\n", msgType);
1045 printf(
"%.*S\n", (
int)length, message);
1048 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR),
nullptr);
1051 printf(
"Failed to convert message!\n");
1054 printf(
"%s\n", msg);
1059 while (isConsentMandatory)
1061 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1062 (void)fflush(stdout);
1063 const int answer = freerdp_interruptible_getc(instance->context, stdin);
1065 if ((answer == EOF) || feof(stdin))
1067 printf(
"\nError: Could not read answer from stdin.\n");
1071 const int confirm = freerdp_interruptible_getc(instance->context, stdin);
1094static const char* extract_authorization_code(
char* url)
1098 for (
char* p = strchr(url,
'?'); p++ !=
nullptr; p = strchr(p,
'&'))
1100 if (strncmp(p,
"code=", 5) != 0)
1103 char* end =
nullptr;
1106 end = strchr(p,
'&');
1116#if defined(WITH_AAD)
1117static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1118 const char* req_cnf,
char** token)
1120 WINPR_ASSERT(instance);
1121 WINPR_ASSERT(instance->context);
1124 char* url =
nullptr;
1125 char* token_request =
nullptr;
1127 WINPR_ASSERT(scope);
1128 WINPR_ASSERT(req_cnf);
1129 WINPR_ASSERT(token);
1134 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1135 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1137 printf(
"Browse to: %s\n", request);
1139 printf(
"Paste redirect URL here: \n");
1141 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1145 const char* code = extract_authorization_code(url);
1149 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1150 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1155 rc = client_common_get_access_token(instance, token_request, token);
1158 free(token_request);
1160 return rc && (*token !=
nullptr);
1163static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1165 WINPR_ASSERT(instance);
1166 WINPR_ASSERT(instance->context);
1169 char* url =
nullptr;
1170 char* token_request =
nullptr;
1172 WINPR_ASSERT(token);
1178 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1179 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1182 printf(
"Browse to: %s\n", request);
1184 printf(
"Paste redirect URL here: \n");
1186 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1190 const char* code = extract_authorization_code(url);
1193 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1194 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1200 rc = client_common_get_access_token(instance, token_request, token);
1203 free(token_request);
1205 return rc && (*token !=
nullptr);
1209BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1212 WINPR_ASSERT(instance);
1213 WINPR_ASSERT(token);
1215#if !defined(WITH_AAD)
1216 WLog_ERR(TAG,
"Build does not support AAD authentication");
1220 WINPR_ASSERT(instance->context);
1229 case ACCESS_TOKEN_TYPE_AAD:
1234 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1243 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1246 va_list ap = WINPR_C_ARRAY_INIT;
1247 va_start(ap, count);
1248 const char* scope = va_arg(ap,
const char*);
1249 const char* req_cnf = va_arg(ap,
const char*);
1250 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1255 case ACCESS_TOKEN_TYPE_AVD:
1258 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1261 rc = client_cli_get_avd_access_token(instance, token);
1264 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%u], aborting", tokenType);
1275BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1278 WINPR_ASSERT(request);
1279 WINPR_ASSERT(token);
1283 BYTE* response =
nullptr;
1284 size_t response_length = 0;
1286 wLog* log = WLog_Get(TAG);
1288 const char* token_ep =
1289 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1290 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1292 WLog_ERR(TAG,
"access token request failed");
1296 if (resp_code != HTTP_STATUS_OK)
1298 char buffer[64] = WINPR_C_ARRAY_INIT;
1300 WLog_Print(log, WLOG_ERROR,
1301 "Server unwilling to provide access token; returned status code %s",
1302 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1303 if (response_length > 0)
1304 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1308 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1320SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1323 WINPR_UNUSED(instance);
1324 WINPR_ASSERT(instance->context);
1325 WINPR_UNUSED(userarg);
1326 WINPR_ASSERT(instance);
1329 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1331 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1337 if (strcmp(what,
"arm-transport") == 0)
1338 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1341 const rdpSettings* settings = instance->context->settings;
1345 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1354 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1355 "tech support for help if this keeps happening.",
1360 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1361 what, current + 1, max, delay);
1362 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1365BOOL client_auto_reconnect(freerdp* instance)
1367 return client_auto_reconnect_ex(instance,
nullptr);
1370BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1374 UINT32 numRetries = 0;
1375 rdpSettings* settings =
nullptr;
1380 WINPR_ASSERT(instance->context);
1382 settings = instance->context->settings;
1383 WINPR_ASSERT(settings);
1385 const UINT32 maxRetries =
1389 error = freerdp_error_info(instance);
1392 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1394 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1395 freerdp_get_error_info_string(error));
1397 case ERRINFO_SUCCESS:
1399 WLog_INFO(TAG,
"Network disconnect!");
1402 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1409 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1413 const UINT err = freerdp_get_last_error(instance->context);
1416 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1417 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1418 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1419 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1420 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1421 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1422 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1423 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1424 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1425 freerdp_get_last_error_name(err));
1427 case FREERDP_ERROR_CONNECT_CANCELLED:
1428 WLog_WARN(TAG,
"Connection aborted by user");
1438 if ((maxRetries > 0) && (numRetries >= maxRetries))
1440 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1445 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1447 const SSIZE_T delay =
1448 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1453 if (freerdp_reconnect(instance))
1456 switch (freerdp_get_last_error(instance->context))
1458 case FREERDP_ERROR_CONNECT_CANCELLED:
1459 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1464 for (SSIZE_T x = 0; x < delay / 10; x++)
1466 if (!IFCALLRESULT(TRUE, window_events, instance))
1468 WLog_ERR(TAG,
"window_events failed!");
1476 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1480int freerdp_client_common_stop(rdpContext* context)
1482 rdpClientContext* cctx = (rdpClientContext*)context;
1485 freerdp_abort_connect_context(&cctx->context);
1489 (void)WaitForSingleObject(cctx->thread, INFINITE);
1490 (void)CloseHandle(cctx->thread);
1491 cctx->thread =
nullptr;
1497#if defined(CHANNEL_ENCOMSP_CLIENT)
1498BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1500 rdpClientContext* cctx =
nullptr;
1506 cctx = (rdpClientContext*)encomsp->custom;
1508 state = cctx->controlToggle;
1509 cctx->controlToggle = !cctx->controlToggle;
1510 return freerdp_client_encomsp_set_control(encomsp, state);
1513BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1520 pdu.ParticipantId = encomsp->participantId;
1521 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1524 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1526 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1527 return rc == CHANNEL_RC_OK;
1531client_encomsp_participant_created(EncomspClientContext* context,
1534 rdpClientContext* cctx =
nullptr;
1535 rdpSettings* settings =
nullptr;
1538 if (!context || !context->custom || !participantCreated)
1539 return ERROR_INVALID_PARAMETER;
1541 cctx = (rdpClientContext*)context->custom;
1544 settings = cctx->context.settings;
1545 WINPR_ASSERT(settings);
1547 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1548 context->participantId = participantCreated->ParticipantId;
1551 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1552 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1554 if (!freerdp_client_encomsp_set_control(context, TRUE))
1555 return ERROR_INTERNAL_ERROR;
1561 return ERROR_INTERNAL_ERROR;
1564 return CHANNEL_RC_OK;
1567static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1569 cctx->encomsp = encomsp;
1570 encomsp->custom = (
void*)cctx;
1571 encomsp->ParticipantCreated = client_encomsp_participant_created;
1574static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1578 encomsp->custom =
nullptr;
1579 encomsp->ParticipantCreated =
nullptr;
1583 cctx->encomsp =
nullptr;
1587void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1588 const ChannelConnectedEventArgs* e)
1590 rdpClientContext* cctx = (rdpClientContext*)context;
1598#if defined(CHANNEL_AINPUT_CLIENT)
1599 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1600 cctx->ainput = (AInputClientContext*)e->pInterface;
1602#if defined(CHANNEL_RDPEI_CLIENT)
1603 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1605 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1608#if defined(CHANNEL_RDPGFX_CLIENT)
1609 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1611 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1614#if defined(CHANNEL_GEOMETRY_CLIENT)
1615 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1617 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1620#if defined(CHANNEL_VIDEO_CLIENT)
1621 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1623 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1625 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1627 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1630#if defined(CHANNEL_ENCOMSP_CLIENT)
1631 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1633 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1638void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1639 const ChannelDisconnectedEventArgs* e)
1641 rdpClientContext* cctx = (rdpClientContext*)context;
1649#if defined(CHANNEL_AINPUT_CLIENT)
1650 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1651 cctx->ainput =
nullptr;
1653#if defined(CHANNEL_RDPEI_CLIENT)
1654 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1656 cctx->rdpei =
nullptr;
1659#if defined(CHANNEL_RDPGFX_CLIENT)
1660 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1662 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1665#if defined(CHANNEL_GEOMETRY_CLIENT)
1666 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1668 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1671#if defined(CHANNEL_VIDEO_CLIENT)
1672 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1674 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1676 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1678 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1681#if defined(CHANNEL_ENCOMSP_CLIENT)
1682 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1684 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1689BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1691 BOOL handled = FALSE;
1695 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1696 if (state != CONNECTION_STATE_ACTIVE)
1699#if defined(CHANNEL_AINPUT_CLIENT)
1706 INT32 value = mflags & 0xFF;
1708 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1709 value = -1 * (0x100 - value);
1715 if (mflags & PTR_FLAGS_WHEEL)
1717 flags |= AINPUT_FLAGS_WHEEL;
1721 if (mflags & PTR_FLAGS_HWHEEL)
1723 flags |= AINPUT_FLAGS_WHEEL;
1727 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1728 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1729 if (rc == CHANNEL_RC_OK)
1735 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1740#if defined(CHANNEL_AINPUT_CLIENT)
1741static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1746 WINPR_ASSERT(cctx->ainput);
1747 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1749 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1751 return rc == CHANNEL_RC_OK;
1755static bool button_pressed(
const rdpClientContext* cctx)
1758 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1760 const BOOL cur = cctx->pressed_buttons[x];
1767BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1770 BOOL handled = FALSE;
1773 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1774 if (state != CONNECTION_STATE_ACTIVE)
1777 if (mflags & PTR_FLAGS_BUTTON1)
1778 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1779 if (mflags & PTR_FLAGS_BUTTON2)
1780 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1781 if (mflags & PTR_FLAGS_BUTTON3)
1782 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1784 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1787 if (!button_pressed(cctx))
1791 const BOOL haveRelative =
1793 if (relative && haveRelative)
1795 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1796 WINPR_ASSERTING_INT_CAST(int16_t, x),
1797 WINPR_ASSERTING_INT_CAST(int16_t, y));
1800#if defined(CHANNEL_AINPUT_CLIENT)
1805 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1806 flags |= AINPUT_FLAGS_HAVE_REL;
1809 flags |= AINPUT_FLAGS_REL;
1811 if (mflags & PTR_FLAGS_DOWN)
1812 flags |= AINPUT_FLAGS_DOWN;
1813 if (mflags & PTR_FLAGS_BUTTON1)
1814 flags |= AINPUT_FLAGS_BUTTON1;
1815 if (mflags & PTR_FLAGS_BUTTON2)
1816 flags |= AINPUT_FLAGS_BUTTON2;
1817 if (mflags & PTR_FLAGS_BUTTON3)
1818 flags |= AINPUT_FLAGS_BUTTON3;
1819 if (mflags & PTR_FLAGS_MOVE)
1820 flags |= AINPUT_FLAGS_MOVE;
1821 handled = ainput_send_diff_event(cctx, flags, x, y);
1831 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1838 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1839 (UINT16)cctx->lastY);
1844BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1847 BOOL handled = FALSE;
1850 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1851 if (state != CONNECTION_STATE_ACTIVE)
1854 if (mflags & PTR_XFLAGS_BUTTON1)
1855 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1856 if (mflags & PTR_XFLAGS_BUTTON2)
1857 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1859 const BOOL haveRelative =
1861 if (relative && haveRelative)
1863 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1864 WINPR_ASSERTING_INT_CAST(int16_t, x),
1865 WINPR_ASSERTING_INT_CAST(int16_t, y));
1868#if defined(CHANNEL_AINPUT_CLIENT)
1874 flags |= AINPUT_FLAGS_REL;
1875 if (mflags & PTR_XFLAGS_DOWN)
1876 flags |= AINPUT_FLAGS_DOWN;
1877 if (mflags & PTR_XFLAGS_BUTTON1)
1878 flags |= AINPUT_XFLAGS_BUTTON1;
1879 if (mflags & PTR_XFLAGS_BUTTON2)
1880 flags |= AINPUT_XFLAGS_BUTTON2;
1882 handled = ainput_send_diff_event(cctx, flags, x, y);
1892 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1899 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1900 (UINT16)cctx->lastY);
1906static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
1909 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
1910 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
1911 WINPR_ASSERT(contact);
1912 WINPR_ASSERT(contact->x <= UINT16_MAX);
1913 WINPR_ASSERT(contact->y <= UINT16_MAX);
1915 switch (contact->count)
1918 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
1919 contact->x, contact->y);
1921 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
1922 contact->x, contact->y);
1924 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
1925 contact->x, contact->y);
1927 return freerdp_client_send_extended_button_event(
1928 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1930 return freerdp_client_send_extended_button_event(
1931 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1938static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1941 WINPR_ASSERT(contact);
1943#if defined(CHANNEL_RDPEI_CLIENT)
1944 RdpeiClientContext* rdpei = cctx->rdpei;
1947 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1951 if (rdpei->TouchRawEvent)
1953 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1954 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1955 ? CONTACT_DATA_PRESSURE_PRESENT
1959 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1960 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1961 RDPINPUT_CONTACT_FLAG_INCONTACT,
1962 contactFlags, contact->pressure);
1963 if (rc1 != CHANNEL_RC_OK)
1966 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
1967 &contactId, flags, contactFlags, contact->pressure);
1968 if (rc2 != CHANNEL_RC_OK)
1973 WINPR_ASSERT(rdpei->TouchEnd);
1974 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1975 if (rc != CHANNEL_RC_OK)
1980 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1981 "-DCHANNEL_RDPEI_CLIENT=ON");
1982 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1986static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1989 WINPR_ASSERT(contact);
1991#if defined(CHANNEL_RDPEI_CLIENT)
1992 RdpeiClientContext* rdpei = cctx->rdpei;
1996 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2000 if (rdpei->TouchRawEvent)
2002 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
2003 RDPINPUT_CONTACT_FLAG_INCONTACT;
2004 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2005 ? CONTACT_DATA_PRESSURE_PRESENT
2007 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2008 flags, contactFlags, contact->pressure);
2009 if (rc != CHANNEL_RC_OK)
2014 WINPR_ASSERT(rdpei->TouchBegin);
2015 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
2016 if (rc != CHANNEL_RC_OK)
2022 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2023 "-DCHANNEL_RDPEI_CLIENT=ON");
2024 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2028static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
2031 const UINT16 flags = PTR_FLAGS_MOVE;
2033 WINPR_ASSERT(contact);
2034 WINPR_ASSERT(contact->x <= UINT16_MAX);
2035 WINPR_ASSERT(contact->y <= UINT16_MAX);
2036 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
2039static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2042 WINPR_ASSERT(contact);
2044#if defined(CHANNEL_RDPEI_CLIENT)
2045 RdpeiClientContext* rdpei = cctx->rdpei;
2048 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2052 if (rdpei->TouchRawEvent)
2054 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2055 RDPINPUT_CONTACT_FLAG_INCONTACT;
2056 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2057 ? CONTACT_DATA_PRESSURE_PRESENT
2059 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2060 flags, contactFlags, contact->pressure);
2061 if (rc != CHANNEL_RC_OK)
2066 WINPR_ASSERT(rdpei->TouchUpdate);
2067 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2068 if (rc != CHANNEL_RC_OK)
2074 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2075 "-DCHANNEL_RDPEI_CLIENT=ON");
2076 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2080static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2083 WINPR_ASSERT(contact);
2085#if defined(CHANNEL_RDPEI_CLIENT)
2086 RdpeiClientContext* rdpei = cctx->rdpei;
2089 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2093 if (rdpei->TouchRawEvent)
2095 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2096 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2097 ? CONTACT_DATA_PRESSURE_PRESENT
2099 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2100 flags, contactFlags, contact->pressure);
2101 if (rc != CHANNEL_RC_OK)
2106 WINPR_ASSERT(rdpei->TouchUpdate);
2107 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2108 if (rc != CHANNEL_RC_OK)
2114 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2115 "-DCHANNEL_RDPEI_CLIENT=ON");
2116 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2120static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2121 UINT32 pressure, INT32 x, INT32 y,
2125 WINPR_ASSERT(pcontact);
2127 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2131 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2132 if (newcontact || (contact->id == touchId))
2134 contact->id = touchId;
2135 contact->flags = flags;
2136 contact->pressure = pressure;
2140 *pcontact = *contact;
2142 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2155BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2156 UINT32 pressure, INT32 x, INT32 y)
2159 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2162 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2163 if (state != CONNECTION_STATE_ACTIVE)
2168 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2171 switch (flags & mask)
2173 case FREERDP_TOUCH_DOWN:
2174 return freerdp_handle_touch_down(cctx, &contact);
2175 case FREERDP_TOUCH_UP:
2176 return freerdp_handle_touch_up(cctx, &contact);
2177 case FREERDP_TOUCH_MOTION:
2178 return freerdp_handle_touch_motion(cctx, &contact);
2179 case FREERDP_TOUCH_CANCEL:
2180 return freerdp_handle_touch_cancel(cctx, &contact);
2182 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2187BOOL freerdp_client_load_channels(freerdp* instance)
2189 WINPR_ASSERT(instance);
2190 WINPR_ASSERT(instance->context);
2192 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2194 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2200int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2202 const char* str_data = freerdp_get_logon_error_info_data(data);
2203 const char* str_type = freerdp_get_logon_error_info_type(type);
2205 if (!instance || !instance->context)
2208 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2212static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2217 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2220 if (deviceid == pen->deviceid)
2230static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2233 static const INT32 null_deviceid = 0;
2236 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2237 if (freerdp_client_is_pen(cctx, deviceid))
2239 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2250 pen->deviceid = deviceid;
2251 pen->max_pressure = pressure;
2254 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2258 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2262BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2264 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2265 if (state != CONNECTION_STATE_ACTIVE)
2268#if defined(CHANNEL_RDPEI_CLIENT)
2269 if ((flags & FREERDP_PEN_REGISTER) != 0)
2271 va_list args = WINPR_C_ARRAY_INIT;
2273 va_start(args, deviceid);
2274 double pressure = va_arg(args,
double);
2276 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2282 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2286 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2288 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2290 RdpeiClientContext* rdpei = cctx->rdpei;
2291 WINPR_ASSERT(rdpei);
2293 UINT32 normalizedpressure = 1024;
2296 UINT16 rotation = 0;
2299 va_list args = WINPR_C_ARRAY_INIT;
2300 va_start(args, deviceid);
2302 x = va_arg(args, INT32);
2303 y = va_arg(args, INT32);
2304 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2306 const double pressure = va_arg(args,
double);
2307 const double np = (pressure * 1024.0) / pen->max_pressure;
2308 normalizedpressure = (UINT32)lround(np);
2309 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2310 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2312 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2314 const unsigned arg = va_arg(args,
unsigned);
2315 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2316 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2318 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2320 const int arg = va_arg(args,
int);
2321 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2322 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2324 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2326 const int arg = va_arg(args,
int);
2327 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2328 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2332 if ((flags & FREERDP_PEN_PRESS) != 0)
2336 flags = FREERDP_PEN_MOTION |
2337 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2338 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2339 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2341 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2343 if (!pen->pressed ||
2344 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2345 flags = FREERDP_PEN_MOTION |
2346 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2348 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2351 flags |= pen->flags;
2352 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2353 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2354 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2355 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2359 if ((flags & FREERDP_PEN_PRESS) != 0)
2361 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2362 pen->hovering = FALSE;
2363 pen->pressed = TRUE;
2365 WINPR_ASSERT(rdpei->PenBegin);
2366 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2367 normalizedpressure, rotation, tiltX, tiltY);
2368 return rc == CHANNEL_RC_OK;
2370 else if ((flags & FREERDP_PEN_MOTION) != 0)
2372 UINT rc = ERROR_INTERNAL_ERROR;
2375 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2378 WINPR_ASSERT(rdpei->PenUpdate);
2379 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2380 rotation, tiltX, tiltY);
2382 else if (pen->hovering)
2384 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2386 WINPR_ASSERT(rdpei->PenHoverUpdate);
2387 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2388 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2392 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2393 pen->hovering = TRUE;
2395 WINPR_ASSERT(rdpei->PenHoverBegin);
2396 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2397 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2399 return rc == CHANNEL_RC_OK;
2401 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2403 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2404 pen->pressed = FALSE;
2405 pen->hovering = TRUE;
2407 WINPR_ASSERT(rdpei->PenUpdate);
2408 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2409 normalizedpressure, rotation, tiltX, tiltY);
2410 if (rc != CHANNEL_RC_OK)
2412 WINPR_ASSERT(rdpei->PenEnd);
2413 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2414 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2415 return re == CHANNEL_RC_OK;
2418 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2420 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2421 "-DCHANNEL_RDPEI_CLIENT=ON");
2427BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2431 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2432 if (state != CONNECTION_STATE_ACTIVE)
2435#if defined(CHANNEL_RDPEI_CLIENT)
2436 RdpeiClientContext* rdpei = cctx->rdpei;
2441 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2446 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2447 pen->hovering = FALSE;
2449 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2450 if (rc != CHANNEL_RC_OK)
2456 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2457 "-DCHANNEL_RDPEI_CLIENT=ON");
2462BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2469 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2472 if (pen->deviceid == deviceid)
2479BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2483 const rdpSettings* settings = cctx->context.settings;
2486 BOOL ainput = FALSE;
2487#if defined(CHANNEL_AINPUT_CLIENT)
2488 ainput = cctx->ainput !=
nullptr;
2491 return useRelative && (haveRelative || ainput);
2494#if defined(WITH_AAD)
2495WINPR_ATTR_MALLOC(free, 1)
2496static
char* get_redirect_uri(const rdpSettings* settings)
2498 char* redirect_uri =
nullptr;
2502 const char* redirect_fmt =
2505 const char* tenantid =
"common";
2509 if (tenantid && redirect_fmt)
2514 size_t redirect_len = 0;
2515 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2521 const char* redirect_fmt =
2524 size_t redirect_len = 0;
2525 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2527 return redirect_uri;
2530static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2532 const rdpSettings* settings = cctx->context.settings;
2534 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2535 AAD_WELLKNOWN_authorization_endpoint);
2538 if (!client_id || !ep || !scope)
2541 char* redirect_uri = get_redirect_uri(settings);
2545 char* url =
nullptr;
2547 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2548 client_id, scope, redirect_uri);
2553static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2555 const rdpSettings* settings = cctx->context.settings;
2557 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2558 AAD_WELLKNOWN_authorization_endpoint);
2561 if (!client_id || !ep || !scope)
2564 char* redirect_uri = get_redirect_uri(settings);
2568 char* url =
nullptr;
2571 const char* code = va_arg(ap,
const char*);
2572 winpr_asprintf(&url, &urllen,
2573 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2574 code, client_id, scope, redirect_uri);
2579static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2581 const rdpSettings* settings = cctx->context.settings;
2582 char* url =
nullptr;
2584 char* redirect_uri = get_redirect_uri(settings);
2587 if (!client_id || !redirect_uri)
2591 const char* scope = va_arg(ap,
const char*);
2596 const char* ep = freerdp_utils_aad_get_wellknown_string(
2597 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2598 winpr_asprintf(&url, &urllen,
2599 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2600 client_id, scope, redirect_uri);
2609static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2611 const rdpSettings* settings = cctx->context.settings;
2613 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2614 AAD_WELLKNOWN_authorization_endpoint);
2615 const char* scope = va_arg(ap,
const char*);
2616 const char* code = va_arg(ap,
const char*);
2617 const char* req_cnf = va_arg(ap,
const char*);
2619 if (!client_id || !ep || !scope || !code || !req_cnf)
2622 char* redirect_uri = get_redirect_uri(settings);
2626 char* url =
nullptr;
2631 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2632 code, client_id, scope, redirect_uri, req_cnf);
2638char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2641 char* str =
nullptr;
2643 va_list ap = WINPR_C_ARRAY_INIT;
2647#if defined(WITH_AAD)
2648 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2649 str = aad_auth_request(cctx, ap);
2651 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2652 str = aad_token_request(cctx, ap);
2654 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2655 str = avd_auth_request(cctx, ap);
2657 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2658 str = avd_token_request(cctx, ap);
2668BOOL client_common_save_session_info(WINPR_ATTR_UNUSED rdpContext* context, UINT32 type,
2671 char buffer[128] = WINPR_C_ARRAY_INIT;
2672 WLog_INFO(TAG,
"%s [%s]", freerdp_session_logon_type_str(type),
2673 freerdp_session_logon_type_data_str(type, data, buffer,
sizeof(buffer)));
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.