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 =
nullptr;
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 =
nullptr;
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 =
nullptr;
124 rdpContext* context =
nullptr;
129 if (!IFCALLRESULT(TRUE, pEntryPoints->GlobalInit))
132 instance = freerdp_new();
137 instance->ContextSize = pEntryPoints->ContextSize;
138 instance->ContextNew = freerdp_client_common_new;
139 instance->ContextFree = freerdp_client_common_free;
140 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
142 if (!instance->pClientEntryPoints)
145 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
147 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
150 context = instance->context;
151 context->instance = instance;
153#if defined(WITH_CLIENT_CHANNELS)
154 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
161 free(instance->pClientEntryPoints);
163 freerdp_free(instance);
167void freerdp_client_context_free(rdpContext* context)
169 freerdp* instance =
nullptr;
174 instance = context->instance;
178 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
179 freerdp_context_free(instance);
182 IFCALL(pEntryPoints->GlobalUninit);
184 free(instance->pClientEntryPoints);
185 freerdp_free(instance);
189int freerdp_client_start(rdpContext* context)
191 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
193 if (!context || !context->instance || !context->instance->pClientEntryPoints)
194 return ERROR_BAD_ARGUMENTS;
197 set_default_callbacks(context->instance);
200 rdpClientContext* client_context = (rdpClientContext*)context;
201 client_context->mibClientWrapper = sso_mib_new(context);
202 if (!client_context->mibClientWrapper)
203 return ERROR_INTERNAL_ERROR;
206 pEntryPoints = context->instance->pClientEntryPoints;
207 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
210int freerdp_client_stop(rdpContext* context)
212 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
214 if (!context || !context->instance || !context->instance->pClientEntryPoints)
215 return ERROR_BAD_ARGUMENTS;
217 pEntryPoints = context->instance->pClientEntryPoints;
218 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
221 rdpClientContext* client_context = (rdpClientContext*)context;
222 sso_mib_free(client_context->mibClientWrapper);
223 client_context->mibClientWrapper =
nullptr;
228freerdp* freerdp_client_get_instance(rdpContext* context)
230 if (!context || !context->instance)
233 return context->instance;
236HANDLE freerdp_client_get_thread(rdpContext* context)
241 return ((rdpClientContext*)context)->thread;
244static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
269 settings, FreeRDP_GatewayPassword,
309int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
313 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown,
314 nullptr, 0,
nullptr,
nullptr);
317int freerdp_client_settings_parse_command_line_ex(
319 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
329 status = freerdp_client_settings_parse_command_line_arguments_ex(
330 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
337 if (!freerdp_client_settings_post_process(settings))
340 const char* name = argv[0];
341 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
342 freerdp_get_build_config());
346int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
348 rdpFile* file =
nullptr;
350 file = freerdp_client_rdp_file_new();
355 if (!freerdp_client_parse_rdp_file(file, filename))
358 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
363 freerdp_client_rdp_file_free(file);
367int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
370 rdpFile* file =
nullptr;
372 file = freerdp_client_rdp_file_new();
377 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
378 freerdp_client_populate_settings_from_rdp_file(file, settings))
383 freerdp_client_rdp_file_free(file);
387int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
390 rdpFile* file =
nullptr;
392 file = freerdp_client_rdp_file_new();
397 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
400 if (!freerdp_client_write_rdp_file(file, filename, unicode))
405 freerdp_client_rdp_file_free(file);
409int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
413 char* filename =
nullptr;
414 char* password =
nullptr;
415 rdpAssistanceFile* file =
nullptr;
417 if (!settings || !argv || (argc < 2))
422 for (
int x = 2; x < argc; x++)
424 const char* key = strstr(argv[x],
"assistance:");
427 password = strchr(key,
':') + 1;
430 file = freerdp_assistance_file_new();
435 status = freerdp_assistance_parse_file(file, filename, password);
440 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
445 freerdp_assistance_file_free(file);
449static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
452 WINPR_ASSERT(instance);
454 WINPR_ASSERT(result);
458 (void)fflush(stdout);
460 char* line =
nullptr;
461 if (suggestion && strlen(suggestion) > 0)
463 line = _strdup(suggestion);
464 size = strlen(suggestion);
467 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
470 char ebuffer[256] = WINPR_C_ARRAY_INIT;
471 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
472 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
482 line = StrSep(&line,
"\r");
483 line = StrSep(&line,
"\n");
504static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
505 char** password,
char** domain)
507 static const size_t password_size = 512;
508 const char* userAuth =
"Username: ";
509 const char* domainAuth =
"Domain: ";
510 const char* pwdAuth =
"Password: ";
511 BOOL pinOnly = FALSE;
512 BOOL queryAll = FALSE;
514 WINPR_ASSERT(instance);
515 WINPR_ASSERT(instance->context);
516 WINPR_ASSERT(instance->context->settings);
520 case AUTH_SMARTCARD_PIN:
521 pwdAuth =
"Smartcard-Pin: ";
534 userAuth =
"GatewayUsername: ";
535 domainAuth =
"GatewayDomain: ";
536 pwdAuth =
"GatewayPassword: ";
542 if (!username || !password || !domain)
547 const char* suggest = *username;
548 if (queryAll || !suggest)
550 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
558 const char* suggest = *domain;
559 if (queryAll || !suggest)
561 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
568 char* line = calloc(password_size,
sizeof(
char));
573 const BOOL fromStdin =
576 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
580 if (password_size > 0)
598BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
599 rdp_auth_reason reason)
601 WINPR_ASSERT(instance);
602 WINPR_ASSERT(username);
603 WINPR_ASSERT(password);
604 WINPR_ASSERT(domain);
614 case AUTH_SMARTCARD_PIN:
615 if ((*username) && (*password))
626 return client_cli_authenticate_raw(instance, reason, username, password, domain);
629BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
630 DWORD count, DWORD* choice, BOOL gateway)
632 unsigned long answer = 0;
635 printf(
"Multiple smartcards are available for use:\n");
636 for (DWORD i = 0; i < count; i++)
639 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
640 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
643 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
644 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
645 cert->issuer, cert->upn);
648 free(container_name);
653 char input[10] = WINPR_C_ARRAY_INIT;
655 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
656 gateway ?
"gateway authentication" :
"logon", count - 1);
657 (void)fflush(stdout);
658 if (!fgets(input, 10, stdin))
660 WLog_ERR(TAG,
"could not read from stdin");
664 answer = strtoul(input, &p, 10);
665 if ((*p ==
'\n' && p != input) && answer < count)
667 *choice = (UINT32)answer;
673#if defined(WITH_FREERDP_DEPRECATED)
674BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
678 WLog_INFO(TAG,
"Authentication via smartcard");
682 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
685BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
687 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
691static DWORD client_cli_accept_certificate(freerdp* instance)
695 WINPR_ASSERT(instance);
696 WINPR_ASSERT(instance->context);
698 const rdpSettings* settings = instance->context->settings;
699 WINPR_ASSERT(settings);
707 printf(
"Do you trust the above certificate? (Y/T/N) ");
708 (void)fflush(stdout);
709 answer = freerdp_interruptible_getc(instance->context, stdin);
711 if ((answer == EOF) || feof(stdin))
713 printf(
"\nError: Could not read answer from stdin.\n");
721 answer = freerdp_interruptible_getc(instance->context, stdin);
728 answer = freerdp_interruptible_getc(instance->context, stdin);
735 answer = freerdp_interruptible_getc(instance->context, stdin);
761#if defined(WITH_FREERDP_DEPRECATED)
762DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
763 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
765 WINPR_UNUSED(common_name);
766 WINPR_UNUSED(host_mismatch);
768 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
769 printf(
"Certificate details:\n");
770 printf(
"\tSubject: %s\n", subject);
771 printf(
"\tIssuer: %s\n", issuer);
772 printf(
"\tThumbprint: %s\n", fingerprint);
773 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
774 "the CA certificate in your certificate store, or the certificate has expired.\n"
775 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
776 return client_cli_accept_certificate(instance);
780static char* client_cli_pem_cert(
const char* pem)
782 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
786 char* fp = freerdp_certificate_get_fingerprint(cert);
787 char* start = freerdp_certificate_get_validity(cert, TRUE);
788 char* end = freerdp_certificate_get_validity(cert, FALSE);
789 freerdp_certificate_free(cert);
793 winpr_asprintf(&str, &slen,
796 "\tThumbprint: %s\n",
819DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
820 const char* common_name,
const char* subject,
821 const char* issuer,
const char* fingerprint, DWORD flags)
823 const char* type =
"RDP-Server";
825 WINPR_ASSERT(instance);
826 WINPR_ASSERT(instance->context);
827 WINPR_ASSERT(instance->context->settings);
829 if (flags & VERIFY_CERT_FLAG_GATEWAY)
830 type =
"RDP-Gateway";
832 if (flags & VERIFY_CERT_FLAG_REDIRECT)
833 type =
"RDP-Redirect";
835 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
836 printf(
"\tCommon Name: %s\n", common_name);
837 printf(
"\tSubject: %s\n", subject);
838 printf(
"\tIssuer: %s\n", issuer);
842 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
844 char* str = client_cli_pem_cert(fingerprint);
849 printf(
"\tThumbprint: %s\n", fingerprint);
851 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
852 "the CA certificate in your certificate store, or the certificate has expired.\n"
853 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
854 return client_cli_accept_certificate(instance);
872#if defined(WITH_FREERDP_DEPRECATED)
873DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
874 const char* subject,
const char* issuer,
875 const char* fingerprint,
const char* old_subject,
876 const char* old_issuer,
const char* old_fingerprint)
878 WINPR_UNUSED(common_name);
880 printf(
"WARNING: This callback is deprecated, migrate to "
881 "client_cli_verify_changed_certificate_ex\n");
882 printf(
"!!! Certificate has changed !!!\n");
884 printf(
"New Certificate details:\n");
885 printf(
"\tSubject: %s\n", subject);
886 printf(
"\tIssuer: %s\n", issuer);
887 printf(
"\tThumbprint: %s\n", fingerprint);
889 printf(
"Old Certificate details:\n");
890 printf(
"\tSubject: %s\n", old_subject);
891 printf(
"\tIssuer: %s\n", old_issuer);
892 printf(
"\tThumbprint: %s\n", old_fingerprint);
894 printf(
"The above X.509 certificate does not match the certificate used for previous "
896 "This may indicate that the certificate has been tampered with.\n"
897 "Please contact the administrator of the RDP server and clarify.\n");
898 return client_cli_accept_certificate(instance);
921DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
922 const char* common_name,
const char* subject,
923 const char* issuer,
const char* fingerprint,
924 const char* old_subject,
const char* old_issuer,
925 const char* old_fingerprint, DWORD flags)
927 const char* type =
"RDP-Server";
929 WINPR_ASSERT(instance);
930 WINPR_ASSERT(instance->context);
931 WINPR_ASSERT(instance->context->settings);
933 if (flags & VERIFY_CERT_FLAG_GATEWAY)
934 type =
"RDP-Gateway";
936 if (flags & VERIFY_CERT_FLAG_REDIRECT)
937 type =
"RDP-Redirect";
939 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
941 printf(
"New Certificate details:\n");
942 printf(
"\tCommon Name: %s\n", common_name);
943 printf(
"\tSubject: %s\n", subject);
944 printf(
"\tIssuer: %s\n", issuer);
948 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
950 char* str = client_cli_pem_cert(fingerprint);
955 printf(
"\tThumbprint: %s\n", fingerprint);
957 printf(
"Old Certificate details:\n");
958 printf(
"\tSubject: %s\n", old_subject);
959 printf(
"\tIssuer: %s\n", old_issuer);
963 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
965 char* str = client_cli_pem_cert(old_fingerprint);
970 printf(
"\tThumbprint: %s\n", old_fingerprint);
972 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
974 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
975 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
976 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
977 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
980 printf(
"The above X.509 certificate does not match the certificate used for previous "
982 "This may indicate that the certificate has been tampered with.\n"
983 "Please contact the administrator of the RDP server and clarify.\n");
984 return client_cli_accept_certificate(instance);
987BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
988 BOOL isConsentMandatory,
size_t length,
989 const WCHAR* message)
991 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
993 WINPR_ASSERT(instance);
994 WINPR_ASSERT(instance->context);
995 WINPR_ASSERT(instance->context->settings);
997 if (!isDisplayMandatory && !isConsentMandatory)
1000 printf(
"%s:\n", msgType);
1002 printf(
"%.*S\n", (
int)length, message);
1005 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR),
nullptr);
1008 printf(
"Failed to convert message!\n");
1011 printf(
"%s\n", msg);
1016 while (isConsentMandatory)
1018 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1019 (void)fflush(stdout);
1020 const int answer = freerdp_interruptible_getc(instance->context, stdin);
1022 if ((answer == EOF) || feof(stdin))
1024 printf(
"\nError: Could not read answer from stdin.\n");
1028 const int confirm = freerdp_interruptible_getc(instance->context, stdin);
1051static const char* extract_authorization_code(
char* url)
1055 for (
char* p = strchr(url,
'?'); p++ !=
nullptr; p = strchr(p,
'&'))
1057 if (strncmp(p,
"code=", 5) != 0)
1060 char* end =
nullptr;
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);
1081 char* url =
nullptr;
1082 char* token_request =
nullptr;
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 !=
nullptr);
1120static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1122 WINPR_ASSERT(instance);
1123 WINPR_ASSERT(instance->context);
1126 char* url =
nullptr;
1127 char* token_request =
nullptr;
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 !=
nullptr);
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
1201 va_list ap = WINPR_C_ARRAY_INIT;
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 =
nullptr;
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] = WINPR_C_ARRAY_INIT;
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,
nullptr);
1324BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1328 UINT32 numRetries = 0;
1329 rdpSettings* settings =
nullptr;
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 const UINT err = freerdp_get_last_error(instance->context);
1370 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1371 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1372 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1373 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1374 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1375 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1376 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1377 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1378 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1379 freerdp_get_last_error_name(err));
1381 case FREERDP_ERROR_CONNECT_CANCELLED:
1382 WLog_WARN(TAG,
"Connection aborted by user");
1392 if ((maxRetries > 0) && (numRetries >= maxRetries))
1394 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1399 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1401 const SSIZE_T delay =
1402 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1407 if (freerdp_reconnect(instance))
1410 switch (freerdp_get_last_error(instance->context))
1412 case FREERDP_ERROR_CONNECT_CANCELLED:
1413 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1418 for (SSIZE_T x = 0; x < delay / 10; x++)
1420 if (!IFCALLRESULT(TRUE, window_events, instance))
1422 WLog_ERR(TAG,
"window_events failed!");
1430 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1434int freerdp_client_common_stop(rdpContext* context)
1436 rdpClientContext* cctx = (rdpClientContext*)context;
1439 freerdp_abort_connect_context(&cctx->context);
1443 (void)WaitForSingleObject(cctx->thread, INFINITE);
1444 (void)CloseHandle(cctx->thread);
1445 cctx->thread =
nullptr;
1451#if defined(CHANNEL_ENCOMSP_CLIENT)
1452BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1454 rdpClientContext* cctx =
nullptr;
1460 cctx = (rdpClientContext*)encomsp->custom;
1462 state = cctx->controlToggle;
1463 cctx->controlToggle = !cctx->controlToggle;
1464 return freerdp_client_encomsp_set_control(encomsp, state);
1467BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1474 pdu.ParticipantId = encomsp->participantId;
1475 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1478 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1480 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1481 return rc == CHANNEL_RC_OK;
1485client_encomsp_participant_created(EncomspClientContext* context,
1488 rdpClientContext* cctx =
nullptr;
1489 rdpSettings* settings =
nullptr;
1492 if (!context || !context->custom || !participantCreated)
1493 return ERROR_INVALID_PARAMETER;
1495 cctx = (rdpClientContext*)context->custom;
1498 settings = cctx->context.settings;
1499 WINPR_ASSERT(settings);
1501 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1502 context->participantId = participantCreated->ParticipantId;
1505 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1506 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1508 if (!freerdp_client_encomsp_set_control(context, TRUE))
1509 return ERROR_INTERNAL_ERROR;
1515 return ERROR_INTERNAL_ERROR;
1518 return CHANNEL_RC_OK;
1521static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1523 cctx->encomsp = encomsp;
1524 encomsp->custom = (
void*)cctx;
1525 encomsp->ParticipantCreated = client_encomsp_participant_created;
1528static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1532 encomsp->custom =
nullptr;
1533 encomsp->ParticipantCreated =
nullptr;
1537 cctx->encomsp =
nullptr;
1541void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1542 const ChannelConnectedEventArgs* e)
1544 rdpClientContext* cctx = (rdpClientContext*)context;
1552#if defined(CHANNEL_AINPUT_CLIENT)
1553 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1554 cctx->ainput = (AInputClientContext*)e->pInterface;
1556#if defined(CHANNEL_RDPEI_CLIENT)
1557 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1559 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1562#if defined(CHANNEL_RDPGFX_CLIENT)
1563 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1565 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1568#if defined(CHANNEL_GEOMETRY_CLIENT)
1569 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1571 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1574#if defined(CHANNEL_VIDEO_CLIENT)
1575 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1577 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1579 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1581 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1584#if defined(CHANNEL_ENCOMSP_CLIENT)
1585 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1587 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1592void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1593 const ChannelDisconnectedEventArgs* e)
1595 rdpClientContext* cctx = (rdpClientContext*)context;
1603#if defined(CHANNEL_AINPUT_CLIENT)
1604 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1605 cctx->ainput =
nullptr;
1607#if defined(CHANNEL_RDPEI_CLIENT)
1608 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1610 cctx->rdpei =
nullptr;
1613#if defined(CHANNEL_RDPGFX_CLIENT)
1614 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1616 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1619#if defined(CHANNEL_GEOMETRY_CLIENT)
1620 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1622 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1625#if defined(CHANNEL_VIDEO_CLIENT)
1626 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1628 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1630 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1632 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1635#if defined(CHANNEL_ENCOMSP_CLIENT)
1636 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1638 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1643BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1645 BOOL handled = FALSE;
1649#if defined(CHANNEL_AINPUT_CLIENT)
1656 INT32 value = mflags & 0xFF;
1658 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1659 value = -1 * (0x100 - value);
1665 if (mflags & PTR_FLAGS_WHEEL)
1667 flags |= AINPUT_FLAGS_WHEEL;
1671 if (mflags & PTR_FLAGS_HWHEEL)
1673 flags |= AINPUT_FLAGS_WHEEL;
1677 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1678 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1679 if (rc == CHANNEL_RC_OK)
1685 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1690#if defined(CHANNEL_AINPUT_CLIENT)
1691static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1696 WINPR_ASSERT(cctx->ainput);
1697 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1699 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1701 return rc == CHANNEL_RC_OK;
1705static bool button_pressed(
const rdpClientContext* cctx)
1708 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1710 const BOOL cur = cctx->pressed_buttons[x];
1717BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1720 BOOL handled = FALSE;
1724 if (mflags & PTR_FLAGS_BUTTON1)
1725 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1726 if (mflags & PTR_FLAGS_BUTTON2)
1727 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1728 if (mflags & PTR_FLAGS_BUTTON3)
1729 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1731 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1734 if (!button_pressed(cctx))
1738 const BOOL haveRelative =
1740 if (relative && haveRelative)
1742 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1743 WINPR_ASSERTING_INT_CAST(int16_t, x),
1744 WINPR_ASSERTING_INT_CAST(int16_t, y));
1747#if defined(CHANNEL_AINPUT_CLIENT)
1752 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1753 flags |= AINPUT_FLAGS_HAVE_REL;
1756 flags |= AINPUT_FLAGS_REL;
1758 if (mflags & PTR_FLAGS_DOWN)
1759 flags |= AINPUT_FLAGS_DOWN;
1760 if (mflags & PTR_FLAGS_BUTTON1)
1761 flags |= AINPUT_FLAGS_BUTTON1;
1762 if (mflags & PTR_FLAGS_BUTTON2)
1763 flags |= AINPUT_FLAGS_BUTTON2;
1764 if (mflags & PTR_FLAGS_BUTTON3)
1765 flags |= AINPUT_FLAGS_BUTTON3;
1766 if (mflags & PTR_FLAGS_MOVE)
1767 flags |= AINPUT_FLAGS_MOVE;
1768 handled = ainput_send_diff_event(cctx, flags, x, y);
1778 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1785 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1786 (UINT16)cctx->lastY);
1791BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1794 BOOL handled = FALSE;
1797 if (mflags & PTR_XFLAGS_BUTTON1)
1798 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1799 if (mflags & PTR_XFLAGS_BUTTON2)
1800 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1802 const BOOL haveRelative =
1804 if (relative && haveRelative)
1806 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1807 WINPR_ASSERTING_INT_CAST(int16_t, x),
1808 WINPR_ASSERTING_INT_CAST(int16_t, y));
1811#if defined(CHANNEL_AINPUT_CLIENT)
1817 flags |= AINPUT_FLAGS_REL;
1818 if (mflags & PTR_XFLAGS_DOWN)
1819 flags |= AINPUT_FLAGS_DOWN;
1820 if (mflags & PTR_XFLAGS_BUTTON1)
1821 flags |= AINPUT_XFLAGS_BUTTON1;
1822 if (mflags & PTR_XFLAGS_BUTTON2)
1823 flags |= AINPUT_XFLAGS_BUTTON2;
1825 handled = ainput_send_diff_event(cctx, flags, x, y);
1835 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1842 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1843 (UINT16)cctx->lastY);
1849static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
1852 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
1853 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
1854 WINPR_ASSERT(contact);
1855 WINPR_ASSERT(contact->x <= UINT16_MAX);
1856 WINPR_ASSERT(contact->y <= UINT16_MAX);
1858 switch (contact->count)
1861 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
1862 contact->x, contact->y);
1864 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
1865 contact->x, contact->y);
1867 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
1868 contact->x, contact->y);
1870 return freerdp_client_send_extended_button_event(
1871 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1873 return freerdp_client_send_extended_button_event(
1874 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1881static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1884 WINPR_ASSERT(contact);
1886#if defined(CHANNEL_RDPEI_CLIENT)
1887 RdpeiClientContext* rdpei = cctx->rdpei;
1890 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1894 if (rdpei->TouchRawEvent)
1896 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1897 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1898 ? CONTACT_DATA_PRESSURE_PRESENT
1902 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1903 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1904 RDPINPUT_CONTACT_FLAG_INCONTACT,
1905 contactFlags, contact->pressure);
1906 if (rc1 != CHANNEL_RC_OK)
1909 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
1910 &contactId, flags, contactFlags, contact->pressure);
1911 if (rc2 != CHANNEL_RC_OK)
1916 WINPR_ASSERT(rdpei->TouchEnd);
1917 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1918 if (rc != CHANNEL_RC_OK)
1923 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1924 "-DCHANNEL_RDPEI_CLIENT=ON");
1925 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1929static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1932 WINPR_ASSERT(contact);
1934#if defined(CHANNEL_RDPEI_CLIENT)
1935 RdpeiClientContext* rdpei = cctx->rdpei;
1939 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1943 if (rdpei->TouchRawEvent)
1945 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1946 RDPINPUT_CONTACT_FLAG_INCONTACT;
1947 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1948 ? CONTACT_DATA_PRESSURE_PRESENT
1950 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1951 flags, contactFlags, contact->pressure);
1952 if (rc != CHANNEL_RC_OK)
1957 WINPR_ASSERT(rdpei->TouchBegin);
1958 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1959 if (rc != CHANNEL_RC_OK)
1965 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1966 "-DCHANNEL_RDPEI_CLIENT=ON");
1967 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1971static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
1974 const UINT16 flags = PTR_FLAGS_MOVE;
1976 WINPR_ASSERT(contact);
1977 WINPR_ASSERT(contact->x <= UINT16_MAX);
1978 WINPR_ASSERT(contact->y <= UINT16_MAX);
1979 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1982static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1985 WINPR_ASSERT(contact);
1987#if defined(CHANNEL_RDPEI_CLIENT)
1988 RdpeiClientContext* rdpei = cctx->rdpei;
1991 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
1995 if (rdpei->TouchRawEvent)
1997 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1998 RDPINPUT_CONTACT_FLAG_INCONTACT;
1999 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2000 ? CONTACT_DATA_PRESSURE_PRESENT
2002 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2003 flags, contactFlags, contact->pressure);
2004 if (rc != CHANNEL_RC_OK)
2009 WINPR_ASSERT(rdpei->TouchUpdate);
2010 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2011 if (rc != CHANNEL_RC_OK)
2017 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2018 "-DCHANNEL_RDPEI_CLIENT=ON");
2019 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2023static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2026 WINPR_ASSERT(contact);
2028#if defined(CHANNEL_RDPEI_CLIENT)
2029 RdpeiClientContext* rdpei = cctx->rdpei;
2032 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2036 if (rdpei->TouchRawEvent)
2038 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2039 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2040 ? CONTACT_DATA_PRESSURE_PRESENT
2042 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2043 flags, contactFlags, contact->pressure);
2044 if (rc != CHANNEL_RC_OK)
2049 WINPR_ASSERT(rdpei->TouchUpdate);
2050 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2051 if (rc != CHANNEL_RC_OK)
2057 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2058 "-DCHANNEL_RDPEI_CLIENT=ON");
2059 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2063static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2064 UINT32 pressure, INT32 x, INT32 y,
2068 WINPR_ASSERT(pcontact);
2070 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2074 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2075 if (newcontact || (contact->id == touchId))
2077 contact->id = touchId;
2078 contact->flags = flags;
2079 contact->pressure = pressure;
2083 *pcontact = *contact;
2085 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2098BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2099 UINT32 pressure, INT32 x, INT32 y)
2102 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2107 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2110 switch (flags & mask)
2112 case FREERDP_TOUCH_DOWN:
2113 return freerdp_handle_touch_down(cctx, &contact);
2114 case FREERDP_TOUCH_UP:
2115 return freerdp_handle_touch_up(cctx, &contact);
2116 case FREERDP_TOUCH_MOTION:
2117 return freerdp_handle_touch_motion(cctx, &contact);
2118 case FREERDP_TOUCH_CANCEL:
2119 return freerdp_handle_touch_cancel(cctx, &contact);
2121 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2126BOOL freerdp_client_load_channels(freerdp* instance)
2128 WINPR_ASSERT(instance);
2129 WINPR_ASSERT(instance->context);
2131 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2133 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2139int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2141 const char* str_data = freerdp_get_logon_error_info_data(data);
2142 const char* str_type = freerdp_get_logon_error_info_type(type);
2144 if (!instance || !instance->context)
2147 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2151static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2156 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2159 if (deviceid == pen->deviceid)
2169static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2172 static const INT32 null_deviceid = 0;
2175 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2176 if (freerdp_client_is_pen(cctx, deviceid))
2178 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2189 pen->deviceid = deviceid;
2190 pen->max_pressure = pressure;
2193 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2197 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2201BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2203#if defined(CHANNEL_RDPEI_CLIENT)
2204 if ((flags & FREERDP_PEN_REGISTER) != 0)
2206 va_list args = WINPR_C_ARRAY_INIT;
2208 va_start(args, deviceid);
2209 double pressure = va_arg(args,
double);
2211 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2217 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2221 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2223 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2225 RdpeiClientContext* rdpei = cctx->rdpei;
2226 WINPR_ASSERT(rdpei);
2228 UINT32 normalizedpressure = 1024;
2231 UINT16 rotation = 0;
2234 va_list args = WINPR_C_ARRAY_INIT;
2235 va_start(args, deviceid);
2237 x = va_arg(args, INT32);
2238 y = va_arg(args, INT32);
2239 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2241 const double pressure = va_arg(args,
double);
2242 const double np = (pressure * 1024.0) / pen->max_pressure;
2243 normalizedpressure = (UINT32)lround(np);
2244 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2245 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2247 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2249 const unsigned arg = va_arg(args,
unsigned);
2250 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2251 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2253 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2255 const int arg = va_arg(args,
int);
2256 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2257 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2259 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2261 const int arg = va_arg(args,
int);
2262 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2263 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2267 if ((flags & FREERDP_PEN_PRESS) != 0)
2271 flags = FREERDP_PEN_MOTION |
2272 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2273 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2274 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2276 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2278 if (!pen->pressed ||
2279 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2280 flags = FREERDP_PEN_MOTION |
2281 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2283 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2286 flags |= pen->flags;
2287 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2288 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2289 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2290 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2294 if ((flags & FREERDP_PEN_PRESS) != 0)
2296 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2297 pen->hovering = FALSE;
2298 pen->pressed = TRUE;
2300 WINPR_ASSERT(rdpei->PenBegin);
2301 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2302 normalizedpressure, rotation, tiltX, tiltY);
2303 return rc == CHANNEL_RC_OK;
2305 else if ((flags & FREERDP_PEN_MOTION) != 0)
2307 UINT rc = ERROR_INTERNAL_ERROR;
2310 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2313 WINPR_ASSERT(rdpei->PenUpdate);
2314 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2315 rotation, tiltX, tiltY);
2317 else if (pen->hovering)
2319 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2321 WINPR_ASSERT(rdpei->PenHoverUpdate);
2322 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2323 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2327 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2328 pen->hovering = TRUE;
2330 WINPR_ASSERT(rdpei->PenHoverBegin);
2331 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2332 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2334 return rc == CHANNEL_RC_OK;
2336 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2338 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2339 pen->pressed = FALSE;
2340 pen->hovering = TRUE;
2342 WINPR_ASSERT(rdpei->PenUpdate);
2343 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2344 normalizedpressure, rotation, tiltX, tiltY);
2345 if (rc != CHANNEL_RC_OK)
2347 WINPR_ASSERT(rdpei->PenEnd);
2348 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2349 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2350 return re == CHANNEL_RC_OK;
2353 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2355 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2356 "-DCHANNEL_RDPEI_CLIENT=ON");
2362BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2366#if defined(CHANNEL_RDPEI_CLIENT)
2367 RdpeiClientContext* rdpei = cctx->rdpei;
2372 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2377 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2378 pen->hovering = FALSE;
2380 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2381 if (rc != CHANNEL_RC_OK)
2387 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2388 "-DCHANNEL_RDPEI_CLIENT=ON");
2393BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2400 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2403 if (pen->deviceid == deviceid)
2410BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2414 const rdpSettings* settings = cctx->context.settings;
2417 BOOL ainput = FALSE;
2418#if defined(CHANNEL_AINPUT_CLIENT)
2419 ainput = cctx->ainput !=
nullptr;
2422 return useRelative && (haveRelative || ainput);
2425#if defined(WITH_AAD)
2426WINPR_ATTR_MALLOC(free, 1)
2428static
char* get_redirect_uri(const rdpSettings* settings)
2430 char* redirect_uri =
nullptr;
2434 const char* redirect_fmt =
2437 const char* tenantid =
"common";
2441 if (tenantid && redirect_fmt)
2446 size_t redirect_len = 0;
2447 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2453 const char* redirect_fmt =
2456 size_t redirect_len = 0;
2457 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2459 return redirect_uri;
2462static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2464 const rdpSettings* settings = cctx->context.settings;
2466 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2467 AAD_WELLKNOWN_authorization_endpoint);
2470 if (!client_id || !ep || !scope)
2473 char* redirect_uri = get_redirect_uri(settings);
2477 char* url =
nullptr;
2479 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2480 client_id, scope, redirect_uri);
2485static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2487 const rdpSettings* settings = cctx->context.settings;
2489 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2490 AAD_WELLKNOWN_authorization_endpoint);
2493 if (!client_id || !ep || !scope)
2496 char* redirect_uri = get_redirect_uri(settings);
2500 char* url =
nullptr;
2503 const char* code = va_arg(ap,
const char*);
2504 winpr_asprintf(&url, &urllen,
2505 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2506 code, client_id, scope, redirect_uri);
2511static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2513 const rdpSettings* settings = cctx->context.settings;
2514 char* url =
nullptr;
2516 char* redirect_uri = get_redirect_uri(settings);
2519 if (!client_id || !redirect_uri)
2523 const char* scope = va_arg(ap,
const char*);
2528 const char* ep = freerdp_utils_aad_get_wellknown_string(
2529 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2530 winpr_asprintf(&url, &urllen,
2531 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2532 client_id, scope, redirect_uri);
2541static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2543 const rdpSettings* settings = cctx->context.settings;
2545 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2546 AAD_WELLKNOWN_authorization_endpoint);
2547 const char* scope = va_arg(ap,
const char*);
2548 const char* code = va_arg(ap,
const char*);
2549 const char* req_cnf = va_arg(ap,
const char*);
2551 if (!client_id || !ep || !scope || !code || !req_cnf)
2554 char* redirect_uri = get_redirect_uri(settings);
2558 char* url =
nullptr;
2563 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2564 code, client_id, scope, redirect_uri, req_cnf);
2570char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2573 char* str =
nullptr;
2575 va_list ap = WINPR_C_ARRAY_INIT;
2579#if defined(WITH_AAD)
2580 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2581 str = aad_auth_request(cctx, ap);
2583 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2584 str = aad_token_request(cctx, ap);
2586 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2587 str = avd_auth_request(cctx, ap);
2589 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2590 str = avd_token_request(cctx, ap);
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 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_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.