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