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/utils/smartcardlogon.h>
42#if defined(CHANNEL_AINPUT_CLIENT)
43#include <freerdp/client/ainput.h>
44#include <freerdp/channels/ainput.h>
47#if defined(CHANNEL_VIDEO_CLIENT)
48#include <freerdp/client/video.h>
49#include <freerdp/channels/video.h>
52#if defined(CHANNEL_RDPGFX_CLIENT)
53#include <freerdp/client/rdpgfx.h>
54#include <freerdp/channels/rdpgfx.h>
55#include <freerdp/gdi/gfx.h>
58#if defined(CHANNEL_GEOMETRY_CLIENT)
59#include <freerdp/client/geometry.h>
60#include <freerdp/channels/geometry.h>
63#if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
64#include <freerdp/gdi/video.h>
68#include <freerdp/utils/http.h>
69#include <freerdp/utils/aad.h>
73#include "sso_mib_tokens.h"
76#include <freerdp/log.h>
77#define TAG CLIENT_TAG("common")
79static void set_default_callbacks(freerdp* instance)
81 WINPR_ASSERT(instance);
82 instance->AuthenticateEx = client_cli_authenticate_ex;
83 instance->ChooseSmartcard = client_cli_choose_smartcard;
84 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
85 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
86 instance->PresentGatewayMessage = client_cli_present_gateway_message;
87 instance->LogonErrorInfo = client_cli_logon_error_info;
88 instance->GetAccessToken = client_cli_get_access_token;
89 instance->RetryDialog = client_common_retry_dialog;
92static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
94 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
96 WINPR_ASSERT(instance);
97 WINPR_ASSERT(context);
99 instance->LoadChannels = freerdp_client_load_channels;
100 set_default_callbacks(instance);
102 pEntryPoints = instance->pClientEntryPoints;
103 WINPR_ASSERT(pEntryPoints);
104 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
107static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
109 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
111 WINPR_ASSERT(instance);
112 WINPR_ASSERT(context);
114 pEntryPoints = instance->pClientEntryPoints;
115 WINPR_ASSERT(pEntryPoints);
116 IFCALL(pEntryPoints->ClientFree, instance, context);
121rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
123 freerdp* instance = NULL;
124 rdpContext* context = NULL;
129 IFCALL(pEntryPoints->GlobalInit);
130 instance = freerdp_new();
135 instance->ContextSize = pEntryPoints->ContextSize;
136 instance->ContextNew = freerdp_client_common_new;
137 instance->ContextFree = freerdp_client_common_free;
138 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
140 if (!instance->pClientEntryPoints)
143 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
145 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
148 context = instance->context;
149 context->instance = instance;
151#if defined(WITH_CLIENT_CHANNELS)
152 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
159 free(instance->pClientEntryPoints);
161 freerdp_free(instance);
165void freerdp_client_context_free(rdpContext* context)
167 freerdp* instance = NULL;
172 instance = context->instance;
176 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
177 freerdp_context_free(instance);
180 IFCALL(pEntryPoints->GlobalUninit);
182 free(instance->pClientEntryPoints);
183 freerdp_free(instance);
187int freerdp_client_start(rdpContext* context)
189 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
191 if (!context || !context->instance || !context->instance->pClientEntryPoints)
192 return ERROR_BAD_ARGUMENTS;
195 set_default_callbacks(context->instance);
198 rdpClientContext* client_context = (rdpClientContext*)context;
199 client_context->mibClientWrapper = sso_mib_new(context);
200 if (!client_context->mibClientWrapper)
201 return ERROR_INTERNAL_ERROR;
204 pEntryPoints = context->instance->pClientEntryPoints;
205 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
208int freerdp_client_stop(rdpContext* context)
210 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
212 if (!context || !context->instance || !context->instance->pClientEntryPoints)
213 return ERROR_BAD_ARGUMENTS;
215 pEntryPoints = context->instance->pClientEntryPoints;
216 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
219 rdpClientContext* client_context = (rdpClientContext*)context;
220 sso_mib_free(client_context->mibClientWrapper);
221 client_context->mibClientWrapper = NULL;
226freerdp* freerdp_client_get_instance(rdpContext* context)
228 if (!context || !context->instance)
231 return context->instance;
234HANDLE freerdp_client_get_thread(rdpContext* context)
239 return ((rdpClientContext*)context)->thread;
242static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
267 settings, FreeRDP_GatewayPassword,
307int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
311 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown, NULL,
315int freerdp_client_settings_parse_command_line_ex(
317 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
327 status = freerdp_client_settings_parse_command_line_arguments_ex(
328 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
335 if (!freerdp_client_settings_post_process(settings))
338 const char* name = argv[0];
339 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
340 freerdp_get_build_config());
344int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
346 rdpFile* file = NULL;
348 file = freerdp_client_rdp_file_new();
353 if (!freerdp_client_parse_rdp_file(file, filename))
356 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
361 freerdp_client_rdp_file_free(file);
365int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
368 rdpFile* file = NULL;
370 file = freerdp_client_rdp_file_new();
375 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
376 freerdp_client_populate_settings_from_rdp_file(file, settings))
381 freerdp_client_rdp_file_free(file);
385int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
388 rdpFile* file = NULL;
390 file = freerdp_client_rdp_file_new();
395 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
398 if (!freerdp_client_write_rdp_file(file, filename, unicode))
403 freerdp_client_rdp_file_free(file);
407int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
411 char* filename = NULL;
412 char* password = NULL;
413 rdpAssistanceFile* file = NULL;
415 if (!settings || !argv || (argc < 2))
420 for (
int x = 2; x < argc; x++)
422 const char* key = strstr(argv[x],
"assistance:");
425 password = strchr(key,
':') + 1;
428 file = freerdp_assistance_file_new();
433 status = freerdp_assistance_parse_file(file, filename, password);
438 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
443 freerdp_assistance_file_free(file);
447static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
450 WINPR_ASSERT(instance);
452 WINPR_ASSERT(result);
456 (void)fflush(stdout);
459 if (suggestion && strlen(suggestion) > 0)
461 line = _strdup(suggestion);
462 size = strlen(suggestion);
465 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
468 char ebuffer[256] = { 0 };
469 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
470 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
480 line = StrSep(&line,
"\r");
481 line = StrSep(&line,
"\n");
502static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
503 char** password,
char** domain)
505 static const size_t password_size = 512;
506 const char* userAuth =
"Username: ";
507 const char* domainAuth =
"Domain: ";
508 const char* pwdAuth =
"Password: ";
509 BOOL pinOnly = FALSE;
510 BOOL queryAll = FALSE;
512 WINPR_ASSERT(instance);
513 WINPR_ASSERT(instance->context);
514 WINPR_ASSERT(instance->context->settings);
518 case AUTH_SMARTCARD_PIN:
519 pwdAuth =
"Smartcard-Pin: ";
532 userAuth =
"GatewayUsername: ";
533 domainAuth =
"GatewayDomain: ";
534 pwdAuth =
"GatewayPassword: ";
540 if (!username || !password || !domain)
545 const char* suggest = *username;
546 if (queryAll || !suggest)
548 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
556 const char* suggest = *domain;
557 if (queryAll || !suggest)
559 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
566 char* line = calloc(password_size,
sizeof(
char));
571 const BOOL fromStdin =
574 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
578 if (password_size > 0)
596BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
597 rdp_auth_reason reason)
599 WINPR_ASSERT(instance);
600 WINPR_ASSERT(username);
601 WINPR_ASSERT(password);
602 WINPR_ASSERT(domain);
612 case AUTH_SMARTCARD_PIN:
613 if ((*username) && (*password))
624 return client_cli_authenticate_raw(instance, reason, username, password, domain);
627BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
628 DWORD count, DWORD* choice, BOOL gateway)
630 unsigned long answer = 0;
633 printf(
"Multiple smartcards are available for use:\n");
634 for (DWORD i = 0; i < count; i++)
637 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
638 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
641 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
642 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
643 cert->issuer, cert->upn);
646 free(container_name);
651 char input[10] = { 0 };
653 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
654 gateway ?
"gateway authentication" :
"logon", count - 1);
655 (void)fflush(stdout);
656 if (!fgets(input, 10, stdin))
658 WLog_ERR(TAG,
"could not read from stdin");
662 answer = strtoul(input, &p, 10);
663 if ((*p ==
'\n' && p != input) && answer < count)
665 *choice = (UINT32)answer;
671#if defined(WITH_FREERDP_DEPRECATED)
672BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
676 WLog_INFO(TAG,
"Authentication via smartcard");
680 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
683BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
685 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
689static DWORD client_cli_accept_certificate(freerdp* instance)
693 WINPR_ASSERT(instance);
694 WINPR_ASSERT(instance->context);
696 const rdpSettings* settings = instance->context->settings;
697 WINPR_ASSERT(settings);
705 printf(
"Do you trust the above certificate? (Y/T/N) ");
706 (void)fflush(stdout);
707 answer = freerdp_interruptible_getc(instance->context, stdin);
709 if ((answer == EOF) || feof(stdin))
711 printf(
"\nError: Could not read answer from stdin.\n");
719 answer = freerdp_interruptible_getc(instance->context, stdin);
726 answer = freerdp_interruptible_getc(instance->context, stdin);
733 answer = freerdp_interruptible_getc(instance->context, stdin);
759#if defined(WITH_FREERDP_DEPRECATED)
760DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
761 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
763 WINPR_UNUSED(common_name);
764 WINPR_UNUSED(host_mismatch);
766 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
767 printf(
"Certificate details:\n");
768 printf(
"\tSubject: %s\n", subject);
769 printf(
"\tIssuer: %s\n", issuer);
770 printf(
"\tThumbprint: %s\n", fingerprint);
771 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
772 "the CA certificate in your certificate store, or the certificate has expired.\n"
773 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
774 return client_cli_accept_certificate(instance);
778static char* client_cli_pem_cert(
const char* pem)
780 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
784 char* fp = freerdp_certificate_get_fingerprint(cert);
785 char* start = freerdp_certificate_get_validity(cert, TRUE);
786 char* end = freerdp_certificate_get_validity(cert, FALSE);
787 freerdp_certificate_free(cert);
791 winpr_asprintf(&str, &slen,
794 "\tThumbprint: %s\n",
817DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
818 const char* common_name,
const char* subject,
819 const char* issuer,
const char* fingerprint, DWORD flags)
821 const char* type =
"RDP-Server";
823 WINPR_ASSERT(instance);
824 WINPR_ASSERT(instance->context);
825 WINPR_ASSERT(instance->context->settings);
827 if (flags & VERIFY_CERT_FLAG_GATEWAY)
828 type =
"RDP-Gateway";
830 if (flags & VERIFY_CERT_FLAG_REDIRECT)
831 type =
"RDP-Redirect";
833 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
834 printf(
"\tCommon Name: %s\n", common_name);
835 printf(
"\tSubject: %s\n", subject);
836 printf(
"\tIssuer: %s\n", issuer);
840 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
842 char* str = client_cli_pem_cert(fingerprint);
847 printf(
"\tThumbprint: %s\n", fingerprint);
849 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
850 "the CA certificate in your certificate store, or the certificate has expired.\n"
851 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
852 return client_cli_accept_certificate(instance);
870#if defined(WITH_FREERDP_DEPRECATED)
871DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
872 const char* subject,
const char* issuer,
873 const char* fingerprint,
const char* old_subject,
874 const char* old_issuer,
const char* old_fingerprint)
876 WINPR_UNUSED(common_name);
878 printf(
"WARNING: This callback is deprecated, migrate to "
879 "client_cli_verify_changed_certificate_ex\n");
880 printf(
"!!! Certificate has changed !!!\n");
882 printf(
"New Certificate details:\n");
883 printf(
"\tSubject: %s\n", subject);
884 printf(
"\tIssuer: %s\n", issuer);
885 printf(
"\tThumbprint: %s\n", fingerprint);
887 printf(
"Old Certificate details:\n");
888 printf(
"\tSubject: %s\n", old_subject);
889 printf(
"\tIssuer: %s\n", old_issuer);
890 printf(
"\tThumbprint: %s\n", old_fingerprint);
892 printf(
"The above X.509 certificate does not match the certificate used for previous "
894 "This may indicate that the certificate has been tampered with.\n"
895 "Please contact the administrator of the RDP server and clarify.\n");
896 return client_cli_accept_certificate(instance);
919DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
920 const char* common_name,
const char* subject,
921 const char* issuer,
const char* fingerprint,
922 const char* old_subject,
const char* old_issuer,
923 const char* old_fingerprint, DWORD flags)
925 const char* type =
"RDP-Server";
927 WINPR_ASSERT(instance);
928 WINPR_ASSERT(instance->context);
929 WINPR_ASSERT(instance->context->settings);
931 if (flags & VERIFY_CERT_FLAG_GATEWAY)
932 type =
"RDP-Gateway";
934 if (flags & VERIFY_CERT_FLAG_REDIRECT)
935 type =
"RDP-Redirect";
937 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
939 printf(
"New Certificate details:\n");
940 printf(
"\tCommon Name: %s\n", common_name);
941 printf(
"\tSubject: %s\n", subject);
942 printf(
"\tIssuer: %s\n", issuer);
946 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
948 char* str = client_cli_pem_cert(fingerprint);
953 printf(
"\tThumbprint: %s\n", fingerprint);
955 printf(
"Old Certificate details:\n");
956 printf(
"\tSubject: %s\n", old_subject);
957 printf(
"\tIssuer: %s\n", old_issuer);
961 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
963 char* str = client_cli_pem_cert(old_fingerprint);
968 printf(
"\tThumbprint: %s\n", old_fingerprint);
970 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
972 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
973 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
974 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
975 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
978 printf(
"The above X.509 certificate does not match the certificate used for previous "
980 "This may indicate that the certificate has been tampered with.\n"
981 "Please contact the administrator of the RDP server and clarify.\n");
982 return client_cli_accept_certificate(instance);
985BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
986 BOOL isConsentMandatory,
size_t length,
987 const WCHAR* message)
990 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
992 WINPR_ASSERT(instance);
993 WINPR_ASSERT(instance->context);
994 WINPR_ASSERT(instance->context->settings);
996 if (!isDisplayMandatory && !isConsentMandatory)
999 printf(
"%s:\n", msgType);
1001 printf(
"%.*S\n", (
int)length, message);
1004 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR), NULL);
1007 printf(
"Failed to convert message!\n");
1010 printf(
"%s\n", msg);
1015 while (isConsentMandatory)
1017 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1018 (void)fflush(stdout);
1019 answer = freerdp_interruptible_getc(instance->context, stdin);
1021 if ((answer == EOF) || feof(stdin))
1023 printf(
"\nError: Could not read answer from stdin.\n");
1031 answer = freerdp_interruptible_getc(instance->context, stdin);
1038 (void)freerdp_interruptible_getc(instance->context, stdin);
1051static const char* extract_authorization_code(
char* url)
1055 for (
char* p = strchr(url,
'?'); p++ != NULL; p = strchr(p,
'&'))
1057 if (strncmp(p,
"code=", 5) != 0)
1063 end = strchr(p,
'&');
1073#if defined(WITH_AAD)
1074static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1075 const char* req_cnf,
char** token)
1077 WINPR_ASSERT(instance);
1078 WINPR_ASSERT(instance->context);
1082 char* token_request = NULL;
1084 WINPR_ASSERT(scope);
1085 WINPR_ASSERT(req_cnf);
1086 WINPR_ASSERT(token);
1091 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1092 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1094 printf(
"Browse to: %s\n", request);
1096 printf(
"Paste redirect URL here: \n");
1098 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1102 const char* code = extract_authorization_code(url);
1106 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1107 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1112 rc = client_common_get_access_token(instance, token_request, token);
1115 free(token_request);
1117 return rc && (*token != NULL);
1120static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1122 WINPR_ASSERT(instance);
1123 WINPR_ASSERT(instance->context);
1127 char* token_request = NULL;
1129 WINPR_ASSERT(token);
1135 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1136 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1139 printf(
"Browse to: %s\n", request);
1141 printf(
"Paste redirect URL here: \n");
1143 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1147 const char* code = extract_authorization_code(url);
1150 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1151 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1157 rc = client_common_get_access_token(instance, token_request, token);
1160 free(token_request);
1162 return rc && (*token != NULL);
1166BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1169 WINPR_ASSERT(instance);
1170 WINPR_ASSERT(token);
1172#if !defined(WITH_AAD)
1173 WLog_ERR(TAG,
"Build does not support AAD authentication");
1177 WINPR_ASSERT(instance->context);
1186 case ACCESS_TOKEN_TYPE_AAD:
1191 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1198 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1202 va_start(ap, count);
1203 const char* scope = va_arg(ap,
const char*);
1204 const char* req_cnf = va_arg(ap,
const char*);
1205 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1209 case ACCESS_TOKEN_TYPE_AVD:
1212 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1215 rc = client_cli_get_avd_access_token(instance, token);
1218 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%u], aborting", tokenType);
1229BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1232 WINPR_ASSERT(request);
1233 WINPR_ASSERT(token);
1237 BYTE* response = NULL;
1238 size_t response_length = 0;
1240 wLog* log = WLog_Get(TAG);
1242 const char* token_ep =
1243 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1244 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1246 WLog_ERR(TAG,
"access token request failed");
1250 if (resp_code != HTTP_STATUS_OK)
1252 char buffer[64] = { 0 };
1254 WLog_Print(log, WLOG_ERROR,
1255 "Server unwilling to provide access token; returned status code %s",
1256 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1257 if (response_length > 0)
1258 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1262 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1274SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1277 WINPR_UNUSED(instance);
1278 WINPR_ASSERT(instance->context);
1279 WINPR_UNUSED(userarg);
1280 WINPR_ASSERT(instance);
1283 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1285 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1291 if (strcmp(what,
"arm-transport") == 0)
1292 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1295 const rdpSettings* settings = instance->context->settings;
1299 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1308 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1309 "tech support for help if this keeps happening.",
1314 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1315 what, current + 1, max, delay);
1316 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1319BOOL client_auto_reconnect(freerdp* instance)
1321 return client_auto_reconnect_ex(instance, NULL);
1324BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1328 UINT32 numRetries = 0;
1329 rdpSettings* settings = NULL;
1334 WINPR_ASSERT(instance->context);
1336 settings = instance->context->settings;
1337 WINPR_ASSERT(settings);
1339 const UINT32 maxRetries =
1343 error = freerdp_error_info(instance);
1346 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1348 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1349 freerdp_get_error_info_string(error));
1351 case ERRINFO_SUCCESS:
1353 WLog_INFO(TAG,
"Network disconnect!");
1356 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1363 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1367 switch (freerdp_get_last_error(instance->context))
1369 case FREERDP_ERROR_CONNECT_CANCELLED:
1370 WLog_WARN(TAG,
"Connection aborted by user");
1380 if ((maxRetries > 0) && (numRetries >= maxRetries))
1382 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1387 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1389 const SSIZE_T delay =
1390 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries, NULL);
1395 if (freerdp_reconnect(instance))
1398 switch (freerdp_get_last_error(instance->context))
1400 case FREERDP_ERROR_CONNECT_CANCELLED:
1401 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1406 for (SSIZE_T x = 0; x < delay / 10; x++)
1408 if (!IFCALLRESULT(TRUE, window_events, instance))
1410 WLog_ERR(TAG,
"window_events failed!");
1418 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1422int freerdp_client_common_stop(rdpContext* context)
1424 rdpClientContext* cctx = (rdpClientContext*)context;
1427 freerdp_abort_connect_context(&cctx->context);
1431 (void)WaitForSingleObject(cctx->thread, INFINITE);
1432 (void)CloseHandle(cctx->thread);
1433 cctx->thread = NULL;
1439#if defined(CHANNEL_ENCOMSP_CLIENT)
1440BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1442 rdpClientContext* cctx = NULL;
1448 cctx = (rdpClientContext*)encomsp->custom;
1450 state = cctx->controlToggle;
1451 cctx->controlToggle = !cctx->controlToggle;
1452 return freerdp_client_encomsp_set_control(encomsp, state);
1455BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1462 pdu.ParticipantId = encomsp->participantId;
1463 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1466 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1468 encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1474client_encomsp_participant_created(EncomspClientContext* context,
1477 rdpClientContext* cctx = NULL;
1478 rdpSettings* settings = NULL;
1481 if (!context || !context->custom || !participantCreated)
1482 return ERROR_INVALID_PARAMETER;
1484 cctx = (rdpClientContext*)context->custom;
1487 settings = cctx->context.settings;
1488 WINPR_ASSERT(settings);
1490 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1491 context->participantId = participantCreated->ParticipantId;
1494 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1495 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1497 if (!freerdp_client_encomsp_set_control(context, TRUE))
1498 return ERROR_INTERNAL_ERROR;
1504 return ERROR_INTERNAL_ERROR;
1507 return CHANNEL_RC_OK;
1510static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1512 cctx->encomsp = encomsp;
1513 encomsp->custom = (
void*)cctx;
1514 encomsp->ParticipantCreated = client_encomsp_participant_created;
1517static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1521 encomsp->custom = NULL;
1522 encomsp->ParticipantCreated = NULL;
1526 cctx->encomsp = NULL;
1530void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1531 const ChannelConnectedEventArgs* e)
1533 rdpClientContext* cctx = (rdpClientContext*)context;
1541#if defined(CHANNEL_AINPUT_CLIENT)
1542 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1543 cctx->ainput = (AInputClientContext*)e->pInterface;
1545#if defined(CHANNEL_RDPEI_CLIENT)
1546 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1548 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1551#if defined(CHANNEL_RDPGFX_CLIENT)
1552 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1554 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1557#if defined(CHANNEL_GEOMETRY_CLIENT)
1558 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1560 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1563#if defined(CHANNEL_VIDEO_CLIENT)
1564 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1566 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1568 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1570 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1573#if defined(CHANNEL_ENCOMSP_CLIENT)
1574 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1576 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1581void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1582 const ChannelDisconnectedEventArgs* e)
1584 rdpClientContext* cctx = (rdpClientContext*)context;
1592#if defined(CHANNEL_AINPUT_CLIENT)
1593 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1594 cctx->ainput = NULL;
1596#if defined(CHANNEL_RDPEI_CLIENT)
1597 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1602#if defined(CHANNEL_RDPGFX_CLIENT)
1603 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1605 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1608#if defined(CHANNEL_GEOMETRY_CLIENT)
1609 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1611 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1614#if defined(CHANNEL_VIDEO_CLIENT)
1615 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1617 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1619 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1621 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1624#if defined(CHANNEL_ENCOMSP_CLIENT)
1625 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1627 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1632BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1634 BOOL handled = FALSE;
1638#if defined(CHANNEL_AINPUT_CLIENT)
1645 INT32 value = mflags & 0xFF;
1647 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1648 value = -1 * (0x100 - value);
1654 if (mflags & PTR_FLAGS_WHEEL)
1656 flags |= AINPUT_FLAGS_WHEEL;
1660 if (mflags & PTR_FLAGS_HWHEEL)
1662 flags |= AINPUT_FLAGS_WHEEL;
1666 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1667 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1668 if (rc == CHANNEL_RC_OK)
1674 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1679#if defined(CHANNEL_AINPUT_CLIENT)
1680static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1685 WINPR_ASSERT(cctx->ainput);
1686 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1688 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1690 return rc == CHANNEL_RC_OK;
1694static bool button_pressed(
const rdpClientContext* cctx)
1697 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1699 const BOOL cur = cctx->pressed_buttons[x];
1706BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1709 BOOL handled = FALSE;
1713 if (mflags & PTR_FLAGS_BUTTON1)
1714 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1715 if (mflags & PTR_FLAGS_BUTTON2)
1716 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1717 if (mflags & PTR_FLAGS_BUTTON3)
1718 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1720 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1723 if (!button_pressed(cctx))
1727 const BOOL haveRelative =
1729 if (relative && haveRelative)
1731 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1732 WINPR_ASSERTING_INT_CAST(int16_t, x),
1733 WINPR_ASSERTING_INT_CAST(int16_t, y));
1736#if defined(CHANNEL_AINPUT_CLIENT)
1741 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1742 flags |= AINPUT_FLAGS_HAVE_REL;
1745 flags |= AINPUT_FLAGS_REL;
1747 if (mflags & PTR_FLAGS_DOWN)
1748 flags |= AINPUT_FLAGS_DOWN;
1749 if (mflags & PTR_FLAGS_BUTTON1)
1750 flags |= AINPUT_FLAGS_BUTTON1;
1751 if (mflags & PTR_FLAGS_BUTTON2)
1752 flags |= AINPUT_FLAGS_BUTTON2;
1753 if (mflags & PTR_FLAGS_BUTTON3)
1754 flags |= AINPUT_FLAGS_BUTTON3;
1755 if (mflags & PTR_FLAGS_MOVE)
1756 flags |= AINPUT_FLAGS_MOVE;
1757 handled = ainput_send_diff_event(cctx, flags, x, y);
1767 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1774 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1775 (UINT16)cctx->lastY);
1780BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1783 BOOL handled = FALSE;
1786 if (mflags & PTR_XFLAGS_BUTTON1)
1787 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1788 if (mflags & PTR_XFLAGS_BUTTON2)
1789 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
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)
1806 flags |= AINPUT_FLAGS_REL;
1807 if (mflags & PTR_XFLAGS_DOWN)
1808 flags |= AINPUT_FLAGS_DOWN;
1809 if (mflags & PTR_XFLAGS_BUTTON1)
1810 flags |= AINPUT_XFLAGS_BUTTON1;
1811 if (mflags & PTR_XFLAGS_BUTTON2)
1812 flags |= AINPUT_XFLAGS_BUTTON2;
1814 handled = ainput_send_diff_event(cctx, flags, x, y);
1824 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1831 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1832 (UINT16)cctx->lastY);
1838static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
1841 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
1842 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
1843 WINPR_ASSERT(contact);
1844 WINPR_ASSERT(contact->x <= UINT16_MAX);
1845 WINPR_ASSERT(contact->y <= UINT16_MAX);
1847 switch (contact->count)
1850 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
1851 contact->x, contact->y);
1853 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
1854 contact->x, contact->y);
1856 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
1857 contact->x, contact->y);
1859 return freerdp_client_send_extended_button_event(
1860 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1862 return freerdp_client_send_extended_button_event(
1863 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1870static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1873 WINPR_ASSERT(contact);
1875#if defined(CHANNEL_RDPEI_CLIENT)
1876 RdpeiClientContext* rdpei = cctx->rdpei;
1879 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1883 if (rdpei->TouchRawEvent)
1885 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1886 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1887 ? CONTACT_DATA_PRESSURE_PRESENT
1890 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1891 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1892 RDPINPUT_CONTACT_FLAG_INCONTACT,
1893 contactFlags, contact->pressure);
1894 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1895 contactFlags, contact->pressure);
1899 WINPR_ASSERT(rdpei->TouchEnd);
1900 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1904 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1905 "-DCHANNEL_RDPEI_CLIENT=ON");
1906 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1910static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1913 WINPR_ASSERT(contact);
1915#if defined(CHANNEL_RDPEI_CLIENT)
1916 RdpeiClientContext* rdpei = cctx->rdpei;
1920 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1924 if (rdpei->TouchRawEvent)
1926 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1927 RDPINPUT_CONTACT_FLAG_INCONTACT;
1928 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1929 ? CONTACT_DATA_PRESSURE_PRESENT
1931 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1932 contactFlags, contact->pressure);
1936 WINPR_ASSERT(rdpei->TouchBegin);
1937 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1942 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1943 "-DCHANNEL_RDPEI_CLIENT=ON");
1944 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1948static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
1951 const UINT16 flags = PTR_FLAGS_MOVE;
1953 WINPR_ASSERT(contact);
1954 WINPR_ASSERT(contact->x <= UINT16_MAX);
1955 WINPR_ASSERT(contact->y <= UINT16_MAX);
1956 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1959static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1962 WINPR_ASSERT(contact);
1964#if defined(CHANNEL_RDPEI_CLIENT)
1965 RdpeiClientContext* rdpei = cctx->rdpei;
1968 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
1972 if (rdpei->TouchRawEvent)
1974 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1975 RDPINPUT_CONTACT_FLAG_INCONTACT;
1976 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1977 ? CONTACT_DATA_PRESSURE_PRESENT
1979 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1980 contactFlags, contact->pressure);
1984 WINPR_ASSERT(rdpei->TouchUpdate);
1985 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1990 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1991 "-DCHANNEL_RDPEI_CLIENT=ON");
1992 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
1996static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1999 WINPR_ASSERT(contact);
2001#if defined(CHANNEL_RDPEI_CLIENT)
2002 RdpeiClientContext* rdpei = cctx->rdpei;
2005 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2009 if (rdpei->TouchRawEvent)
2011 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2012 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2013 ? CONTACT_DATA_PRESSURE_PRESENT
2015 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
2016 contactFlags, contact->pressure);
2020 WINPR_ASSERT(rdpei->TouchUpdate);
2021 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2026 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2027 "-DCHANNEL_RDPEI_CLIENT=ON");
2028 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2032static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2033 UINT32 pressure, INT32 x, INT32 y,
2037 WINPR_ASSERT(pcontact);
2039 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2043 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2044 if (newcontact || (contact->id == touchId))
2046 contact->id = touchId;
2047 contact->flags = flags;
2048 contact->pressure = pressure;
2052 *pcontact = *contact;
2054 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2067BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2068 UINT32 pressure, INT32 x, INT32 y)
2070 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
2075 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2078 switch (flags & mask)
2080 case FREERDP_TOUCH_DOWN:
2081 return freerdp_handle_touch_down(cctx, &contact);
2082 case FREERDP_TOUCH_UP:
2083 return freerdp_handle_touch_up(cctx, &contact);
2084 case FREERDP_TOUCH_MOTION:
2085 return freerdp_handle_touch_motion(cctx, &contact);
2086 case FREERDP_TOUCH_CANCEL:
2087 return freerdp_handle_touch_cancel(cctx, &contact);
2089 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2094BOOL freerdp_client_load_channels(freerdp* instance)
2096 WINPR_ASSERT(instance);
2097 WINPR_ASSERT(instance->context);
2099 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2101 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2107int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2109 const char* str_data = freerdp_get_logon_error_info_data(data);
2110 const char* str_type = freerdp_get_logon_error_info_type(type);
2112 if (!instance || !instance->context)
2115 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2119static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2124 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2127 if (deviceid == pen->deviceid)
2137static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2140 static const INT32 null_deviceid = 0;
2143 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2144 if (freerdp_client_is_pen(cctx, deviceid))
2146 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2157 pen->deviceid = deviceid;
2158 pen->max_pressure = pressure;
2161 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2165 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2169BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2171#if defined(CHANNEL_RDPEI_CLIENT)
2172 if ((flags & FREERDP_PEN_REGISTER) != 0)
2176 va_start(args, deviceid);
2177 double pressure = va_arg(args,
double);
2179 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2185 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2189 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2191 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2193 RdpeiClientContext* rdpei = cctx->rdpei;
2194 WINPR_ASSERT(rdpei);
2196 UINT32 normalizedpressure = 1024;
2199 UINT16 rotation = 0;
2203 va_start(args, deviceid);
2205 x = va_arg(args, INT32);
2206 y = va_arg(args, INT32);
2207 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2209 const double pressure = va_arg(args,
double);
2210 const double np = (pressure * 1024.0) / pen->max_pressure;
2211 normalizedpressure = (UINT32)lround(np);
2212 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2213 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2215 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2217 const unsigned arg = va_arg(args,
unsigned);
2218 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2219 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2221 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2223 const int arg = va_arg(args,
int);
2224 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2225 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2227 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2229 const int arg = va_arg(args,
int);
2230 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2231 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2235 if ((flags & FREERDP_PEN_PRESS) != 0)
2239 flags = FREERDP_PEN_MOTION |
2240 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2241 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2242 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2244 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2246 if (!pen->pressed ||
2247 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2248 flags = FREERDP_PEN_MOTION |
2249 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2251 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2254 flags |= pen->flags;
2255 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2256 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2257 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2258 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2262 if ((flags & FREERDP_PEN_PRESS) != 0)
2264 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2265 pen->hovering = FALSE;
2266 pen->pressed = TRUE;
2268 WINPR_ASSERT(rdpei->PenBegin);
2269 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2270 normalizedpressure, rotation, tiltX, tiltY);
2271 return rc == CHANNEL_RC_OK;
2273 else if ((flags & FREERDP_PEN_MOTION) != 0)
2275 UINT rc = ERROR_INTERNAL_ERROR;
2278 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2281 WINPR_ASSERT(rdpei->PenUpdate);
2282 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2283 rotation, tiltX, tiltY);
2285 else if (pen->hovering)
2287 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2289 WINPR_ASSERT(rdpei->PenHoverUpdate);
2290 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2291 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2295 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2296 pen->hovering = TRUE;
2298 WINPR_ASSERT(rdpei->PenHoverBegin);
2299 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2300 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2302 return rc == CHANNEL_RC_OK;
2304 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2306 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2307 pen->pressed = FALSE;
2308 pen->hovering = TRUE;
2310 WINPR_ASSERT(rdpei->PenUpdate);
2311 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2312 normalizedpressure, rotation, tiltX, tiltY);
2313 if (rc != CHANNEL_RC_OK)
2315 WINPR_ASSERT(rdpei->PenEnd);
2316 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2317 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2318 return re == CHANNEL_RC_OK;
2321 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2323 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2324 "-DCHANNEL_RDPEI_CLIENT=ON");
2330BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2334#if defined(CHANNEL_RDPEI_CLIENT)
2335 RdpeiClientContext* rdpei = cctx->rdpei;
2340 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2345 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2346 pen->hovering = FALSE;
2347 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2352 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2353 "-DCHANNEL_RDPEI_CLIENT=ON");
2358BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2365 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2368 if (pen->deviceid == deviceid)
2375BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2377 WINPR_ASSERT(ccontext);
2379 const rdpSettings* settings = ccontext->context.settings;
2382 BOOL ainput = FALSE;
2383#if defined(CHANNEL_AINPUT_CLIENT)
2384 ainput = ccontext->ainput != NULL;
2387 return useRelative && (haveRelative || ainput);
2390#if defined(WITH_AAD)
2391WINPR_ATTR_MALLOC(free, 1)
2393static
char* get_redirect_uri(const rdpSettings* settings)
2395 char* redirect_uri = NULL;
2399 const char* redirect_fmt =
2402 const char* tenantid =
"common";
2406 if (tenantid && redirect_fmt)
2411 size_t redirect_len = 0;
2412 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2418 const char* redirect_fmt =
2421 size_t redirect_len = 0;
2422 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2424 return redirect_uri;
2427static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2429 const rdpSettings* settings = cctx->context.settings;
2431 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2432 AAD_WELLKNOWN_authorization_endpoint);
2435 if (!client_id || !ep || !scope)
2438 char* redirect_uri = get_redirect_uri(settings);
2444 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2445 client_id, scope, redirect_uri);
2450static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2452 const rdpSettings* settings = cctx->context.settings;
2454 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2455 AAD_WELLKNOWN_authorization_endpoint);
2458 if (!client_id || !ep || !scope)
2461 char* redirect_uri = get_redirect_uri(settings);
2468 const char* code = va_arg(ap,
const char*);
2469 winpr_asprintf(&url, &urllen,
2470 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2471 code, client_id, scope, redirect_uri);
2476static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2478 const rdpSettings* settings = cctx->context.settings;
2481 char* redirect_uri = get_redirect_uri(settings);
2484 if (!client_id || !redirect_uri)
2488 const char* scope = va_arg(ap,
const char*);
2493 const char* ep = freerdp_utils_aad_get_wellknown_string(
2494 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2495 winpr_asprintf(&url, &urllen,
2496 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2497 client_id, scope, redirect_uri);
2506static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2508 const rdpSettings* settings = cctx->context.settings;
2510 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2511 AAD_WELLKNOWN_authorization_endpoint);
2512 const char* scope = va_arg(ap,
const char*);
2513 const char* code = va_arg(ap,
const char*);
2514 const char* req_cnf = va_arg(ap,
const char*);
2516 if (!client_id || !ep || !scope || !code || !req_cnf)
2519 char* redirect_uri = get_redirect_uri(settings);
2528 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2529 code, client_id, scope, redirect_uri, req_cnf);
2535char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2544#if defined(WITH_AAD)
2545 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2546 str = aad_auth_request(cctx, ap);
2548 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2549 str = aad_token_request(cctx, ap);
2551 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2552 str = avd_auth_request(cctx, ap);
2554 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2555 str = avd_token_request(cctx, ap);
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
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 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_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.