21#include <winpr/cast.h>
23#include <freerdp/config.h>
31#include <freerdp/client.h>
33#include <freerdp/freerdp.h>
34#include <freerdp/addin.h>
35#include <freerdp/assistance.h>
36#include <freerdp/client/file.h>
37#include <freerdp/utils/passphrase.h>
38#include <freerdp/client/cmdline.h>
39#include <freerdp/client/channels.h>
40#include <freerdp/utils/smartcardlogon.h>
42#if defined(CHANNEL_AINPUT_CLIENT)
43#include <freerdp/client/ainput.h>
44#include <freerdp/channels/ainput.h>
47#if defined(CHANNEL_VIDEO_CLIENT)
48#include <freerdp/client/video.h>
49#include <freerdp/channels/video.h>
52#if defined(CHANNEL_RDPGFX_CLIENT)
53#include <freerdp/client/rdpgfx.h>
54#include <freerdp/channels/rdpgfx.h>
55#include <freerdp/gdi/gfx.h>
58#if defined(CHANNEL_GEOMETRY_CLIENT)
59#include <freerdp/client/geometry.h>
60#include <freerdp/channels/geometry.h>
63#if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
64#include <freerdp/gdi/video.h>
68#include <freerdp/utils/http.h>
69#include <freerdp/utils/aad.h>
73#include "sso_mib_tokens.h"
76#include <freerdp/log.h>
77#define TAG CLIENT_TAG("common")
79static void set_default_callbacks(freerdp* instance)
81 WINPR_ASSERT(instance);
82 instance->AuthenticateEx = client_cli_authenticate_ex;
83 instance->ChooseSmartcard = client_cli_choose_smartcard;
84 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
85 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
86 instance->PresentGatewayMessage = client_cli_present_gateway_message;
87 instance->LogonErrorInfo = client_cli_logon_error_info;
88 instance->GetAccessToken = client_cli_get_access_token;
89 instance->RetryDialog = client_common_retry_dialog;
92static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
94 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
96 WINPR_ASSERT(instance);
97 WINPR_ASSERT(context);
99 instance->LoadChannels = freerdp_client_load_channels;
100 set_default_callbacks(instance);
102 pEntryPoints = instance->pClientEntryPoints;
103 WINPR_ASSERT(pEntryPoints);
104 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
107static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
109 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
111 WINPR_ASSERT(instance);
112 WINPR_ASSERT(context);
114 pEntryPoints = instance->pClientEntryPoints;
115 WINPR_ASSERT(pEntryPoints);
116 IFCALL(pEntryPoints->ClientFree, instance, context);
121rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
123 freerdp* instance = NULL;
124 rdpContext* context = NULL;
129 IFCALL(pEntryPoints->GlobalInit);
130 instance = freerdp_new();
135 instance->ContextSize = pEntryPoints->ContextSize;
136 instance->ContextNew = freerdp_client_common_new;
137 instance->ContextFree = freerdp_client_common_free;
138 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
140 if (!instance->pClientEntryPoints)
143 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
145 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
148 context = instance->context;
149 context->instance = instance;
151#if defined(WITH_CLIENT_CHANNELS)
152 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
159 free(instance->pClientEntryPoints);
161 freerdp_free(instance);
165void freerdp_client_context_free(rdpContext* context)
167 freerdp* instance = NULL;
172 instance = context->instance;
176 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
177 freerdp_context_free(instance);
180 IFCALL(pEntryPoints->GlobalUninit);
182 free(instance->pClientEntryPoints);
183 freerdp_free(instance);
187int freerdp_client_start(rdpContext* context)
189 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
191 if (!context || !context->instance || !context->instance->pClientEntryPoints)
192 return ERROR_BAD_ARGUMENTS;
195 set_default_callbacks(context->instance);
198 rdpClientContext* client_context = (rdpClientContext*)context;
199 client_context->mibClientWrapper = sso_mib_new(context);
200 if (!client_context->mibClientWrapper)
201 return ERROR_INTERNAL_ERROR;
204 pEntryPoints = context->instance->pClientEntryPoints;
205 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
208int freerdp_client_stop(rdpContext* context)
210 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
212 if (!context || !context->instance || !context->instance->pClientEntryPoints)
213 return ERROR_BAD_ARGUMENTS;
215 pEntryPoints = context->instance->pClientEntryPoints;
216 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
219 rdpClientContext* client_context = (rdpClientContext*)context;
220 sso_mib_free(client_context->mibClientWrapper);
221 client_context->mibClientWrapper = NULL;
226freerdp* freerdp_client_get_instance(rdpContext* context)
228 if (!context || !context->instance)
231 return context->instance;
234HANDLE freerdp_client_get_thread(rdpContext* context)
239 return ((rdpClientContext*)context)->thread;
242static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
267 settings, FreeRDP_GatewayPassword,
307int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
311 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown, NULL,
315int freerdp_client_settings_parse_command_line_ex(
317 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
327 status = freerdp_client_settings_parse_command_line_arguments_ex(
328 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
335 if (!freerdp_client_settings_post_process(settings))
338 const char* name = argv[0];
339 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
340 freerdp_get_build_config());
344int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
346 rdpFile* file = NULL;
348 file = freerdp_client_rdp_file_new();
353 if (!freerdp_client_parse_rdp_file(file, filename))
356 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
361 freerdp_client_rdp_file_free(file);
365int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
368 rdpFile* file = NULL;
370 file = freerdp_client_rdp_file_new();
375 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
376 freerdp_client_populate_settings_from_rdp_file(file, settings))
381 freerdp_client_rdp_file_free(file);
385int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
388 rdpFile* file = NULL;
390 file = freerdp_client_rdp_file_new();
395 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
398 if (!freerdp_client_write_rdp_file(file, filename, unicode))
403 freerdp_client_rdp_file_free(file);
407int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
411 char* filename = NULL;
412 char* password = NULL;
413 rdpAssistanceFile* file = NULL;
415 if (!settings || !argv || (argc < 2))
420 for (
int x = 2; x < argc; x++)
422 const char* key = strstr(argv[x],
"assistance:");
425 password = strchr(key,
':') + 1;
428 file = freerdp_assistance_file_new();
433 status = freerdp_assistance_parse_file(file, filename, password);
438 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
443 freerdp_assistance_file_free(file);
447static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
450 WINPR_ASSERT(instance);
452 WINPR_ASSERT(result);
456 (void)fflush(stdout);
459 if (suggestion && strlen(suggestion) > 0)
461 line = _strdup(suggestion);
462 size = strlen(suggestion);
465 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
468 char ebuffer[256] = { 0 };
469 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
470 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
480 line = StrSep(&line,
"\r");
481 line = StrSep(&line,
"\n");
502static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
503 char** password,
char** domain)
505 static const size_t password_size = 512;
506 const char* userAuth =
"Username: ";
507 const char* domainAuth =
"Domain: ";
508 const char* pwdAuth =
"Password: ";
509 BOOL pinOnly = FALSE;
510 BOOL queryAll = FALSE;
512 WINPR_ASSERT(instance);
513 WINPR_ASSERT(instance->context);
514 WINPR_ASSERT(instance->context->settings);
518 case AUTH_SMARTCARD_PIN:
519 pwdAuth =
"Smartcard-Pin: ";
532 userAuth =
"GatewayUsername: ";
533 domainAuth =
"GatewayDomain: ";
534 pwdAuth =
"GatewayPassword: ";
540 if (!username || !password || !domain)
545 const char* suggest = *username;
546 if (queryAll || !suggest)
548 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
556 const char* suggest = *domain;
557 if (queryAll || !suggest)
559 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
566 char* line = calloc(password_size,
sizeof(
char));
571 const BOOL fromStdin =
574 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
578 if (password_size > 0)
596BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
597 rdp_auth_reason reason)
599 WINPR_ASSERT(instance);
600 WINPR_ASSERT(username);
601 WINPR_ASSERT(password);
602 WINPR_ASSERT(domain);
612 case AUTH_SMARTCARD_PIN:
613 if ((*username) && (*password))
624 return client_cli_authenticate_raw(instance, reason, username, password, domain);
627BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
628 DWORD count, DWORD* choice, BOOL gateway)
630 unsigned long answer = 0;
633 printf(
"Multiple smartcards are available for use:\n");
634 for (DWORD i = 0; i < count; i++)
637 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
638 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
641 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
642 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
643 cert->issuer, cert->upn);
646 free(container_name);
651 char input[10] = { 0 };
653 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
654 gateway ?
"gateway authentication" :
"logon", count - 1);
655 (void)fflush(stdout);
656 if (!fgets(input, 10, stdin))
658 WLog_ERR(TAG,
"could not read from stdin");
662 answer = strtoul(input, &p, 10);
663 if ((*p ==
'\n' && p != input) && answer < count)
665 *choice = (UINT32)answer;
671#if defined(WITH_FREERDP_DEPRECATED)
672BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
676 WLog_INFO(TAG,
"Authentication via smartcard");
680 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
683BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
685 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
689static DWORD client_cli_accept_certificate(freerdp* instance)
693 WINPR_ASSERT(instance);
694 WINPR_ASSERT(instance->context);
696 const rdpSettings* settings = instance->context->settings;
697 WINPR_ASSERT(settings);
705 printf(
"Do you trust the above certificate? (Y/T/N) ");
706 (void)fflush(stdout);
707 answer = freerdp_interruptible_getc(instance->context, stdin);
709 if ((answer == EOF) || feof(stdin))
711 printf(
"\nError: Could not read answer from stdin.\n");
719 answer = freerdp_interruptible_getc(instance->context, stdin);
726 answer = freerdp_interruptible_getc(instance->context, stdin);
733 answer = freerdp_interruptible_getc(instance->context, stdin);
759#if defined(WITH_FREERDP_DEPRECATED)
760DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
761 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
763 WINPR_UNUSED(common_name);
764 WINPR_UNUSED(host_mismatch);
766 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
767 printf(
"Certificate details:\n");
768 printf(
"\tSubject: %s\n", subject);
769 printf(
"\tIssuer: %s\n", issuer);
770 printf(
"\tThumbprint: %s\n", fingerprint);
771 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
772 "the CA certificate in your certificate store, or the certificate has expired.\n"
773 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
774 return client_cli_accept_certificate(instance);
778static char* client_cli_pem_cert(
const char* pem)
780 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
784 char* fp = freerdp_certificate_get_fingerprint(cert);
785 char* start = freerdp_certificate_get_validity(cert, TRUE);
786 char* end = freerdp_certificate_get_validity(cert, FALSE);
787 freerdp_certificate_free(cert);
791 winpr_asprintf(&str, &slen,
794 "\tThumbprint: %s\n",
817DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
818 const char* common_name,
const char* subject,
819 const char* issuer,
const char* fingerprint, DWORD flags)
821 const char* type =
"RDP-Server";
823 WINPR_ASSERT(instance);
824 WINPR_ASSERT(instance->context);
825 WINPR_ASSERT(instance->context->settings);
827 if (flags & VERIFY_CERT_FLAG_GATEWAY)
828 type =
"RDP-Gateway";
830 if (flags & VERIFY_CERT_FLAG_REDIRECT)
831 type =
"RDP-Redirect";
833 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
834 printf(
"\tCommon Name: %s\n", common_name);
835 printf(
"\tSubject: %s\n", subject);
836 printf(
"\tIssuer: %s\n", issuer);
840 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
842 char* str = client_cli_pem_cert(fingerprint);
847 printf(
"\tThumbprint: %s\n", fingerprint);
849 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
850 "the CA certificate in your certificate store, or the certificate has expired.\n"
851 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
852 return client_cli_accept_certificate(instance);
870#if defined(WITH_FREERDP_DEPRECATED)
871DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
872 const char* subject,
const char* issuer,
873 const char* fingerprint,
const char* old_subject,
874 const char* old_issuer,
const char* old_fingerprint)
876 WINPR_UNUSED(common_name);
878 printf(
"WARNING: This callback is deprecated, migrate to "
879 "client_cli_verify_changed_certificate_ex\n");
880 printf(
"!!! Certificate has changed !!!\n");
882 printf(
"New Certificate details:\n");
883 printf(
"\tSubject: %s\n", subject);
884 printf(
"\tIssuer: %s\n", issuer);
885 printf(
"\tThumbprint: %s\n", fingerprint);
887 printf(
"Old Certificate details:\n");
888 printf(
"\tSubject: %s\n", old_subject);
889 printf(
"\tIssuer: %s\n", old_issuer);
890 printf(
"\tThumbprint: %s\n", old_fingerprint);
892 printf(
"The above X.509 certificate does not match the certificate used for previous "
894 "This may indicate that the certificate has been tampered with.\n"
895 "Please contact the administrator of the RDP server and clarify.\n");
896 return client_cli_accept_certificate(instance);
919DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
920 const char* common_name,
const char* subject,
921 const char* issuer,
const char* fingerprint,
922 const char* old_subject,
const char* old_issuer,
923 const char* old_fingerprint, DWORD flags)
925 const char* type =
"RDP-Server";
927 WINPR_ASSERT(instance);
928 WINPR_ASSERT(instance->context);
929 WINPR_ASSERT(instance->context->settings);
931 if (flags & VERIFY_CERT_FLAG_GATEWAY)
932 type =
"RDP-Gateway";
934 if (flags & VERIFY_CERT_FLAG_REDIRECT)
935 type =
"RDP-Redirect";
937 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
939 printf(
"New Certificate details:\n");
940 printf(
"\tCommon Name: %s\n", common_name);
941 printf(
"\tSubject: %s\n", subject);
942 printf(
"\tIssuer: %s\n", issuer);
946 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
948 char* str = client_cli_pem_cert(fingerprint);
953 printf(
"\tThumbprint: %s\n", fingerprint);
955 printf(
"Old Certificate details:\n");
956 printf(
"\tSubject: %s\n", old_subject);
957 printf(
"\tIssuer: %s\n", old_issuer);
961 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
963 char* str = client_cli_pem_cert(old_fingerprint);
968 printf(
"\tThumbprint: %s\n", old_fingerprint);
970 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
972 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
973 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
974 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
975 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
978 printf(
"The above X.509 certificate does not match the certificate used for previous "
980 "This may indicate that the certificate has been tampered with.\n"
981 "Please contact the administrator of the RDP server and clarify.\n");
982 return client_cli_accept_certificate(instance);
985BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
986 BOOL isConsentMandatory,
size_t length,
987 const WCHAR* message)
990 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
992 WINPR_ASSERT(instance);
993 WINPR_ASSERT(instance->context);
994 WINPR_ASSERT(instance->context->settings);
996 if (!isDisplayMandatory && !isConsentMandatory)
999 printf(
"%s:\n", msgType);
1001 printf(
"%.*S\n", (
int)length, message);
1004 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR), NULL);
1007 printf(
"Failed to convert message!\n");
1010 printf(
"%s\n", msg);
1015 while (isConsentMandatory)
1017 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1018 (void)fflush(stdout);
1019 answer = freerdp_interruptible_getc(instance->context, stdin);
1021 if ((answer == EOF) || feof(stdin))
1023 printf(
"\nError: Could not read answer from stdin.\n");
1031 answer = freerdp_interruptible_getc(instance->context, stdin);
1038 (void)freerdp_interruptible_getc(instance->context, stdin);
1051static const char* extract_authorization_code(
char* url)
1055 for (
char* p = strchr(url,
'?'); p++ != NULL; p = strchr(p,
'&'))
1057 if (strncmp(p,
"code=", 5) != 0)
1063 end = strchr(p,
'&');
1073#if defined(WITH_AAD)
1074static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1075 const char* req_cnf,
char** token)
1077 WINPR_ASSERT(instance);
1078 WINPR_ASSERT(instance->context);
1082 char* token_request = NULL;
1084 WINPR_ASSERT(scope);
1085 WINPR_ASSERT(req_cnf);
1086 WINPR_ASSERT(token);
1091 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1092 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1094 printf(
"Browse to: %s\n", request);
1096 printf(
"Paste redirect URL here: \n");
1098 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1101 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);
1111 rc = client_common_get_access_token(instance, token_request, token);
1114 free(token_request);
1116 return rc && (*token != NULL);
1119static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1121 WINPR_ASSERT(instance);
1122 WINPR_ASSERT(instance->context);
1126 char* token_request = NULL;
1128 WINPR_ASSERT(token);
1134 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1135 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1138 printf(
"Browse to: %s\n", request);
1140 printf(
"Paste redirect URL here: \n");
1142 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1145 const char* code = extract_authorization_code(url);
1149 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1150 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1155 rc = client_common_get_access_token(instance, token_request, token);
1158 free(token_request);
1160 return rc && (*token != NULL);
1164BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1167 WINPR_ASSERT(instance);
1168 WINPR_ASSERT(token);
1170#if !defined(WITH_AAD)
1171 WLog_ERR(TAG,
"Build does not support AAD authentication");
1175 WINPR_ASSERT(instance->context);
1184 case ACCESS_TOKEN_TYPE_AAD:
1189 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1196 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1200 va_start(ap, count);
1201 const char* scope = va_arg(ap,
const char*);
1202 const char* req_cnf = va_arg(ap,
const char*);
1203 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1207 case ACCESS_TOKEN_TYPE_AVD:
1210 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1213 rc = client_cli_get_avd_access_token(instance, token);
1216 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%" PRIuz
"], aborting", tokenType);
1227BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1230 WINPR_ASSERT(request);
1231 WINPR_ASSERT(token);
1235 BYTE* response = NULL;
1236 size_t response_length = 0;
1238 wLog* log = WLog_Get(TAG);
1240 const char* token_ep =
1241 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1242 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1244 WLog_ERR(TAG,
"access token request failed");
1248 if (resp_code != HTTP_STATUS_OK)
1250 char buffer[64] = { 0 };
1252 WLog_Print(log, WLOG_ERROR,
1253 "Server unwilling to provide access token; returned status code %s",
1254 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1255 if (response_length > 0)
1256 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1260 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1272SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1275 WINPR_UNUSED(instance);
1276 WINPR_ASSERT(instance->context);
1277 WINPR_UNUSED(userarg);
1278 WINPR_ASSERT(instance);
1281 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1283 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1289 if (strcmp(what,
"arm-transport") == 0)
1290 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1293 const rdpSettings* settings = instance->context->settings;
1297 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1306 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1307 "tech support for help if this keeps happening.",
1312 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1313 what, current + 1, max, delay);
1314 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1317BOOL client_auto_reconnect(freerdp* instance)
1319 return client_auto_reconnect_ex(instance, NULL);
1322BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1326 UINT32 numRetries = 0;
1327 rdpSettings* settings = NULL;
1332 WINPR_ASSERT(instance->context);
1334 settings = instance->context->settings;
1335 WINPR_ASSERT(settings);
1337 const UINT32 maxRetries =
1341 error = freerdp_error_info(instance);
1344 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1346 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1347 freerdp_get_error_info_string(error));
1349 case ERRINFO_SUCCESS:
1351 WLog_INFO(TAG,
"Network disconnect!");
1354 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1361 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1365 switch (freerdp_get_last_error(instance->context))
1367 case FREERDP_ERROR_CONNECT_CANCELLED:
1368 WLog_WARN(TAG,
"Connection aborted by user");
1378 if ((maxRetries > 0) && (numRetries >= maxRetries))
1380 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1385 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1387 const SSIZE_T delay =
1388 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries, NULL);
1393 if (freerdp_reconnect(instance))
1396 switch (freerdp_get_last_error(instance->context))
1398 case FREERDP_ERROR_CONNECT_CANCELLED:
1399 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1404 for (UINT32 x = 0; x < delay / 10; x++)
1406 if (!IFCALLRESULT(TRUE, window_events, instance))
1408 WLog_ERR(TAG,
"window_events failed!");
1416 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1420int freerdp_client_common_stop(rdpContext* context)
1422 rdpClientContext* cctx = (rdpClientContext*)context;
1425 freerdp_abort_connect_context(&cctx->context);
1429 (void)WaitForSingleObject(cctx->thread, INFINITE);
1430 (void)CloseHandle(cctx->thread);
1431 cctx->thread = NULL;
1437#if defined(CHANNEL_ENCOMSP_CLIENT)
1438BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1440 rdpClientContext* cctx = NULL;
1446 cctx = (rdpClientContext*)encomsp->custom;
1448 state = cctx->controlToggle;
1449 cctx->controlToggle = !cctx->controlToggle;
1450 return freerdp_client_encomsp_set_control(encomsp, state);
1453BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1460 pdu.ParticipantId = encomsp->participantId;
1461 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1464 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1466 encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1472client_encomsp_participant_created(EncomspClientContext* context,
1475 rdpClientContext* cctx = NULL;
1476 rdpSettings* settings = NULL;
1479 if (!context || !context->custom || !participantCreated)
1480 return ERROR_INVALID_PARAMETER;
1482 cctx = (rdpClientContext*)context->custom;
1485 settings = cctx->context.settings;
1486 WINPR_ASSERT(settings);
1488 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1489 context->participantId = participantCreated->ParticipantId;
1492 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1493 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1495 if (!freerdp_client_encomsp_set_control(context, TRUE))
1496 return ERROR_INTERNAL_ERROR;
1502 return ERROR_INTERNAL_ERROR;
1505 return CHANNEL_RC_OK;
1508static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1510 cctx->encomsp = encomsp;
1511 encomsp->custom = (
void*)cctx;
1512 encomsp->ParticipantCreated = client_encomsp_participant_created;
1515static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1519 encomsp->custom = NULL;
1520 encomsp->ParticipantCreated = NULL;
1524 cctx->encomsp = NULL;
1528void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1529 const ChannelConnectedEventArgs* e)
1531 rdpClientContext* cctx = (rdpClientContext*)context;
1539#if defined(CHANNEL_AINPUT_CLIENT)
1540 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1541 cctx->ainput = (AInputClientContext*)e->pInterface;
1543#if defined(CHANNEL_RDPEI_CLIENT)
1544 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1546 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1549#if defined(CHANNEL_RDPGFX_CLIENT)
1550 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1552 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1555#if defined(CHANNEL_GEOMETRY_CLIENT)
1556 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1558 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1561#if defined(CHANNEL_VIDEO_CLIENT)
1562 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1564 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1566 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1568 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1571#if defined(CHANNEL_ENCOMSP_CLIENT)
1572 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1574 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1579void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1580 const ChannelDisconnectedEventArgs* e)
1582 rdpClientContext* cctx = (rdpClientContext*)context;
1590#if defined(CHANNEL_AINPUT_CLIENT)
1591 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1592 cctx->ainput = NULL;
1594#if defined(CHANNEL_RDPEI_CLIENT)
1595 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1600#if defined(CHANNEL_RDPGFX_CLIENT)
1601 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1603 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1606#if defined(CHANNEL_GEOMETRY_CLIENT)
1607 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1609 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1612#if defined(CHANNEL_VIDEO_CLIENT)
1613 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1615 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1617 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1619 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1622#if defined(CHANNEL_ENCOMSP_CLIENT)
1623 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1625 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1630BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1632 BOOL handled = FALSE;
1636#if defined(CHANNEL_AINPUT_CLIENT)
1643 INT32 value = mflags & 0xFF;
1645 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1646 value = -1 * (0x100 - value);
1652 if (mflags & PTR_FLAGS_WHEEL)
1654 flags |= AINPUT_FLAGS_WHEEL;
1658 if (mflags & PTR_FLAGS_HWHEEL)
1660 flags |= AINPUT_FLAGS_WHEEL;
1664 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1665 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1666 if (rc == CHANNEL_RC_OK)
1672 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1677#if defined(CHANNEL_AINPUT_CLIENT)
1678static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1683 WINPR_ASSERT(cctx->ainput);
1684 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1686 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1688 return rc == CHANNEL_RC_OK;
1692static bool button_pressed(
const rdpClientContext* cctx)
1695 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1697 const BOOL cur = cctx->pressed_buttons[x];
1704BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1707 BOOL handled = FALSE;
1711 if (mflags & PTR_FLAGS_BUTTON1)
1712 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1713 if (mflags & PTR_FLAGS_BUTTON2)
1714 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1715 if (mflags & PTR_FLAGS_BUTTON3)
1716 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1718 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1721 if (!button_pressed(cctx))
1725 const BOOL haveRelative =
1727 if (relative && haveRelative)
1729 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1730 WINPR_ASSERTING_INT_CAST(int16_t, x),
1731 WINPR_ASSERTING_INT_CAST(int16_t, y));
1734#if defined(CHANNEL_AINPUT_CLIENT)
1739 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1740 flags |= AINPUT_FLAGS_HAVE_REL;
1743 flags |= AINPUT_FLAGS_REL;
1745 if (mflags & PTR_FLAGS_DOWN)
1746 flags |= AINPUT_FLAGS_DOWN;
1747 if (mflags & PTR_FLAGS_BUTTON1)
1748 flags |= AINPUT_FLAGS_BUTTON1;
1749 if (mflags & PTR_FLAGS_BUTTON2)
1750 flags |= AINPUT_FLAGS_BUTTON2;
1751 if (mflags & PTR_FLAGS_BUTTON3)
1752 flags |= AINPUT_FLAGS_BUTTON3;
1753 if (mflags & PTR_FLAGS_MOVE)
1754 flags |= AINPUT_FLAGS_MOVE;
1755 handled = ainput_send_diff_event(cctx, flags, x, y);
1765 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1772 freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1773 (UINT16)cctx->lastY);
1778BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1781 BOOL handled = FALSE;
1784 if (mflags & PTR_XFLAGS_BUTTON1)
1785 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1786 if (mflags & PTR_XFLAGS_BUTTON2)
1787 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1789 const BOOL haveRelative =
1791 if (relative && haveRelative)
1793 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1794 WINPR_ASSERTING_INT_CAST(int16_t, x),
1795 WINPR_ASSERTING_INT_CAST(int16_t, y));
1798#if defined(CHANNEL_AINPUT_CLIENT)
1804 flags |= AINPUT_FLAGS_REL;
1805 if (mflags & PTR_XFLAGS_DOWN)
1806 flags |= AINPUT_FLAGS_DOWN;
1807 if (mflags & PTR_XFLAGS_BUTTON1)
1808 flags |= AINPUT_XFLAGS_BUTTON1;
1809 if (mflags & PTR_XFLAGS_BUTTON2)
1810 flags |= AINPUT_XFLAGS_BUTTON2;
1812 handled = ainput_send_diff_event(cctx, flags, x, y);
1822 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1829 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1830 (UINT16)cctx->lastY);
1836static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
1839 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
1840 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
1841 WINPR_ASSERT(contact);
1842 WINPR_ASSERT(contact->x <= UINT16_MAX);
1843 WINPR_ASSERT(contact->y <= UINT16_MAX);
1845 switch (contact->count)
1848 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
1849 contact->x, contact->y);
1851 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
1852 contact->x, contact->y);
1854 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
1855 contact->x, contact->y);
1857 return freerdp_client_send_extended_button_event(
1858 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1860 return freerdp_client_send_extended_button_event(
1861 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1868static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1871 WINPR_ASSERT(contact);
1873#if defined(CHANNEL_RDPEI_CLIENT)
1874 RdpeiClientContext* rdpei = cctx->rdpei;
1877 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1881 if (rdpei->TouchRawEvent)
1883 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1884 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1885 ? CONTACT_DATA_PRESSURE_PRESENT
1888 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1889 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1890 RDPINPUT_CONTACT_FLAG_INCONTACT,
1891 contactFlags, contact->pressure);
1892 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1893 contactFlags, contact->pressure);
1897 WINPR_ASSERT(rdpei->TouchEnd);
1898 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1902 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1903 "-DCHANNEL_RDPEI_CLIENT=ON");
1904 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1908static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1911 WINPR_ASSERT(contact);
1913#if defined(CHANNEL_RDPEI_CLIENT)
1914 RdpeiClientContext* rdpei = cctx->rdpei;
1918 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1922 if (rdpei->TouchRawEvent)
1924 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1925 RDPINPUT_CONTACT_FLAG_INCONTACT;
1926 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1927 ? CONTACT_DATA_PRESSURE_PRESENT
1929 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1930 contactFlags, contact->pressure);
1934 WINPR_ASSERT(rdpei->TouchBegin);
1935 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1940 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1941 "-DCHANNEL_RDPEI_CLIENT=ON");
1942 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1946static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
1949 const UINT16 flags = PTR_FLAGS_MOVE;
1951 WINPR_ASSERT(contact);
1952 WINPR_ASSERT(contact->x <= UINT16_MAX);
1953 WINPR_ASSERT(contact->y <= UINT16_MAX);
1954 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1957static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1960 WINPR_ASSERT(contact);
1962#if defined(CHANNEL_RDPEI_CLIENT)
1963 RdpeiClientContext* rdpei = cctx->rdpei;
1966 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
1970 if (rdpei->TouchRawEvent)
1972 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1973 RDPINPUT_CONTACT_FLAG_INCONTACT;
1974 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1975 ? CONTACT_DATA_PRESSURE_PRESENT
1977 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1978 contactFlags, contact->pressure);
1982 WINPR_ASSERT(rdpei->TouchUpdate);
1983 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1988 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1989 "-DCHANNEL_RDPEI_CLIENT=ON");
1990 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
1994static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
1995 UINT32 pressure, INT32 x, INT32 y,
1999 WINPR_ASSERT(pcontact);
2001 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2005 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2006 if (newcontact || (contact->id == touchId))
2008 contact->id = touchId;
2009 contact->flags = flags;
2010 contact->pressure = pressure;
2014 *pcontact = *contact;
2016 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2029BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2030 UINT32 pressure, INT32 x, INT32 y)
2032 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
2037 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2040 switch (flags & mask)
2042 case FREERDP_TOUCH_DOWN:
2043 return freerdp_handle_touch_down(cctx, &contact);
2044 case FREERDP_TOUCH_UP:
2045 return freerdp_handle_touch_up(cctx, &contact);
2046 case FREERDP_TOUCH_MOTION:
2047 return freerdp_handle_touch_motion(cctx, &contact);
2049 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %d, ignoring", flags);
2054BOOL freerdp_client_load_channels(freerdp* instance)
2056 WINPR_ASSERT(instance);
2057 WINPR_ASSERT(instance->context);
2059 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2061 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2067int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2069 const char* str_data = freerdp_get_logon_error_info_data(data);
2070 const char* str_type = freerdp_get_logon_error_info_type(type);
2072 if (!instance || !instance->context)
2075 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2079static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2084 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2087 if (deviceid == pen->deviceid)
2097static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2100 static const INT32 null_deviceid = 0;
2103 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2104 if (freerdp_client_is_pen(cctx, deviceid))
2106 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2117 pen->deviceid = deviceid;
2118 pen->max_pressure = pressure;
2121 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2125 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2129BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2131#if defined(CHANNEL_RDPEI_CLIENT)
2132 if ((flags & FREERDP_PEN_REGISTER) != 0)
2136 va_start(args, deviceid);
2137 double pressure = va_arg(args,
double);
2139 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2145 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2149 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2151 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2153 RdpeiClientContext* rdpei = cctx->rdpei;
2154 WINPR_ASSERT(rdpei);
2156 UINT32 normalizedpressure = 1024;
2159 UINT16 rotation = 0;
2163 va_start(args, deviceid);
2165 x = va_arg(args, INT32);
2166 y = va_arg(args, INT32);
2167 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2169 const double pressure = va_arg(args,
double);
2170 const double np = (pressure * 1024.0) / pen->max_pressure;
2171 normalizedpressure = (UINT32)lround(np);
2172 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2173 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2175 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2177 const unsigned arg = va_arg(args,
unsigned);
2178 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2179 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2181 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2183 const int arg = va_arg(args,
int);
2184 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2185 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2187 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2189 const int arg = va_arg(args,
int);
2190 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2191 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2195 if ((flags & FREERDP_PEN_PRESS) != 0)
2199 flags = FREERDP_PEN_MOTION |
2200 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2201 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2202 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2204 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2206 if (!pen->pressed ||
2207 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2208 flags = FREERDP_PEN_MOTION |
2209 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2211 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2214 flags |= pen->flags;
2215 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2216 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2217 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2218 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2222 if ((flags & FREERDP_PEN_PRESS) != 0)
2224 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2225 pen->hovering = FALSE;
2226 pen->pressed = TRUE;
2228 WINPR_ASSERT(rdpei->PenBegin);
2229 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2230 normalizedpressure, rotation, tiltX, tiltY);
2231 return rc == CHANNEL_RC_OK;
2233 else if ((flags & FREERDP_PEN_MOTION) != 0)
2235 UINT rc = ERROR_INTERNAL_ERROR;
2238 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2241 WINPR_ASSERT(rdpei->PenUpdate);
2242 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2243 rotation, tiltX, tiltY);
2245 else if (pen->hovering)
2247 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2249 WINPR_ASSERT(rdpei->PenHoverUpdate);
2250 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2251 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2255 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2256 pen->hovering = TRUE;
2258 WINPR_ASSERT(rdpei->PenHoverBegin);
2259 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2260 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2262 return rc == CHANNEL_RC_OK;
2264 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2266 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2267 pen->pressed = FALSE;
2268 pen->hovering = TRUE;
2270 WINPR_ASSERT(rdpei->PenUpdate);
2271 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2272 normalizedpressure, rotation, tiltX, tiltY);
2273 if (rc != CHANNEL_RC_OK)
2275 WINPR_ASSERT(rdpei->PenEnd);
2276 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2277 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2278 return re == CHANNEL_RC_OK;
2281 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2283 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2284 "-DCHANNEL_RDPEI_CLIENT=ON");
2290BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2294#if defined(CHANNEL_RDPEI_CLIENT)
2295 RdpeiClientContext* rdpei = cctx->rdpei;
2300 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2305 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2306 pen->hovering = FALSE;
2307 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2312 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2313 "-DCHANNEL_RDPEI_CLIENT=ON");
2318BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2325 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2328 if (pen->deviceid == deviceid)
2335BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2337 WINPR_ASSERT(ccontext);
2339 const rdpSettings* settings = ccontext->context.settings;
2342 BOOL ainput = FALSE;
2343#if defined(CHANNEL_AINPUT_CLIENT)
2344 ainput = ccontext->ainput != NULL;
2347 return useRelative && (haveRelative || ainput);
2350#if defined(WITH_AAD)
2351WINPR_ATTR_MALLOC(free, 1)
2352static
char* get_redirect_uri(const rdpSettings* settings)
2354 char* redirect_uri = NULL;
2358 const char* redirect_fmt =
2361 const char* tenantid =
"common";
2365 if (tenantid && redirect_fmt)
2370 size_t redirect_len = 0;
2371 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2377 const char* redirect_fmt =
2380 size_t redirect_len = 0;
2381 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2383 return redirect_uri;
2386static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2388 const rdpSettings* settings = cctx->context.settings;
2390 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2391 AAD_WELLKNOWN_authorization_endpoint);
2394 if (!client_id || !ep || !scope)
2397 char* redirect_uri = get_redirect_uri(settings);
2403 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2404 client_id, scope, redirect_uri);
2409static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2411 const rdpSettings* settings = cctx->context.settings;
2413 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2414 AAD_WELLKNOWN_authorization_endpoint);
2417 if (!client_id || !ep || !scope)
2420 char* redirect_uri = get_redirect_uri(settings);
2427 const char* code = va_arg(ap,
const char*);
2428 winpr_asprintf(&url, &urllen,
2429 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2430 code, client_id, scope, redirect_uri);
2435static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2437 const rdpSettings* settings = cctx->context.settings;
2440 char* redirect_uri = get_redirect_uri(settings);
2443 if (!client_id || !redirect_uri)
2445 const char* scope = va_arg(ap,
const char*);
2449 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2450 AAD_WELLKNOWN_authorization_endpoint);
2452 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2453 client_id, scope, redirect_uri);
2459static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2461 const rdpSettings* settings = cctx->context.settings;
2463 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2464 AAD_WELLKNOWN_authorization_endpoint);
2465 const char* scope = va_arg(ap,
const char*);
2466 const char* code = va_arg(ap,
const char*);
2467 const char* req_cnf = va_arg(ap,
const char*);
2469 if (!client_id || !ep || !scope || !code || !req_cnf)
2472 char* redirect_uri = get_redirect_uri(settings);
2481 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2482 code, client_id, scope, redirect_uri, req_cnf);
2488char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2497#if defined(WITH_AAD)
2498 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2499 str = aad_auth_request(cctx, ap);
2501 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2502 str = aad_token_request(cctx, ap);
2504 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2505 str = avd_auth_request(cctx, ap);
2507 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2508 str = avd_token_request(cctx, ap);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.