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;
511 WINPR_ASSERT(instance);
512 WINPR_ASSERT(instance->context);
513 WINPR_ASSERT(instance->context->settings);
517 case AUTH_SMARTCARD_PIN:
518 pwdAuth =
"Smartcard-Pin: ";
529 userAuth =
"GatewayUsername: ";
530 domainAuth =
"GatewayDomain: ";
531 pwdAuth =
"GatewayPassword: ";
537 if (!username || !password || !domain)
542 const int rc = client_cli_read_string(instance, userAuth, *username, username);
549 const int rc = client_cli_read_string(instance, domainAuth, *domain, domain);
555 char* line = calloc(password_size,
sizeof(
char));
560 const BOOL fromStdin =
563 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
567 if (password_size > 0)
585BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
586 rdp_auth_reason reason)
588 WINPR_ASSERT(instance);
589 WINPR_ASSERT(username);
590 WINPR_ASSERT(password);
591 WINPR_ASSERT(domain);
601 case AUTH_SMARTCARD_PIN:
602 if ((*username) && (*password))
613 return client_cli_authenticate_raw(instance, reason, username, password, domain);
616BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
617 DWORD count, DWORD* choice, BOOL gateway)
619 unsigned long answer = 0;
622 printf(
"Multiple smartcards are available for use:\n");
623 for (DWORD i = 0; i < count; i++)
626 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
627 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
630 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
631 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
632 cert->issuer, cert->upn);
635 free(container_name);
640 char input[10] = { 0 };
642 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
643 gateway ?
"gateway authentication" :
"logon", count - 1);
644 (void)fflush(stdout);
645 if (!fgets(input, 10, stdin))
647 WLog_ERR(TAG,
"could not read from stdin");
651 answer = strtoul(input, &p, 10);
652 if ((*p ==
'\n' && p != input) && answer < count)
654 *choice = (UINT32)answer;
660#if defined(WITH_FREERDP_DEPRECATED)
661BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
665 WLog_INFO(TAG,
"Authentication via smartcard");
669 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
672BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
674 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
678static DWORD client_cli_accept_certificate(freerdp* instance)
682 WINPR_ASSERT(instance);
683 WINPR_ASSERT(instance->context);
685 const rdpSettings* settings = instance->context->settings;
686 WINPR_ASSERT(settings);
694 printf(
"Do you trust the above certificate? (Y/T/N) ");
695 (void)fflush(stdout);
696 answer = freerdp_interruptible_getc(instance->context, stdin);
698 if ((answer == EOF) || feof(stdin))
700 printf(
"\nError: Could not read answer from stdin.\n");
708 answer = freerdp_interruptible_getc(instance->context, stdin);
715 answer = freerdp_interruptible_getc(instance->context, stdin);
722 answer = freerdp_interruptible_getc(instance->context, stdin);
748#if defined(WITH_FREERDP_DEPRECATED)
749DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
750 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
752 WINPR_UNUSED(common_name);
753 WINPR_UNUSED(host_mismatch);
755 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
756 printf(
"Certificate details:\n");
757 printf(
"\tSubject: %s\n", subject);
758 printf(
"\tIssuer: %s\n", issuer);
759 printf(
"\tThumbprint: %s\n", fingerprint);
760 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
761 "the CA certificate in your certificate store, or the certificate has expired.\n"
762 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
763 return client_cli_accept_certificate(instance);
767static char* client_cli_pem_cert(
const char* pem)
769 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
773 char* fp = freerdp_certificate_get_fingerprint(cert);
774 char* start = freerdp_certificate_get_validity(cert, TRUE);
775 char* end = freerdp_certificate_get_validity(cert, FALSE);
776 freerdp_certificate_free(cert);
780 winpr_asprintf(&str, &slen,
783 "\tThumbprint: %s\n",
806DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
807 const char* common_name,
const char* subject,
808 const char* issuer,
const char* fingerprint, DWORD flags)
810 const char* type =
"RDP-Server";
812 WINPR_ASSERT(instance);
813 WINPR_ASSERT(instance->context);
814 WINPR_ASSERT(instance->context->settings);
816 if (flags & VERIFY_CERT_FLAG_GATEWAY)
817 type =
"RDP-Gateway";
819 if (flags & VERIFY_CERT_FLAG_REDIRECT)
820 type =
"RDP-Redirect";
822 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
823 printf(
"\tCommon Name: %s\n", common_name);
824 printf(
"\tSubject: %s\n", subject);
825 printf(
"\tIssuer: %s\n", issuer);
829 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
831 char* str = client_cli_pem_cert(fingerprint);
836 printf(
"\tThumbprint: %s\n", fingerprint);
838 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
839 "the CA certificate in your certificate store, or the certificate has expired.\n"
840 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
841 return client_cli_accept_certificate(instance);
859#if defined(WITH_FREERDP_DEPRECATED)
860DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
861 const char* subject,
const char* issuer,
862 const char* fingerprint,
const char* old_subject,
863 const char* old_issuer,
const char* old_fingerprint)
865 WINPR_UNUSED(common_name);
867 printf(
"WARNING: This callback is deprecated, migrate to "
868 "client_cli_verify_changed_certificate_ex\n");
869 printf(
"!!! Certificate has changed !!!\n");
871 printf(
"New Certificate details:\n");
872 printf(
"\tSubject: %s\n", subject);
873 printf(
"\tIssuer: %s\n", issuer);
874 printf(
"\tThumbprint: %s\n", fingerprint);
876 printf(
"Old Certificate details:\n");
877 printf(
"\tSubject: %s\n", old_subject);
878 printf(
"\tIssuer: %s\n", old_issuer);
879 printf(
"\tThumbprint: %s\n", old_fingerprint);
881 printf(
"The above X.509 certificate does not match the certificate used for previous "
883 "This may indicate that the certificate has been tampered with.\n"
884 "Please contact the administrator of the RDP server and clarify.\n");
885 return client_cli_accept_certificate(instance);
908DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
909 const char* common_name,
const char* subject,
910 const char* issuer,
const char* fingerprint,
911 const char* old_subject,
const char* old_issuer,
912 const char* old_fingerprint, DWORD flags)
914 const char* type =
"RDP-Server";
916 WINPR_ASSERT(instance);
917 WINPR_ASSERT(instance->context);
918 WINPR_ASSERT(instance->context->settings);
920 if (flags & VERIFY_CERT_FLAG_GATEWAY)
921 type =
"RDP-Gateway";
923 if (flags & VERIFY_CERT_FLAG_REDIRECT)
924 type =
"RDP-Redirect";
926 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
928 printf(
"New Certificate details:\n");
929 printf(
"\tCommon Name: %s\n", common_name);
930 printf(
"\tSubject: %s\n", subject);
931 printf(
"\tIssuer: %s\n", issuer);
935 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
937 char* str = client_cli_pem_cert(fingerprint);
942 printf(
"\tThumbprint: %s\n", fingerprint);
944 printf(
"Old Certificate details:\n");
945 printf(
"\tSubject: %s\n", old_subject);
946 printf(
"\tIssuer: %s\n", old_issuer);
950 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
952 char* str = client_cli_pem_cert(old_fingerprint);
957 printf(
"\tThumbprint: %s\n", old_fingerprint);
959 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
961 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
962 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
963 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
964 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
967 printf(
"The above X.509 certificate does not match the certificate used for previous "
969 "This may indicate that the certificate has been tampered with.\n"
970 "Please contact the administrator of the RDP server and clarify.\n");
971 return client_cli_accept_certificate(instance);
974BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
975 BOOL isConsentMandatory,
size_t length,
976 const WCHAR* message)
979 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
981 WINPR_ASSERT(instance);
982 WINPR_ASSERT(instance->context);
983 WINPR_ASSERT(instance->context->settings);
985 if (!isDisplayMandatory && !isConsentMandatory)
988 printf(
"%s:\n", msgType);
990 printf(
"%.*S\n", (
int)length, message);
993 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR), NULL);
996 printf(
"Failed to convert message!\n");
1004 while (isConsentMandatory)
1006 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1007 (void)fflush(stdout);
1008 answer = freerdp_interruptible_getc(instance->context, stdin);
1010 if ((answer == EOF) || feof(stdin))
1012 printf(
"\nError: Could not read answer from stdin.\n");
1020 answer = freerdp_interruptible_getc(instance->context, stdin);
1027 (void)freerdp_interruptible_getc(instance->context, stdin);
1040static const char* extract_authorization_code(
char* url)
1044 for (
char* p = strchr(url,
'?'); p++ != NULL; p = strchr(p,
'&'))
1046 if (strncmp(p,
"code=", 5) != 0)
1052 end = strchr(p,
'&');
1062#if defined(WITH_AAD)
1063static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1064 const char* req_cnf,
char** token)
1066 WINPR_ASSERT(instance);
1067 WINPR_ASSERT(instance->context);
1071 char* token_request = NULL;
1073 WINPR_ASSERT(scope);
1074 WINPR_ASSERT(req_cnf);
1075 WINPR_ASSERT(token);
1080 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1081 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1083 printf(
"Browse to: %s\n", request);
1085 printf(
"Paste redirect URL here: \n");
1087 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1090 const char* code = extract_authorization_code(url);
1095 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1096 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1100 rc = client_common_get_access_token(instance, token_request, token);
1103 free(token_request);
1105 return rc && (*token != NULL);
1108static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1110 WINPR_ASSERT(instance);
1111 WINPR_ASSERT(instance->context);
1115 char* token_request = NULL;
1117 WINPR_ASSERT(token);
1123 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1124 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1127 printf(
"Browse to: %s\n", request);
1129 printf(
"Paste redirect URL here: \n");
1131 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1134 const char* code = extract_authorization_code(url);
1138 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1139 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1144 rc = client_common_get_access_token(instance, token_request, token);
1147 free(token_request);
1149 return rc && (*token != NULL);
1153BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1156 WINPR_ASSERT(instance);
1157 WINPR_ASSERT(token);
1159#if !defined(WITH_AAD)
1160 WLog_ERR(TAG,
"Build does not support AAD authentication");
1164 WINPR_ASSERT(instance->context);
1173 case ACCESS_TOKEN_TYPE_AAD:
1178 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1185 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1189 va_start(ap, count);
1190 const char* scope = va_arg(ap,
const char*);
1191 const char* req_cnf = va_arg(ap,
const char*);
1192 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1196 case ACCESS_TOKEN_TYPE_AVD:
1199 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1202 rc = client_cli_get_avd_access_token(instance, token);
1205 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%" PRIuz
"], aborting", tokenType);
1216BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1219 WINPR_ASSERT(request);
1220 WINPR_ASSERT(token);
1224 BYTE* response = NULL;
1225 size_t response_length = 0;
1227 wLog* log = WLog_Get(TAG);
1229 const char* token_ep =
1230 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1231 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1233 WLog_ERR(TAG,
"access token request failed");
1237 if (resp_code != HTTP_STATUS_OK)
1239 char buffer[64] = { 0 };
1241 WLog_Print(log, WLOG_ERROR,
1242 "Server unwilling to provide access token; returned status code %s",
1243 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1244 if (response_length > 0)
1245 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1249 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1261SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1264 WINPR_UNUSED(instance);
1265 WINPR_ASSERT(instance->context);
1266 WINPR_UNUSED(userarg);
1267 WINPR_ASSERT(instance);
1270 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1272 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1278 if (strcmp(what,
"arm-transport") == 0)
1279 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1282 const rdpSettings* settings = instance->context->settings;
1286 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1295 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1296 "tech support for help if this keeps happening.",
1301 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1302 what, current + 1, max, delay);
1303 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1306BOOL client_auto_reconnect(freerdp* instance)
1308 return client_auto_reconnect_ex(instance, NULL);
1311BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1315 UINT32 numRetries = 0;
1316 rdpSettings* settings = NULL;
1321 WINPR_ASSERT(instance->context);
1323 settings = instance->context->settings;
1324 WINPR_ASSERT(settings);
1326 const UINT32 maxRetries =
1330 error = freerdp_error_info(instance);
1333 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1335 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1336 freerdp_get_error_info_string(error));
1338 case ERRINFO_SUCCESS:
1340 WLog_INFO(TAG,
"Network disconnect!");
1343 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1350 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1354 switch (freerdp_get_last_error(instance->context))
1356 case FREERDP_ERROR_CONNECT_CANCELLED:
1357 WLog_WARN(TAG,
"Connection aborted by user");
1367 if ((maxRetries > 0) && (numRetries >= maxRetries))
1369 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1374 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1376 const SSIZE_T delay =
1377 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries, NULL);
1382 if (freerdp_reconnect(instance))
1385 switch (freerdp_get_last_error(instance->context))
1387 case FREERDP_ERROR_CONNECT_CANCELLED:
1388 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1393 for (UINT32 x = 0; x < delay / 10; x++)
1395 if (!IFCALLRESULT(TRUE, window_events, instance))
1397 WLog_ERR(TAG,
"window_events failed!");
1405 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1409int freerdp_client_common_stop(rdpContext* context)
1411 rdpClientContext* cctx = (rdpClientContext*)context;
1414 freerdp_abort_connect_context(&cctx->context);
1418 (void)WaitForSingleObject(cctx->thread, INFINITE);
1419 (void)CloseHandle(cctx->thread);
1420 cctx->thread = NULL;
1426#if defined(CHANNEL_ENCOMSP_CLIENT)
1427BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1429 rdpClientContext* cctx = NULL;
1435 cctx = (rdpClientContext*)encomsp->custom;
1437 state = cctx->controlToggle;
1438 cctx->controlToggle = !cctx->controlToggle;
1439 return freerdp_client_encomsp_set_control(encomsp, state);
1442BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1449 pdu.ParticipantId = encomsp->participantId;
1450 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1453 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1455 encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1461client_encomsp_participant_created(EncomspClientContext* context,
1464 rdpClientContext* cctx = NULL;
1465 rdpSettings* settings = NULL;
1468 if (!context || !context->custom || !participantCreated)
1469 return ERROR_INVALID_PARAMETER;
1471 cctx = (rdpClientContext*)context->custom;
1474 settings = cctx->context.settings;
1475 WINPR_ASSERT(settings);
1477 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1478 context->participantId = participantCreated->ParticipantId;
1481 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1482 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1484 if (!freerdp_client_encomsp_set_control(context, TRUE))
1485 return ERROR_INTERNAL_ERROR;
1491 return ERROR_INTERNAL_ERROR;
1494 return CHANNEL_RC_OK;
1497static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1499 cctx->encomsp = encomsp;
1500 encomsp->custom = (
void*)cctx;
1501 encomsp->ParticipantCreated = client_encomsp_participant_created;
1504static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1508 encomsp->custom = NULL;
1509 encomsp->ParticipantCreated = NULL;
1513 cctx->encomsp = NULL;
1517void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1518 const ChannelConnectedEventArgs* e)
1520 rdpClientContext* cctx = (rdpClientContext*)context;
1528#if defined(CHANNEL_AINPUT_CLIENT)
1529 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1530 cctx->ainput = (AInputClientContext*)e->pInterface;
1532#if defined(CHANNEL_RDPEI_CLIENT)
1533 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1535 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1538#if defined(CHANNEL_RDPGFX_CLIENT)
1539 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1541 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1544#if defined(CHANNEL_GEOMETRY_CLIENT)
1545 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1547 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1550#if defined(CHANNEL_VIDEO_CLIENT)
1551 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1553 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1555 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1557 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1560#if defined(CHANNEL_ENCOMSP_CLIENT)
1561 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1563 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1568void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1569 const ChannelDisconnectedEventArgs* e)
1571 rdpClientContext* cctx = (rdpClientContext*)context;
1579#if defined(CHANNEL_AINPUT_CLIENT)
1580 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1581 cctx->ainput = NULL;
1583#if defined(CHANNEL_RDPEI_CLIENT)
1584 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1589#if defined(CHANNEL_RDPGFX_CLIENT)
1590 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1592 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1595#if defined(CHANNEL_GEOMETRY_CLIENT)
1596 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1598 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1601#if defined(CHANNEL_VIDEO_CLIENT)
1602 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1604 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1606 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1608 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1611#if defined(CHANNEL_ENCOMSP_CLIENT)
1612 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1614 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1619BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1621 BOOL handled = FALSE;
1625#if defined(CHANNEL_AINPUT_CLIENT)
1632 INT32 value = mflags & 0xFF;
1634 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1635 value = -1 * (0x100 - value);
1641 if (mflags & PTR_FLAGS_WHEEL)
1643 flags |= AINPUT_FLAGS_WHEEL;
1647 if (mflags & PTR_FLAGS_HWHEEL)
1649 flags |= AINPUT_FLAGS_WHEEL;
1653 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1654 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1655 if (rc == CHANNEL_RC_OK)
1661 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1666#if defined(CHANNEL_AINPUT_CLIENT)
1667static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1672 WINPR_ASSERT(cctx->ainput);
1673 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1675 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1677 return rc == CHANNEL_RC_OK;
1681static bool button_pressed(
const rdpClientContext* cctx)
1684 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1686 const BOOL cur = cctx->pressed_buttons[x];
1693BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1696 BOOL handled = FALSE;
1700 if (mflags & PTR_FLAGS_BUTTON1)
1701 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1702 if (mflags & PTR_FLAGS_BUTTON2)
1703 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1704 if (mflags & PTR_FLAGS_BUTTON3)
1705 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1707 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1710 if (!button_pressed(cctx))
1714 const BOOL haveRelative =
1716 if (relative && haveRelative)
1718 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1719 WINPR_ASSERTING_INT_CAST(int16_t, x),
1720 WINPR_ASSERTING_INT_CAST(int16_t, y));
1723#if defined(CHANNEL_AINPUT_CLIENT)
1728 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1729 flags |= AINPUT_FLAGS_HAVE_REL;
1732 flags |= AINPUT_FLAGS_REL;
1734 if (mflags & PTR_FLAGS_DOWN)
1735 flags |= AINPUT_FLAGS_DOWN;
1736 if (mflags & PTR_FLAGS_BUTTON1)
1737 flags |= AINPUT_FLAGS_BUTTON1;
1738 if (mflags & PTR_FLAGS_BUTTON2)
1739 flags |= AINPUT_FLAGS_BUTTON2;
1740 if (mflags & PTR_FLAGS_BUTTON3)
1741 flags |= AINPUT_FLAGS_BUTTON3;
1742 if (mflags & PTR_FLAGS_MOVE)
1743 flags |= AINPUT_FLAGS_MOVE;
1744 handled = ainput_send_diff_event(cctx, flags, x, y);
1754 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1761 freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1762 (UINT16)cctx->lastY);
1767BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1770 BOOL handled = FALSE;
1773 if (mflags & PTR_XFLAGS_BUTTON1)
1774 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1775 if (mflags & PTR_XFLAGS_BUTTON2)
1776 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1778 const BOOL haveRelative =
1780 if (relative && haveRelative)
1782 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1783 WINPR_ASSERTING_INT_CAST(int16_t, x),
1784 WINPR_ASSERTING_INT_CAST(int16_t, y));
1787#if defined(CHANNEL_AINPUT_CLIENT)
1793 flags |= AINPUT_FLAGS_REL;
1794 if (mflags & PTR_XFLAGS_DOWN)
1795 flags |= AINPUT_FLAGS_DOWN;
1796 if (mflags & PTR_XFLAGS_BUTTON1)
1797 flags |= AINPUT_XFLAGS_BUTTON1;
1798 if (mflags & PTR_XFLAGS_BUTTON2)
1799 flags |= AINPUT_XFLAGS_BUTTON2;
1801 handled = ainput_send_diff_event(cctx, flags, x, y);
1811 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1818 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1819 (UINT16)cctx->lastY);
1825static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
1828 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
1829 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
1830 WINPR_ASSERT(contact);
1831 WINPR_ASSERT(contact->x <= UINT16_MAX);
1832 WINPR_ASSERT(contact->y <= UINT16_MAX);
1834 switch (contact->count)
1837 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
1838 contact->x, contact->y);
1840 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
1841 contact->x, contact->y);
1843 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
1844 contact->x, contact->y);
1846 return freerdp_client_send_extended_button_event(
1847 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1849 return freerdp_client_send_extended_button_event(
1850 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
1857static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1860 WINPR_ASSERT(contact);
1862#if defined(CHANNEL_RDPEI_CLIENT)
1863 RdpeiClientContext* rdpei = cctx->rdpei;
1866 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1870 if (rdpei->TouchRawEvent)
1872 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1873 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1874 ? CONTACT_DATA_PRESSURE_PRESENT
1877 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1878 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1879 RDPINPUT_CONTACT_FLAG_INCONTACT,
1880 contactFlags, contact->pressure);
1881 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1882 contactFlags, contact->pressure);
1886 WINPR_ASSERT(rdpei->TouchEnd);
1887 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1891 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1892 "-DCHANNEL_RDPEI_CLIENT=ON");
1893 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
1897static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1900 WINPR_ASSERT(contact);
1902#if defined(CHANNEL_RDPEI_CLIENT)
1903 RdpeiClientContext* rdpei = cctx->rdpei;
1907 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1911 if (rdpei->TouchRawEvent)
1913 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1914 RDPINPUT_CONTACT_FLAG_INCONTACT;
1915 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1916 ? CONTACT_DATA_PRESSURE_PRESENT
1918 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1919 contactFlags, contact->pressure);
1923 WINPR_ASSERT(rdpei->TouchBegin);
1924 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1929 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1930 "-DCHANNEL_RDPEI_CLIENT=ON");
1931 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
1935static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
1938 const UINT16 flags = PTR_FLAGS_MOVE;
1940 WINPR_ASSERT(contact);
1941 WINPR_ASSERT(contact->x <= UINT16_MAX);
1942 WINPR_ASSERT(contact->y <= UINT16_MAX);
1943 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1946static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1949 WINPR_ASSERT(contact);
1951#if defined(CHANNEL_RDPEI_CLIENT)
1952 RdpeiClientContext* rdpei = cctx->rdpei;
1955 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
1959 if (rdpei->TouchRawEvent)
1961 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1962 RDPINPUT_CONTACT_FLAG_INCONTACT;
1963 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1964 ? CONTACT_DATA_PRESSURE_PRESENT
1966 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1967 contactFlags, contact->pressure);
1971 WINPR_ASSERT(rdpei->TouchUpdate);
1972 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1977 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1978 "-DCHANNEL_RDPEI_CLIENT=ON");
1979 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
1983static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
1984 UINT32 pressure, INT32 x, INT32 y,
1988 WINPR_ASSERT(pcontact);
1990 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
1994 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
1995 if (newcontact || (contact->id == touchId))
1997 contact->id = touchId;
1998 contact->flags = flags;
1999 contact->pressure = pressure;
2003 *pcontact = *contact;
2005 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2018BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2019 UINT32 pressure, INT32 x, INT32 y)
2021 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
2026 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2029 switch (flags & mask)
2031 case FREERDP_TOUCH_DOWN:
2032 return freerdp_handle_touch_down(cctx, &contact);
2033 case FREERDP_TOUCH_UP:
2034 return freerdp_handle_touch_up(cctx, &contact);
2035 case FREERDP_TOUCH_MOTION:
2036 return freerdp_handle_touch_motion(cctx, &contact);
2038 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %d, ignoring", flags);
2043BOOL freerdp_client_load_channels(freerdp* instance)
2045 WINPR_ASSERT(instance);
2046 WINPR_ASSERT(instance->context);
2048 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2050 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2056int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2058 const char* str_data = freerdp_get_logon_error_info_data(data);
2059 const char* str_type = freerdp_get_logon_error_info_type(type);
2061 if (!instance || !instance->context)
2064 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2068static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2073 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2076 if (deviceid == pen->deviceid)
2086static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2089 static const INT32 null_deviceid = 0;
2092 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2093 if (freerdp_client_is_pen(cctx, deviceid))
2095 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2106 pen->deviceid = deviceid;
2107 pen->max_pressure = pressure;
2110 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2114 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2118BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2120#if defined(CHANNEL_RDPEI_CLIENT)
2121 if ((flags & FREERDP_PEN_REGISTER) != 0)
2125 va_start(args, deviceid);
2126 double pressure = va_arg(args,
double);
2128 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2134 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2138 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2140 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2142 RdpeiClientContext* rdpei = cctx->rdpei;
2143 WINPR_ASSERT(rdpei);
2145 UINT32 normalizedpressure = 1024;
2148 UINT16 rotation = 0;
2152 va_start(args, deviceid);
2154 x = va_arg(args, INT32);
2155 y = va_arg(args, INT32);
2156 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2158 const double pressure = va_arg(args,
double);
2159 const double np = (pressure * 1024.0) / pen->max_pressure;
2160 normalizedpressure = (UINT32)lround(np);
2161 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2162 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2164 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2166 const unsigned arg = va_arg(args,
unsigned);
2167 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2168 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2170 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2172 const int arg = va_arg(args,
int);
2173 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2174 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2176 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2178 const int arg = va_arg(args,
int);
2179 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2180 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2184 if ((flags & FREERDP_PEN_PRESS) != 0)
2188 flags = FREERDP_PEN_MOTION |
2189 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2190 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2191 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2193 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2195 if (!pen->pressed ||
2196 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2197 flags = FREERDP_PEN_MOTION |
2198 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2200 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2203 flags |= pen->flags;
2204 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2205 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2206 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2207 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2211 if ((flags & FREERDP_PEN_PRESS) != 0)
2213 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2214 pen->hovering = FALSE;
2215 pen->pressed = TRUE;
2217 WINPR_ASSERT(rdpei->PenBegin);
2218 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2219 normalizedpressure, rotation, tiltX, tiltY);
2220 return rc == CHANNEL_RC_OK;
2222 else if ((flags & FREERDP_PEN_MOTION) != 0)
2224 UINT rc = ERROR_INTERNAL_ERROR;
2227 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2230 WINPR_ASSERT(rdpei->PenUpdate);
2231 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2232 rotation, tiltX, tiltY);
2234 else if (pen->hovering)
2236 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2238 WINPR_ASSERT(rdpei->PenHoverUpdate);
2239 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2240 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2244 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2245 pen->hovering = TRUE;
2247 WINPR_ASSERT(rdpei->PenHoverBegin);
2248 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2249 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2251 return rc == CHANNEL_RC_OK;
2253 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2255 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2256 pen->pressed = FALSE;
2257 pen->hovering = TRUE;
2259 WINPR_ASSERT(rdpei->PenUpdate);
2260 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2261 normalizedpressure, rotation, tiltX, tiltY);
2262 if (rc != CHANNEL_RC_OK)
2264 WINPR_ASSERT(rdpei->PenEnd);
2265 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2266 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2267 return re == CHANNEL_RC_OK;
2270 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2272 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2273 "-DCHANNEL_RDPEI_CLIENT=ON");
2279BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2283#if defined(CHANNEL_RDPEI_CLIENT)
2284 RdpeiClientContext* rdpei = cctx->rdpei;
2289 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2294 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2295 pen->hovering = FALSE;
2296 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2301 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2302 "-DCHANNEL_RDPEI_CLIENT=ON");
2307BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2314 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2317 if (pen->deviceid == deviceid)
2324BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2326 WINPR_ASSERT(ccontext);
2328 const rdpSettings* settings = ccontext->context.settings;
2331 BOOL ainput = FALSE;
2332#if defined(CHANNEL_AINPUT_CLIENT)
2333 ainput = ccontext->ainput != NULL;
2336 return useRelative && (haveRelative || ainput);
2339#if defined(WITH_AAD)
2340WINPR_ATTR_MALLOC(free, 1)
2341static
char* get_redirect_uri(const rdpSettings* settings)
2343 char* redirect_uri = NULL;
2347 const char* redirect_fmt =
2350 const char* tenantid =
"common";
2354 if (tenantid && redirect_fmt)
2359 size_t redirect_len = 0;
2360 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2366 const char* redirect_fmt =
2369 size_t redirect_len = 0;
2370 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2372 return redirect_uri;
2375static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2377 const rdpSettings* settings = cctx->context.settings;
2379 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2380 AAD_WELLKNOWN_authorization_endpoint);
2383 if (!client_id || !ep || !scope)
2386 char* redirect_uri = get_redirect_uri(settings);
2392 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2393 client_id, scope, redirect_uri);
2398static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2400 const rdpSettings* settings = cctx->context.settings;
2402 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2403 AAD_WELLKNOWN_authorization_endpoint);
2406 if (!client_id || !ep || !scope)
2409 char* redirect_uri = get_redirect_uri(settings);
2416 const char* code = va_arg(ap,
const char*);
2417 winpr_asprintf(&url, &urllen,
2418 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2419 code, client_id, scope, redirect_uri);
2424static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2426 const rdpSettings* settings = cctx->context.settings;
2429 char* redirect_uri = get_redirect_uri(settings);
2432 if (!client_id || !redirect_uri)
2434 const char* scope = va_arg(ap,
const char*);
2438 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2439 AAD_WELLKNOWN_authorization_endpoint);
2441 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2442 client_id, scope, redirect_uri);
2448static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2450 const rdpSettings* settings = cctx->context.settings;
2452 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2453 AAD_WELLKNOWN_authorization_endpoint);
2454 const char* scope = va_arg(ap,
const char*);
2455 const char* code = va_arg(ap,
const char*);
2456 const char* req_cnf = va_arg(ap,
const char*);
2458 if (!client_id || !ep || !scope || !code || !req_cnf)
2461 char* redirect_uri = get_redirect_uri(settings);
2470 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2471 code, client_id, scope, redirect_uri, req_cnf);
2477char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2486#if defined(WITH_AAD)
2487 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2488 str = aad_auth_request(cctx, ap);
2490 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2491 str = aad_token_request(cctx, ap);
2493 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2494 str = avd_auth_request(cctx, ap);
2496 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2497 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.