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 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1650 if (state != CONNECTION_STATE_ACTIVE)
1653#if defined(CHANNEL_AINPUT_CLIENT)
1660 INT32 value = mflags & 0xFF;
1662 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1663 value = -1 * (0x100 - value);
1669 if (mflags & PTR_FLAGS_WHEEL)
1671 flags |= AINPUT_FLAGS_WHEEL;
1675 if (mflags & PTR_FLAGS_HWHEEL)
1677 flags |= AINPUT_FLAGS_WHEEL;
1681 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1682 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1683 if (rc == CHANNEL_RC_OK)
1689 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1694#if defined(CHANNEL_AINPUT_CLIENT)
1695static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1700 WINPR_ASSERT(cctx->ainput);
1701 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1703 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1705 return rc == CHANNEL_RC_OK;
1709static bool button_pressed(
const rdpClientContext* cctx)
1712 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1714 const BOOL cur = cctx->pressed_buttons[x];
1721BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1724 BOOL handled = FALSE;
1727 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1728 if (state != CONNECTION_STATE_ACTIVE)
1731 if (mflags & PTR_FLAGS_BUTTON1)
1732 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1733 if (mflags & PTR_FLAGS_BUTTON2)
1734 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1735 if (mflags & PTR_FLAGS_BUTTON3)
1736 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1738 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1741 if (!button_pressed(cctx))
1745 const BOOL haveRelative =
1747 if (relative && haveRelative)
1749 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1750 WINPR_ASSERTING_INT_CAST(int16_t, x),
1751 WINPR_ASSERTING_INT_CAST(int16_t, y));
1754#if defined(CHANNEL_AINPUT_CLIENT)
1759 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1760 flags |= AINPUT_FLAGS_HAVE_REL;
1763 flags |= AINPUT_FLAGS_REL;
1765 if (mflags & PTR_FLAGS_DOWN)
1766 flags |= AINPUT_FLAGS_DOWN;
1767 if (mflags & PTR_FLAGS_BUTTON1)
1768 flags |= AINPUT_FLAGS_BUTTON1;
1769 if (mflags & PTR_FLAGS_BUTTON2)
1770 flags |= AINPUT_FLAGS_BUTTON2;
1771 if (mflags & PTR_FLAGS_BUTTON3)
1772 flags |= AINPUT_FLAGS_BUTTON3;
1773 if (mflags & PTR_FLAGS_MOVE)
1774 flags |= AINPUT_FLAGS_MOVE;
1775 handled = ainput_send_diff_event(cctx, flags, x, y);
1785 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1792 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1793 (UINT16)cctx->lastY);
1798BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1801 BOOL handled = FALSE;
1804 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1805 if (state != CONNECTION_STATE_ACTIVE)
1808 if (mflags & PTR_XFLAGS_BUTTON1)
1809 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1810 if (mflags & PTR_XFLAGS_BUTTON2)
1811 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1813 const BOOL haveRelative =
1815 if (relative && haveRelative)
1817 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1818 WINPR_ASSERTING_INT_CAST(int16_t, x),
1819 WINPR_ASSERTING_INT_CAST(int16_t, y));
1822#if defined(CHANNEL_AINPUT_CLIENT)
1828 flags |= AINPUT_FLAGS_REL;
1829 if (mflags & PTR_XFLAGS_DOWN)
1830 flags |= AINPUT_FLAGS_DOWN;
1831 if (mflags & PTR_XFLAGS_BUTTON1)
1832 flags |= AINPUT_XFLAGS_BUTTON1;
1833 if (mflags & PTR_XFLAGS_BUTTON2)
1834 flags |= AINPUT_XFLAGS_BUTTON2;
1836 handled = ainput_send_diff_event(cctx, flags, x, y);
1846 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1853 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1854 (UINT16)cctx->lastY);
1860static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
1863 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
1864 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
1865 WINPR_ASSERT(contact);
1866 WINPR_ASSERT(contact->x <= UINT16_MAX);
1867 WINPR_ASSERT(contact->y <= UINT16_MAX);
1869 switch (contact->count)
1872 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
1873 contact->x, contact->y);
1875 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
1876 contact->x, contact->y);
1878 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
1879 contact->x, contact->y);
1881 return freerdp_client_send_extended_button_event(
1882 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1884 return freerdp_client_send_extended_button_event(
1885 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1892static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1895 WINPR_ASSERT(contact);
1897#if defined(CHANNEL_RDPEI_CLIENT)
1898 RdpeiClientContext* rdpei = cctx->rdpei;
1901 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1905 if (rdpei->TouchRawEvent)
1907 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1908 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1909 ? CONTACT_DATA_PRESSURE_PRESENT
1913 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1914 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1915 RDPINPUT_CONTACT_FLAG_INCONTACT,
1916 contactFlags, contact->pressure);
1917 if (rc1 != CHANNEL_RC_OK)
1920 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
1921 &contactId, flags, contactFlags, contact->pressure);
1922 if (rc2 != CHANNEL_RC_OK)
1927 WINPR_ASSERT(rdpei->TouchEnd);
1928 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1929 if (rc != CHANNEL_RC_OK)
1934 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1935 "-DCHANNEL_RDPEI_CLIENT=ON");
1936 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1940static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1943 WINPR_ASSERT(contact);
1945#if defined(CHANNEL_RDPEI_CLIENT)
1946 RdpeiClientContext* rdpei = cctx->rdpei;
1950 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1954 if (rdpei->TouchRawEvent)
1956 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1957 RDPINPUT_CONTACT_FLAG_INCONTACT;
1958 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1959 ? CONTACT_DATA_PRESSURE_PRESENT
1961 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1962 flags, contactFlags, contact->pressure);
1963 if (rc != CHANNEL_RC_OK)
1968 WINPR_ASSERT(rdpei->TouchBegin);
1969 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1970 if (rc != CHANNEL_RC_OK)
1976 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1977 "-DCHANNEL_RDPEI_CLIENT=ON");
1978 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1982static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
1985 const UINT16 flags = PTR_FLAGS_MOVE;
1987 WINPR_ASSERT(contact);
1988 WINPR_ASSERT(contact->x <= UINT16_MAX);
1989 WINPR_ASSERT(contact->y <= UINT16_MAX);
1990 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1993static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1996 WINPR_ASSERT(contact);
1998#if defined(CHANNEL_RDPEI_CLIENT)
1999 RdpeiClientContext* rdpei = cctx->rdpei;
2002 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2006 if (rdpei->TouchRawEvent)
2008 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2009 RDPINPUT_CONTACT_FLAG_INCONTACT;
2010 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2011 ? CONTACT_DATA_PRESSURE_PRESENT
2013 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2014 flags, contactFlags, contact->pressure);
2015 if (rc != CHANNEL_RC_OK)
2020 WINPR_ASSERT(rdpei->TouchUpdate);
2021 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2022 if (rc != CHANNEL_RC_OK)
2028 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2029 "-DCHANNEL_RDPEI_CLIENT=ON");
2030 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2034static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2037 WINPR_ASSERT(contact);
2039#if defined(CHANNEL_RDPEI_CLIENT)
2040 RdpeiClientContext* rdpei = cctx->rdpei;
2043 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2047 if (rdpei->TouchRawEvent)
2049 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2050 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2051 ? CONTACT_DATA_PRESSURE_PRESENT
2053 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2054 flags, contactFlags, contact->pressure);
2055 if (rc != CHANNEL_RC_OK)
2060 WINPR_ASSERT(rdpei->TouchUpdate);
2061 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2062 if (rc != CHANNEL_RC_OK)
2068 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2069 "-DCHANNEL_RDPEI_CLIENT=ON");
2070 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2074static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2075 UINT32 pressure, INT32 x, INT32 y,
2079 WINPR_ASSERT(pcontact);
2081 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2085 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2086 if (newcontact || (contact->id == touchId))
2088 contact->id = touchId;
2089 contact->flags = flags;
2090 contact->pressure = pressure;
2094 *pcontact = *contact;
2096 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2109BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2110 UINT32 pressure, INT32 x, INT32 y)
2113 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2116 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2117 if (state != CONNECTION_STATE_ACTIVE)
2122 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2125 switch (flags & mask)
2127 case FREERDP_TOUCH_DOWN:
2128 return freerdp_handle_touch_down(cctx, &contact);
2129 case FREERDP_TOUCH_UP:
2130 return freerdp_handle_touch_up(cctx, &contact);
2131 case FREERDP_TOUCH_MOTION:
2132 return freerdp_handle_touch_motion(cctx, &contact);
2133 case FREERDP_TOUCH_CANCEL:
2134 return freerdp_handle_touch_cancel(cctx, &contact);
2136 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2141BOOL freerdp_client_load_channels(freerdp* instance)
2143 WINPR_ASSERT(instance);
2144 WINPR_ASSERT(instance->context);
2146 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2148 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2154int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2156 const char* str_data = freerdp_get_logon_error_info_data(data);
2157 const char* str_type = freerdp_get_logon_error_info_type(type);
2159 if (!instance || !instance->context)
2162 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2166static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2171 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2174 if (deviceid == pen->deviceid)
2184static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2187 static const INT32 null_deviceid = 0;
2190 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2191 if (freerdp_client_is_pen(cctx, deviceid))
2193 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2204 pen->deviceid = deviceid;
2205 pen->max_pressure = pressure;
2208 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2212 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2216BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2218 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2219 if (state != CONNECTION_STATE_ACTIVE)
2222#if defined(CHANNEL_RDPEI_CLIENT)
2223 if ((flags & FREERDP_PEN_REGISTER) != 0)
2225 va_list args = WINPR_C_ARRAY_INIT;
2227 va_start(args, deviceid);
2228 double pressure = va_arg(args,
double);
2230 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2236 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2240 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2242 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2244 RdpeiClientContext* rdpei = cctx->rdpei;
2245 WINPR_ASSERT(rdpei);
2247 UINT32 normalizedpressure = 1024;
2250 UINT16 rotation = 0;
2253 va_list args = WINPR_C_ARRAY_INIT;
2254 va_start(args, deviceid);
2256 x = va_arg(args, INT32);
2257 y = va_arg(args, INT32);
2258 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2260 const double pressure = va_arg(args,
double);
2261 const double np = (pressure * 1024.0) / pen->max_pressure;
2262 normalizedpressure = (UINT32)lround(np);
2263 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2264 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2266 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2268 const unsigned arg = va_arg(args,
unsigned);
2269 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2270 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2272 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2274 const int arg = va_arg(args,
int);
2275 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2276 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2278 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2280 const int arg = va_arg(args,
int);
2281 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2282 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2286 if ((flags & FREERDP_PEN_PRESS) != 0)
2290 flags = FREERDP_PEN_MOTION |
2291 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2292 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2293 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2295 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2297 if (!pen->pressed ||
2298 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2299 flags = FREERDP_PEN_MOTION |
2300 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2302 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2305 flags |= pen->flags;
2306 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2307 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2308 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2309 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2313 if ((flags & FREERDP_PEN_PRESS) != 0)
2315 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2316 pen->hovering = FALSE;
2317 pen->pressed = TRUE;
2319 WINPR_ASSERT(rdpei->PenBegin);
2320 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2321 normalizedpressure, rotation, tiltX, tiltY);
2322 return rc == CHANNEL_RC_OK;
2324 else if ((flags & FREERDP_PEN_MOTION) != 0)
2326 UINT rc = ERROR_INTERNAL_ERROR;
2329 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2332 WINPR_ASSERT(rdpei->PenUpdate);
2333 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2334 rotation, tiltX, tiltY);
2336 else if (pen->hovering)
2338 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2340 WINPR_ASSERT(rdpei->PenHoverUpdate);
2341 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2342 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2346 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2347 pen->hovering = TRUE;
2349 WINPR_ASSERT(rdpei->PenHoverBegin);
2350 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2351 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2353 return rc == CHANNEL_RC_OK;
2355 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2357 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2358 pen->pressed = FALSE;
2359 pen->hovering = TRUE;
2361 WINPR_ASSERT(rdpei->PenUpdate);
2362 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2363 normalizedpressure, rotation, tiltX, tiltY);
2364 if (rc != CHANNEL_RC_OK)
2366 WINPR_ASSERT(rdpei->PenEnd);
2367 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2368 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2369 return re == CHANNEL_RC_OK;
2372 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2374 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2375 "-DCHANNEL_RDPEI_CLIENT=ON");
2381BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2385 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2386 if (state != CONNECTION_STATE_ACTIVE)
2389#if defined(CHANNEL_RDPEI_CLIENT)
2390 RdpeiClientContext* rdpei = cctx->rdpei;
2395 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2400 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2401 pen->hovering = FALSE;
2403 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2404 if (rc != CHANNEL_RC_OK)
2410 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2411 "-DCHANNEL_RDPEI_CLIENT=ON");
2416BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2423 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2426 if (pen->deviceid == deviceid)
2433BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2437 const rdpSettings* settings = cctx->context.settings;
2440 BOOL ainput = FALSE;
2441#if defined(CHANNEL_AINPUT_CLIENT)
2442 ainput = cctx->ainput !=
nullptr;
2445 return useRelative && (haveRelative || ainput);
2448#if defined(WITH_AAD)
2449WINPR_ATTR_MALLOC(free, 1)
2451static
char* get_redirect_uri(const rdpSettings* settings)
2453 char* redirect_uri =
nullptr;
2457 const char* redirect_fmt =
2460 const char* tenantid =
"common";
2464 if (tenantid && redirect_fmt)
2469 size_t redirect_len = 0;
2470 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2476 const char* redirect_fmt =
2479 size_t redirect_len = 0;
2480 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2482 return redirect_uri;
2485static char* avd_auth_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;
2502 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2503 client_id, scope, redirect_uri);
2508static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2510 const rdpSettings* settings = cctx->context.settings;
2512 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2513 AAD_WELLKNOWN_authorization_endpoint);
2516 if (!client_id || !ep || !scope)
2519 char* redirect_uri = get_redirect_uri(settings);
2523 char* url =
nullptr;
2526 const char* code = va_arg(ap,
const char*);
2527 winpr_asprintf(&url, &urllen,
2528 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2529 code, client_id, scope, redirect_uri);
2534static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2536 const rdpSettings* settings = cctx->context.settings;
2537 char* url =
nullptr;
2539 char* redirect_uri = get_redirect_uri(settings);
2542 if (!client_id || !redirect_uri)
2546 const char* scope = va_arg(ap,
const char*);
2551 const char* ep = freerdp_utils_aad_get_wellknown_string(
2552 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2553 winpr_asprintf(&url, &urllen,
2554 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2555 client_id, scope, redirect_uri);
2564static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2566 const rdpSettings* settings = cctx->context.settings;
2568 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2569 AAD_WELLKNOWN_authorization_endpoint);
2570 const char* scope = va_arg(ap,
const char*);
2571 const char* code = va_arg(ap,
const char*);
2572 const char* req_cnf = va_arg(ap,
const char*);
2574 if (!client_id || !ep || !scope || !code || !req_cnf)
2577 char* redirect_uri = get_redirect_uri(settings);
2581 char* url =
nullptr;
2586 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2587 code, client_id, scope, redirect_uri, req_cnf);
2593char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2596 char* str =
nullptr;
2598 va_list ap = WINPR_C_ARRAY_INIT;
2602#if defined(WITH_AAD)
2603 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2604 str = aad_auth_request(cctx, ap);
2606 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2607 str = aad_token_request(cctx, ap);
2609 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2610 str = avd_auth_request(cctx, ap);
2612 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2613 str = avd_token_request(cctx, ap);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.