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_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);
460static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
461 char** password,
char** domain)
463 static const size_t password_size = 512;
464 const char* auth[] = {
"Username: ",
"Domain: ",
"Password: " };
465 const char* authPin[] = {
"Username: ",
"Domain: ",
"Smartcard-Pin: " };
466 const char* gw[] = {
"GatewayUsername: ",
"GatewayDomain: ",
"GatewayPassword: " };
467 const char** prompt = NULL;
468 BOOL pinOnly = FALSE;
470 WINPR_ASSERT(instance);
471 WINPR_ASSERT(instance->context);
472 WINPR_ASSERT(instance->context->settings);
476 case AUTH_SMARTCARD_PIN:
494 if (!username || !password || !domain)
497 if (!*username && !pinOnly)
499 size_t username_size = 0;
500 printf(
"%s", prompt[0]);
501 (void)fflush(stdout);
503 if (freerdp_interruptible_get_line(instance->context, username, &username_size, stdin) < 0)
505 char ebuffer[256] = { 0 };
506 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
507 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
513 *username = StrSep(username,
"\r");
514 *username = StrSep(username,
"\n");
518 if (!*domain && !pinOnly)
520 size_t domain_size = 0;
521 printf(
"%s", prompt[1]);
522 (void)fflush(stdout);
524 if (freerdp_interruptible_get_line(instance->context, domain, &domain_size, stdin) < 0)
526 char ebuffer[256] = { 0 };
527 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
528 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
534 *domain = StrSep(domain,
"\r");
535 *domain = StrSep(domain,
"\n");
541 *password = calloc(password_size,
sizeof(
char));
546 const BOOL fromStdin =
548 if (freerdp_passphrase_read(instance->context, prompt[2], *password, password_size,
564BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
565 rdp_auth_reason reason)
567 WINPR_ASSERT(instance);
568 WINPR_ASSERT(username);
569 WINPR_ASSERT(password);
570 WINPR_ASSERT(domain);
579 case AUTH_SMARTCARD_PIN:
580 if ((*username) && (*password))
591 return client_cli_authenticate_raw(instance, reason, username, password, domain);
594BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
595 DWORD count, DWORD* choice, BOOL gateway)
597 unsigned long answer = 0;
600 printf(
"Multiple smartcards are available for use:\n");
601 for (DWORD i = 0; i < count; i++)
604 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
605 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
608 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
609 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
610 cert->issuer, cert->upn);
613 free(container_name);
618 char input[10] = { 0 };
620 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
621 gateway ?
"gateway authentication" :
"logon", count - 1);
622 (void)fflush(stdout);
623 if (!fgets(input, 10, stdin))
625 WLog_ERR(TAG,
"could not read from stdin");
629 answer = strtoul(input, &p, 10);
630 if ((*p ==
'\n' && p != input) && answer < count)
632 *choice = (UINT32)answer;
638#if defined(WITH_FREERDP_DEPRECATED)
639BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
643 WLog_INFO(TAG,
"Authentication via smartcard");
647 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
650BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
652 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
656static DWORD client_cli_accept_certificate(freerdp* instance)
660 WINPR_ASSERT(instance);
661 WINPR_ASSERT(instance->context);
663 const rdpSettings* settings = instance->context->settings;
664 WINPR_ASSERT(settings);
672 printf(
"Do you trust the above certificate? (Y/T/N) ");
673 (void)fflush(stdout);
674 answer = freerdp_interruptible_getc(instance->context, stdin);
676 if ((answer == EOF) || feof(stdin))
678 printf(
"\nError: Could not read answer from stdin.\n");
686 answer = freerdp_interruptible_getc(instance->context, stdin);
693 answer = freerdp_interruptible_getc(instance->context, stdin);
700 answer = freerdp_interruptible_getc(instance->context, stdin);
726#if defined(WITH_FREERDP_DEPRECATED)
727DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
728 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
730 WINPR_UNUSED(common_name);
731 WINPR_UNUSED(host_mismatch);
733 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
734 printf(
"Certificate details:\n");
735 printf(
"\tSubject: %s\n", subject);
736 printf(
"\tIssuer: %s\n", issuer);
737 printf(
"\tThumbprint: %s\n", fingerprint);
738 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
739 "the CA certificate in your certificate store, or the certificate has expired.\n"
740 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
741 return client_cli_accept_certificate(instance);
745static char* client_cli_pem_cert(
const char* pem)
747 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
751 char* fp = freerdp_certificate_get_fingerprint(cert);
752 char* start = freerdp_certificate_get_validity(cert, TRUE);
753 char* end = freerdp_certificate_get_validity(cert, FALSE);
754 freerdp_certificate_free(cert);
758 winpr_asprintf(&str, &slen,
761 "\tThumbprint: %s\n",
784DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
785 const char* common_name,
const char* subject,
786 const char* issuer,
const char* fingerprint, DWORD flags)
788 const char* type =
"RDP-Server";
790 WINPR_ASSERT(instance);
791 WINPR_ASSERT(instance->context);
792 WINPR_ASSERT(instance->context->settings);
794 if (flags & VERIFY_CERT_FLAG_GATEWAY)
795 type =
"RDP-Gateway";
797 if (flags & VERIFY_CERT_FLAG_REDIRECT)
798 type =
"RDP-Redirect";
800 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
801 printf(
"\tCommon Name: %s\n", common_name);
802 printf(
"\tSubject: %s\n", subject);
803 printf(
"\tIssuer: %s\n", issuer);
807 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
809 char* str = client_cli_pem_cert(fingerprint);
814 printf(
"\tThumbprint: %s\n", fingerprint);
816 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
817 "the CA certificate in your certificate store, or the certificate has expired.\n"
818 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
819 return client_cli_accept_certificate(instance);
837#if defined(WITH_FREERDP_DEPRECATED)
838DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
839 const char* subject,
const char* issuer,
840 const char* fingerprint,
const char* old_subject,
841 const char* old_issuer,
const char* old_fingerprint)
843 WINPR_UNUSED(common_name);
845 printf(
"WARNING: This callback is deprecated, migrate to "
846 "client_cli_verify_changed_certificate_ex\n");
847 printf(
"!!! Certificate has changed !!!\n");
849 printf(
"New Certificate details:\n");
850 printf(
"\tSubject: %s\n", subject);
851 printf(
"\tIssuer: %s\n", issuer);
852 printf(
"\tThumbprint: %s\n", fingerprint);
854 printf(
"Old Certificate details:\n");
855 printf(
"\tSubject: %s\n", old_subject);
856 printf(
"\tIssuer: %s\n", old_issuer);
857 printf(
"\tThumbprint: %s\n", old_fingerprint);
859 printf(
"The above X.509 certificate does not match the certificate used for previous "
861 "This may indicate that the certificate has been tampered with.\n"
862 "Please contact the administrator of the RDP server and clarify.\n");
863 return client_cli_accept_certificate(instance);
886DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
887 const char* common_name,
const char* subject,
888 const char* issuer,
const char* fingerprint,
889 const char* old_subject,
const char* old_issuer,
890 const char* old_fingerprint, DWORD flags)
892 const char* type =
"RDP-Server";
894 WINPR_ASSERT(instance);
895 WINPR_ASSERT(instance->context);
896 WINPR_ASSERT(instance->context->settings);
898 if (flags & VERIFY_CERT_FLAG_GATEWAY)
899 type =
"RDP-Gateway";
901 if (flags & VERIFY_CERT_FLAG_REDIRECT)
902 type =
"RDP-Redirect";
904 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
906 printf(
"New Certificate details:\n");
907 printf(
"\tCommon Name: %s\n", common_name);
908 printf(
"\tSubject: %s\n", subject);
909 printf(
"\tIssuer: %s\n", issuer);
913 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
915 char* str = client_cli_pem_cert(fingerprint);
920 printf(
"\tThumbprint: %s\n", fingerprint);
922 printf(
"Old Certificate details:\n");
923 printf(
"\tSubject: %s\n", old_subject);
924 printf(
"\tIssuer: %s\n", old_issuer);
928 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
930 char* str = client_cli_pem_cert(old_fingerprint);
935 printf(
"\tThumbprint: %s\n", old_fingerprint);
937 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
939 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
940 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
941 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
942 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
945 printf(
"The above X.509 certificate does not match the certificate used for previous "
947 "This may indicate that the certificate has been tampered with.\n"
948 "Please contact the administrator of the RDP server and clarify.\n");
949 return client_cli_accept_certificate(instance);
952BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
953 BOOL isConsentMandatory,
size_t length,
954 const WCHAR* message)
957 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
959 WINPR_ASSERT(instance);
960 WINPR_ASSERT(instance->context);
961 WINPR_ASSERT(instance->context->settings);
963 if (!isDisplayMandatory && !isConsentMandatory)
966 printf(
"%s:\n", msgType);
968 printf(
"%.*S\n", (
int)length, message);
971 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR), NULL);
974 printf(
"Failed to convert message!\n");
982 while (isConsentMandatory)
984 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
985 (void)fflush(stdout);
986 answer = freerdp_interruptible_getc(instance->context, stdin);
988 if ((answer == EOF) || feof(stdin))
990 printf(
"\nError: Could not read answer from stdin.\n");
998 answer = freerdp_interruptible_getc(instance->context, stdin);
1005 (void)freerdp_interruptible_getc(instance->context, stdin);
1018static const char* extract_authorization_code(
char* url)
1022 for (
char* p = strchr(url,
'?'); p++ != NULL; p = strchr(p,
'&'))
1024 if (strncmp(p,
"code=", 5) != 0)
1030 end = strchr(p,
'&');
1040#if defined(WITH_AAD)
1041static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1042 const char* req_cnf,
char** token)
1044 WINPR_ASSERT(instance);
1045 WINPR_ASSERT(instance->context);
1049 char* token_request = NULL;
1051 WINPR_ASSERT(scope);
1052 WINPR_ASSERT(req_cnf);
1053 WINPR_ASSERT(token);
1058 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1059 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1061 printf(
"Browse to: %s\n", request);
1063 printf(
"Paste redirect URL here: \n");
1065 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1068 const char* code = extract_authorization_code(url);
1073 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1074 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1078 rc = client_common_get_access_token(instance, token_request, token);
1081 free(token_request);
1083 return rc && (*token != NULL);
1086static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1088 WINPR_ASSERT(instance);
1089 WINPR_ASSERT(instance->context);
1093 char* token_request = NULL;
1095 WINPR_ASSERT(token);
1101 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1102 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1105 printf(
"Browse to: %s\n", request);
1107 printf(
"Paste redirect URL here: \n");
1109 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1112 const char* code = extract_authorization_code(url);
1116 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1117 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1122 rc = client_common_get_access_token(instance, token_request, token);
1125 free(token_request);
1127 return rc && (*token != NULL);
1131BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1134 WINPR_ASSERT(instance);
1135 WINPR_ASSERT(token);
1137#if !defined(WITH_AAD)
1138 WLog_ERR(TAG,
"Build does not support AAD authentication");
1142 WINPR_ASSERT(instance->context);
1151 case ACCESS_TOKEN_TYPE_AAD:
1156 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1163 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1167 va_start(ap, count);
1168 const char* scope = va_arg(ap,
const char*);
1169 const char* req_cnf = va_arg(ap,
const char*);
1170 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1174 case ACCESS_TOKEN_TYPE_AVD:
1177 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1180 rc = client_cli_get_avd_access_token(instance, token);
1183 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%" PRIuz
"], aborting", tokenType);
1194BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1197 WINPR_ASSERT(request);
1198 WINPR_ASSERT(token);
1202 BYTE* response = NULL;
1203 size_t response_length = 0;
1205 wLog* log = WLog_Get(TAG);
1207 const char* token_ep =
1208 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1209 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1211 WLog_ERR(TAG,
"access token request failed");
1215 if (resp_code != HTTP_STATUS_OK)
1217 char buffer[64] = { 0 };
1219 WLog_Print(log, WLOG_ERROR,
1220 "Server unwilling to provide access token; returned status code %s",
1221 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1222 if (response_length > 0)
1223 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1227 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1239SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1242 WINPR_UNUSED(instance);
1243 WINPR_ASSERT(instance->context);
1244 WINPR_UNUSED(userarg);
1245 WINPR_ASSERT(instance);
1248 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1250 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1256 if (strcmp(what,
"arm-transport") == 0)
1257 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1260 const rdpSettings* settings = instance->context->settings;
1264 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1273 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1274 "tech support for help if this keeps happening.",
1279 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1280 what, current, max, delay);
1281 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1284BOOL client_auto_reconnect(freerdp* instance)
1286 return client_auto_reconnect_ex(instance, NULL);
1289BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1293 UINT32 numRetries = 0;
1294 rdpSettings* settings = NULL;
1299 WINPR_ASSERT(instance->context);
1301 settings = instance->context->settings;
1302 WINPR_ASSERT(settings);
1304 const UINT32 maxRetries =
1308 error = freerdp_error_info(instance);
1311 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1313 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1314 freerdp_get_error_info_string(error));
1316 case ERRINFO_SUCCESS:
1318 WLog_INFO(TAG,
"Network disconnect!");
1330 switch (freerdp_get_last_error(instance->context))
1332 case FREERDP_ERROR_CONNECT_CANCELLED:
1333 WLog_WARN(TAG,
"Connection aborted by user");
1343 if ((maxRetries > 0) && (numRetries++ >= maxRetries))
1349 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1351 IFCALL(instance->RetryDialog, instance,
"connection", numRetries, NULL);
1353 if (freerdp_reconnect(instance))
1356 switch (freerdp_get_last_error(instance->context))
1358 case FREERDP_ERROR_CONNECT_CANCELLED:
1359 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1364 for (UINT32 x = 0; x < 50; x++)
1366 if (!IFCALLRESULT(TRUE, window_events, instance))
1373 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1377int freerdp_client_common_stop(rdpContext* context)
1379 rdpClientContext* cctx = (rdpClientContext*)context;
1382 freerdp_abort_connect_context(&cctx->context);
1386 (void)WaitForSingleObject(cctx->thread, INFINITE);
1387 (void)CloseHandle(cctx->thread);
1388 cctx->thread = NULL;
1394#if defined(CHANNEL_ENCOMSP_CLIENT)
1395BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1397 rdpClientContext* cctx = NULL;
1403 cctx = (rdpClientContext*)encomsp->custom;
1405 state = cctx->controlToggle;
1406 cctx->controlToggle = !cctx->controlToggle;
1407 return freerdp_client_encomsp_set_control(encomsp, state);
1410BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1417 pdu.ParticipantId = encomsp->participantId;
1418 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1421 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1423 encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1429client_encomsp_participant_created(EncomspClientContext* context,
1432 rdpClientContext* cctx = NULL;
1433 rdpSettings* settings = NULL;
1436 if (!context || !context->custom || !participantCreated)
1437 return ERROR_INVALID_PARAMETER;
1439 cctx = (rdpClientContext*)context->custom;
1442 settings = cctx->context.settings;
1443 WINPR_ASSERT(settings);
1445 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1446 context->participantId = participantCreated->ParticipantId;
1449 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1450 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1452 if (!freerdp_client_encomsp_set_control(context, TRUE))
1453 return ERROR_INTERNAL_ERROR;
1459 return ERROR_INTERNAL_ERROR;
1462 return CHANNEL_RC_OK;
1465static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1467 cctx->encomsp = encomsp;
1468 encomsp->custom = (
void*)cctx;
1469 encomsp->ParticipantCreated = client_encomsp_participant_created;
1472static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1476 encomsp->custom = NULL;
1477 encomsp->ParticipantCreated = NULL;
1481 cctx->encomsp = NULL;
1485void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1486 const ChannelConnectedEventArgs* e)
1488 rdpClientContext* cctx = (rdpClientContext*)context;
1496#if defined(CHANNEL_AINPUT_CLIENT)
1497 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1498 cctx->ainput = (AInputClientContext*)e->pInterface;
1500#if defined(CHANNEL_RDPEI_CLIENT)
1501 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1503 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1506#if defined(CHANNEL_RDPGFX_CLIENT)
1507 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1509 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1512#if defined(CHANNEL_GEOMETRY_CLIENT)
1513 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1515 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1518#if defined(CHANNEL_VIDEO_CLIENT)
1519 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1521 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1523 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1525 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1528#if defined(CHANNEL_ENCOMSP_CLIENT)
1529 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1531 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1536void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1537 const ChannelDisconnectedEventArgs* e)
1539 rdpClientContext* cctx = (rdpClientContext*)context;
1547#if defined(CHANNEL_AINPUT_CLIENT)
1548 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1549 cctx->ainput = NULL;
1551#if defined(CHANNEL_RDPEI_CLIENT)
1552 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1557#if defined(CHANNEL_RDPGFX_CLIENT)
1558 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1560 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1563#if defined(CHANNEL_GEOMETRY_CLIENT)
1564 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1566 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1569#if defined(CHANNEL_VIDEO_CLIENT)
1570 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1572 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1574 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1576 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1579#if defined(CHANNEL_ENCOMSP_CLIENT)
1580 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1582 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1587BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1589 BOOL handled = FALSE;
1593#if defined(CHANNEL_AINPUT_CLIENT)
1600 INT32 value = mflags & 0xFF;
1602 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1603 value = -1 * (0x100 - value);
1609 if (mflags & PTR_FLAGS_WHEEL)
1611 flags |= AINPUT_FLAGS_WHEEL;
1615 if (mflags & PTR_FLAGS_HWHEEL)
1617 flags |= AINPUT_FLAGS_WHEEL;
1621 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1622 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1623 if (rc == CHANNEL_RC_OK)
1629 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1634#if defined(CHANNEL_AINPUT_CLIENT)
1635static INLINE BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1640 WINPR_ASSERT(cctx->ainput);
1641 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1643 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1645 return rc == CHANNEL_RC_OK;
1649BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1652 BOOL handled = FALSE;
1656 const BOOL haveRelative =
1658 if (relative && haveRelative)
1660 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1661 WINPR_ASSERTING_INT_CAST(int16_t, x),
1662 WINPR_ASSERTING_INT_CAST(int16_t, y));
1665#if defined(CHANNEL_AINPUT_CLIENT)
1670 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1671 flags |= AINPUT_FLAGS_HAVE_REL;
1674 flags |= AINPUT_FLAGS_REL;
1676 if (mflags & PTR_FLAGS_DOWN)
1677 flags |= AINPUT_FLAGS_DOWN;
1678 if (mflags & PTR_FLAGS_BUTTON1)
1679 flags |= AINPUT_FLAGS_BUTTON1;
1680 if (mflags & PTR_FLAGS_BUTTON2)
1681 flags |= AINPUT_FLAGS_BUTTON2;
1682 if (mflags & PTR_FLAGS_BUTTON3)
1683 flags |= AINPUT_FLAGS_BUTTON3;
1684 if (mflags & PTR_FLAGS_MOVE)
1685 flags |= AINPUT_FLAGS_MOVE;
1686 handled = ainput_send_diff_event(cctx, flags, x, y);
1696 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1703 freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1704 (UINT16)cctx->lastY);
1709BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1712 BOOL handled = FALSE;
1715 const BOOL haveRelative =
1717 if (relative && haveRelative)
1719 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1720 WINPR_ASSERTING_INT_CAST(int16_t, x),
1721 WINPR_ASSERTING_INT_CAST(int16_t, y));
1724#if defined(CHANNEL_AINPUT_CLIENT)
1730 flags |= AINPUT_FLAGS_REL;
1731 if (mflags & PTR_XFLAGS_DOWN)
1732 flags |= AINPUT_FLAGS_DOWN;
1733 if (mflags & PTR_XFLAGS_BUTTON1)
1734 flags |= AINPUT_XFLAGS_BUTTON1;
1735 if (mflags & PTR_XFLAGS_BUTTON2)
1736 flags |= AINPUT_XFLAGS_BUTTON2;
1738 handled = ainput_send_diff_event(cctx, flags, x, y);
1748 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1755 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1756 (UINT16)cctx->lastY);
1762static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1765 WINPR_ASSERT(contact);
1767#if defined(CHANNEL_RDPEI_CLIENT)
1768 RdpeiClientContext* rdpei = cctx->rdpei;
1773 flags |= PTR_FLAGS_BUTTON1;
1775 WINPR_ASSERT(contact->x <= UINT16_MAX);
1776 WINPR_ASSERT(contact->y <= UINT16_MAX);
1777 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1783 if (rdpei->TouchRawEvent)
1785 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1786 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1787 ? CONTACT_DATA_PRESSURE_PRESENT
1790 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1791 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1792 RDPINPUT_CONTACT_FLAG_INCONTACT,
1793 contactFlags, contact->pressure);
1794 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1795 contactFlags, contact->pressure);
1799 WINPR_ASSERT(rdpei->TouchEnd);
1800 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1804 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1805 "-DWITH_CHANNELS=ON");
1811static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1814 WINPR_ASSERT(contact);
1816#if defined(CHANNEL_RDPEI_CLIENT)
1817 RdpeiClientContext* rdpei = cctx->rdpei;
1823 flags |= PTR_FLAGS_DOWN;
1824 flags |= PTR_FLAGS_MOVE;
1825 flags |= PTR_FLAGS_BUTTON1;
1827 WINPR_ASSERT(contact->x <= UINT16_MAX);
1828 WINPR_ASSERT(contact->y <= UINT16_MAX);
1829 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1835 if (rdpei->TouchRawEvent)
1837 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1838 RDPINPUT_CONTACT_FLAG_INCONTACT;
1839 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1840 ? CONTACT_DATA_PRESSURE_PRESENT
1842 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1843 contactFlags, contact->pressure);
1847 WINPR_ASSERT(rdpei->TouchBegin);
1848 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1852 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1853 "-DWITH_CHANNELS=ON");
1859static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1862 WINPR_ASSERT(contact);
1864#if defined(CHANNEL_RDPEI_CLIENT)
1865 RdpeiClientContext* rdpei = cctx->rdpei;
1870 flags |= PTR_FLAGS_MOVE;
1872 WINPR_ASSERT(contact->x <= UINT16_MAX);
1873 WINPR_ASSERT(contact->y <= UINT16_MAX);
1874 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1880 if (rdpei->TouchRawEvent)
1882 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1883 RDPINPUT_CONTACT_FLAG_INCONTACT;
1884 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1885 ? CONTACT_DATA_PRESSURE_PRESENT
1887 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1888 contactFlags, contact->pressure);
1892 WINPR_ASSERT(rdpei->TouchUpdate);
1893 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1897 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1898 "-DWITH_CHANNELS=ON");
1904static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
1905 UINT32 pressure, INT32 x, INT32 y,
1909 WINPR_ASSERT(pcontact);
1911 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
1915 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
1916 if (newcontact || (contact->id == touchId))
1918 contact->id = touchId;
1919 contact->flags = flags;
1920 contact->pressure = pressure;
1924 *pcontact = *contact;
1926 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
1939BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
1940 UINT32 pressure, INT32 x, INT32 y)
1942 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
1947 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
1950 switch (flags & mask)
1952 case FREERDP_TOUCH_DOWN:
1953 return freerdp_handle_touch_down(cctx, &contact);
1954 case FREERDP_TOUCH_UP:
1955 return freerdp_handle_touch_up(cctx, &contact);
1956 case FREERDP_TOUCH_MOTION:
1957 return freerdp_handle_touch_motion(cctx, &contact);
1959 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %d, ignoring", flags);
1964BOOL freerdp_client_load_channels(freerdp* instance)
1966 WINPR_ASSERT(instance);
1967 WINPR_ASSERT(instance->context);
1969 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
1971 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
1977int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
1979 const char* str_data = freerdp_get_logon_error_info_data(data);
1980 const char* str_type = freerdp_get_logon_error_info_type(type);
1982 if (!instance || !instance->context)
1985 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
1989static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
1994 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
1997 if (deviceid == pen->deviceid)
2007static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2010 static const INT32 null_deviceid = 0;
2013 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2014 if (freerdp_client_is_pen(cctx, deviceid))
2016 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2027 pen->deviceid = deviceid;
2028 pen->max_pressure = pressure;
2031 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2035 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2039BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2041 if ((flags & FREERDP_PEN_REGISTER) != 0)
2045 va_start(args, deviceid);
2046 double pressure = va_arg(args,
double);
2048 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2054 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2058 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2060 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2062 RdpeiClientContext* rdpei = cctx->rdpei;
2063 WINPR_ASSERT(rdpei);
2065 UINT32 normalizedpressure = 1024;
2068 UINT16 rotation = 0;
2072 va_start(args, deviceid);
2074 x = va_arg(args, INT32);
2075 y = va_arg(args, INT32);
2076 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2078 const double pressure = va_arg(args,
double);
2079 const double np = (pressure * 1024.0) / pen->max_pressure;
2080 normalizedpressure = (UINT32)lround(np);
2081 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2082 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2084 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2086 const unsigned arg = va_arg(args,
unsigned);
2087 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2088 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2090 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2092 const int arg = va_arg(args,
int);
2093 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2094 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2096 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2098 const int arg = va_arg(args,
int);
2099 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2100 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2104 if ((flags & FREERDP_PEN_PRESS) != 0)
2108 flags = FREERDP_PEN_MOTION |
2109 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2110 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2111 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2113 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2115 if (!pen->pressed ||
2116 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2117 flags = FREERDP_PEN_MOTION |
2118 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2120 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2123 flags |= pen->flags;
2124 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2125 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2126 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2127 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2131 if ((flags & FREERDP_PEN_PRESS) != 0)
2133 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2134 pen->hovering = FALSE;
2135 pen->pressed = TRUE;
2137 WINPR_ASSERT(rdpei->PenBegin);
2138 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2139 normalizedpressure, rotation, tiltX, tiltY);
2140 return rc == CHANNEL_RC_OK;
2142 else if ((flags & FREERDP_PEN_MOTION) != 0)
2144 UINT rc = ERROR_INTERNAL_ERROR;
2147 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2150 WINPR_ASSERT(rdpei->PenUpdate);
2151 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2152 rotation, tiltX, tiltY);
2154 else if (pen->hovering)
2156 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2158 WINPR_ASSERT(rdpei->PenHoverUpdate);
2159 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2160 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2164 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2165 pen->hovering = TRUE;
2167 WINPR_ASSERT(rdpei->PenHoverBegin);
2168 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2169 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2171 return rc == CHANNEL_RC_OK;
2173 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2175 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2176 pen->pressed = FALSE;
2177 pen->hovering = TRUE;
2179 WINPR_ASSERT(rdpei->PenUpdate);
2180 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2181 normalizedpressure, rotation, tiltX, tiltY);
2182 if (rc != CHANNEL_RC_OK)
2184 WINPR_ASSERT(rdpei->PenEnd);
2185 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2186 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2187 return re == CHANNEL_RC_OK;
2190 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2194BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2198 RdpeiClientContext* rdpei = cctx->rdpei;
2203 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2208 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2209 pen->hovering = FALSE;
2210 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2216BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2223 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2226 if (pen->deviceid == deviceid)
2233BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2235 WINPR_ASSERT(ccontext);
2237 const rdpSettings* settings = ccontext->context.settings;
2240 BOOL ainput = FALSE;
2241#if defined(CHANNEL_AINPUT_CLIENT)
2242 ainput = ccontext->ainput != NULL;
2245 return useRelative && (haveRelative || ainput);
2248#if defined(WITH_AAD)
2249WINPR_ATTR_MALLOC(free, 1)
2250static
char* get_redirect_uri(const rdpSettings* settings)
2252 char* redirect_uri = NULL;
2256 const char* redirect_fmt =
2259 const char* tenantid =
"common";
2263 if (tenantid && redirect_fmt)
2268 size_t redirect_len = 0;
2269 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2275 const char* redirect_fmt =
2278 size_t redirect_len = 0;
2279 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2281 return redirect_uri;
2284static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2286 const rdpSettings* settings = cctx->context.settings;
2288 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2289 AAD_WELLKNOWN_authorization_endpoint);
2292 if (!client_id || !ep || !scope)
2295 char* redirect_uri = get_redirect_uri(settings);
2301 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2302 client_id, scope, redirect_uri);
2307static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2309 const rdpSettings* settings = cctx->context.settings;
2311 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2312 AAD_WELLKNOWN_authorization_endpoint);
2315 if (!client_id || !ep || !scope)
2318 char* redirect_uri = get_redirect_uri(settings);
2325 const char* code = va_arg(ap,
const char*);
2326 winpr_asprintf(&url, &urllen,
2327 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2328 code, client_id, scope, redirect_uri);
2333static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2335 const rdpSettings* settings = cctx->context.settings;
2338 char* redirect_uri = get_redirect_uri(settings);
2341 if (!client_id || !redirect_uri)
2343 const char* scope = va_arg(ap,
const char*);
2347 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2348 AAD_WELLKNOWN_authorization_endpoint);
2350 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2351 client_id, scope, redirect_uri);
2357static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2359 const rdpSettings* settings = cctx->context.settings;
2361 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2362 AAD_WELLKNOWN_authorization_endpoint);
2363 const char* scope = va_arg(ap,
const char*);
2364 const char* code = va_arg(ap,
const char*);
2365 const char* req_cnf = va_arg(ap,
const char*);
2367 if (!client_id || !ep || !scope || !code || !req_cnf)
2370 char* redirect_uri = get_redirect_uri(settings);
2379 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2380 code, client_id, scope, redirect_uri, req_cnf);
2386char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2395#if defined(WITH_AAD)
2396 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2397 str = aad_auth_request(cctx, ap);
2399 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2400 str = aad_token_request(cctx, ap);
2402 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2403 str = avd_auth_request(cctx, ap);
2405 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2406 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.