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;
1649static bool button_pressed(
const rdpClientContext* cctx)
1652 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1654 const BOOL cur = cctx->pressed_buttons[x];
1661BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1664 BOOL handled = FALSE;
1668 if (mflags & PTR_FLAGS_BUTTON1)
1669 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1670 if (mflags & PTR_FLAGS_BUTTON2)
1671 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1672 if (mflags & PTR_FLAGS_BUTTON3)
1673 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1675 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1678 if (!button_pressed(cctx))
1682 const BOOL haveRelative =
1684 if (relative && haveRelative)
1686 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1687 WINPR_ASSERTING_INT_CAST(int16_t, x),
1688 WINPR_ASSERTING_INT_CAST(int16_t, y));
1691#if defined(CHANNEL_AINPUT_CLIENT)
1696 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1697 flags |= AINPUT_FLAGS_HAVE_REL;
1700 flags |= AINPUT_FLAGS_REL;
1702 if (mflags & PTR_FLAGS_DOWN)
1703 flags |= AINPUT_FLAGS_DOWN;
1704 if (mflags & PTR_FLAGS_BUTTON1)
1705 flags |= AINPUT_FLAGS_BUTTON1;
1706 if (mflags & PTR_FLAGS_BUTTON2)
1707 flags |= AINPUT_FLAGS_BUTTON2;
1708 if (mflags & PTR_FLAGS_BUTTON3)
1709 flags |= AINPUT_FLAGS_BUTTON3;
1710 if (mflags & PTR_FLAGS_MOVE)
1711 flags |= AINPUT_FLAGS_MOVE;
1712 handled = ainput_send_diff_event(cctx, flags, x, y);
1722 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1729 freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1730 (UINT16)cctx->lastY);
1735BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1738 BOOL handled = FALSE;
1741 if (mflags & PTR_XFLAGS_BUTTON1)
1742 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1743 if (mflags & PTR_XFLAGS_BUTTON2)
1744 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1746 const BOOL haveRelative =
1748 if (relative && haveRelative)
1750 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1751 WINPR_ASSERTING_INT_CAST(int16_t, x),
1752 WINPR_ASSERTING_INT_CAST(int16_t, y));
1755#if defined(CHANNEL_AINPUT_CLIENT)
1761 flags |= AINPUT_FLAGS_REL;
1762 if (mflags & PTR_XFLAGS_DOWN)
1763 flags |= AINPUT_FLAGS_DOWN;
1764 if (mflags & PTR_XFLAGS_BUTTON1)
1765 flags |= AINPUT_XFLAGS_BUTTON1;
1766 if (mflags & PTR_XFLAGS_BUTTON2)
1767 flags |= AINPUT_XFLAGS_BUTTON2;
1769 handled = ainput_send_diff_event(cctx, flags, x, y);
1779 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1786 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1787 (UINT16)cctx->lastY);
1793static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1796 WINPR_ASSERT(contact);
1798#if defined(CHANNEL_RDPEI_CLIENT)
1799 RdpeiClientContext* rdpei = cctx->rdpei;
1804 flags |= PTR_FLAGS_BUTTON1;
1806 WINPR_ASSERT(contact->x <= UINT16_MAX);
1807 WINPR_ASSERT(contact->y <= UINT16_MAX);
1808 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1814 if (rdpei->TouchRawEvent)
1816 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1817 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1818 ? CONTACT_DATA_PRESSURE_PRESENT
1821 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1822 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1823 RDPINPUT_CONTACT_FLAG_INCONTACT,
1824 contactFlags, contact->pressure);
1825 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1826 contactFlags, contact->pressure);
1830 WINPR_ASSERT(rdpei->TouchEnd);
1831 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1835 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1836 "-DWITH_CHANNELS=ON");
1842static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1845 WINPR_ASSERT(contact);
1847#if defined(CHANNEL_RDPEI_CLIENT)
1848 RdpeiClientContext* rdpei = cctx->rdpei;
1854 flags |= PTR_FLAGS_DOWN;
1855 flags |= PTR_FLAGS_MOVE;
1856 flags |= PTR_FLAGS_BUTTON1;
1858 WINPR_ASSERT(contact->x <= UINT16_MAX);
1859 WINPR_ASSERT(contact->y <= UINT16_MAX);
1860 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1866 if (rdpei->TouchRawEvent)
1868 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1869 RDPINPUT_CONTACT_FLAG_INCONTACT;
1870 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1871 ? CONTACT_DATA_PRESSURE_PRESENT
1873 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1874 contactFlags, contact->pressure);
1878 WINPR_ASSERT(rdpei->TouchBegin);
1879 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1883 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1884 "-DWITH_CHANNELS=ON");
1890static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1893 WINPR_ASSERT(contact);
1895#if defined(CHANNEL_RDPEI_CLIENT)
1896 RdpeiClientContext* rdpei = cctx->rdpei;
1901 flags |= PTR_FLAGS_MOVE;
1903 WINPR_ASSERT(contact->x <= UINT16_MAX);
1904 WINPR_ASSERT(contact->y <= UINT16_MAX);
1905 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1911 if (rdpei->TouchRawEvent)
1913 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | 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->TouchUpdate);
1924 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1928 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1929 "-DWITH_CHANNELS=ON");
1935static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
1936 UINT32 pressure, INT32 x, INT32 y,
1940 WINPR_ASSERT(pcontact);
1942 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
1946 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
1947 if (newcontact || (contact->id == touchId))
1949 contact->id = touchId;
1950 contact->flags = flags;
1951 contact->pressure = pressure;
1955 *pcontact = *contact;
1957 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
1970BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
1971 UINT32 pressure, INT32 x, INT32 y)
1973 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
1978 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
1981 switch (flags & mask)
1983 case FREERDP_TOUCH_DOWN:
1984 return freerdp_handle_touch_down(cctx, &contact);
1985 case FREERDP_TOUCH_UP:
1986 return freerdp_handle_touch_up(cctx, &contact);
1987 case FREERDP_TOUCH_MOTION:
1988 return freerdp_handle_touch_motion(cctx, &contact);
1990 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %d, ignoring", flags);
1995BOOL freerdp_client_load_channels(freerdp* instance)
1997 WINPR_ASSERT(instance);
1998 WINPR_ASSERT(instance->context);
2000 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2002 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2008int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2010 const char* str_data = freerdp_get_logon_error_info_data(data);
2011 const char* str_type = freerdp_get_logon_error_info_type(type);
2013 if (!instance || !instance->context)
2016 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2020static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2025 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2028 if (deviceid == pen->deviceid)
2038static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2041 static const INT32 null_deviceid = 0;
2044 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2045 if (freerdp_client_is_pen(cctx, deviceid))
2047 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2058 pen->deviceid = deviceid;
2059 pen->max_pressure = pressure;
2062 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2066 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2070BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2072 if ((flags & FREERDP_PEN_REGISTER) != 0)
2076 va_start(args, deviceid);
2077 double pressure = va_arg(args,
double);
2079 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2085 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2089 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2091 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2093 RdpeiClientContext* rdpei = cctx->rdpei;
2094 WINPR_ASSERT(rdpei);
2096 UINT32 normalizedpressure = 1024;
2099 UINT16 rotation = 0;
2103 va_start(args, deviceid);
2105 x = va_arg(args, INT32);
2106 y = va_arg(args, INT32);
2107 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2109 const double pressure = va_arg(args,
double);
2110 const double np = (pressure * 1024.0) / pen->max_pressure;
2111 normalizedpressure = (UINT32)lround(np);
2112 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2113 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2115 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2117 const unsigned arg = va_arg(args,
unsigned);
2118 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2119 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2121 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2123 const int arg = va_arg(args,
int);
2124 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2125 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2127 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2129 const int arg = va_arg(args,
int);
2130 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2131 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2135 if ((flags & FREERDP_PEN_PRESS) != 0)
2139 flags = FREERDP_PEN_MOTION |
2140 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2141 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2142 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2144 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2146 if (!pen->pressed ||
2147 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2148 flags = FREERDP_PEN_MOTION |
2149 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2151 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2154 flags |= pen->flags;
2155 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2156 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2157 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2158 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2162 if ((flags & FREERDP_PEN_PRESS) != 0)
2164 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2165 pen->hovering = FALSE;
2166 pen->pressed = TRUE;
2168 WINPR_ASSERT(rdpei->PenBegin);
2169 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2170 normalizedpressure, rotation, tiltX, tiltY);
2171 return rc == CHANNEL_RC_OK;
2173 else if ((flags & FREERDP_PEN_MOTION) != 0)
2175 UINT rc = ERROR_INTERNAL_ERROR;
2178 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2181 WINPR_ASSERT(rdpei->PenUpdate);
2182 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2183 rotation, tiltX, tiltY);
2185 else if (pen->hovering)
2187 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2189 WINPR_ASSERT(rdpei->PenHoverUpdate);
2190 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2191 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2195 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2196 pen->hovering = TRUE;
2198 WINPR_ASSERT(rdpei->PenHoverBegin);
2199 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2200 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2202 return rc == CHANNEL_RC_OK;
2204 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2206 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2207 pen->pressed = FALSE;
2208 pen->hovering = TRUE;
2210 WINPR_ASSERT(rdpei->PenUpdate);
2211 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2212 normalizedpressure, rotation, tiltX, tiltY);
2213 if (rc != CHANNEL_RC_OK)
2215 WINPR_ASSERT(rdpei->PenEnd);
2216 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2217 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2218 return re == CHANNEL_RC_OK;
2221 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2225BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2229 RdpeiClientContext* rdpei = cctx->rdpei;
2234 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2239 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2240 pen->hovering = FALSE;
2241 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2247BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2254 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2257 if (pen->deviceid == deviceid)
2264BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2266 WINPR_ASSERT(ccontext);
2268 const rdpSettings* settings = ccontext->context.settings;
2271 BOOL ainput = FALSE;
2272#if defined(CHANNEL_AINPUT_CLIENT)
2273 ainput = ccontext->ainput != NULL;
2276 return useRelative && (haveRelative || ainput);
2279#if defined(WITH_AAD)
2280WINPR_ATTR_MALLOC(free, 1)
2281static
char* get_redirect_uri(const rdpSettings* settings)
2283 char* redirect_uri = NULL;
2287 const char* redirect_fmt =
2290 const char* tenantid =
"common";
2294 if (tenantid && redirect_fmt)
2299 size_t redirect_len = 0;
2300 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2306 const char* redirect_fmt =
2309 size_t redirect_len = 0;
2310 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2312 return redirect_uri;
2315static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2317 const rdpSettings* settings = cctx->context.settings;
2319 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2320 AAD_WELLKNOWN_authorization_endpoint);
2323 if (!client_id || !ep || !scope)
2326 char* redirect_uri = get_redirect_uri(settings);
2332 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2333 client_id, scope, redirect_uri);
2338static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2340 const rdpSettings* settings = cctx->context.settings;
2342 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2343 AAD_WELLKNOWN_authorization_endpoint);
2346 if (!client_id || !ep || !scope)
2349 char* redirect_uri = get_redirect_uri(settings);
2356 const char* code = va_arg(ap,
const char*);
2357 winpr_asprintf(&url, &urllen,
2358 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2359 code, client_id, scope, redirect_uri);
2364static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2366 const rdpSettings* settings = cctx->context.settings;
2369 char* redirect_uri = get_redirect_uri(settings);
2372 if (!client_id || !redirect_uri)
2374 const char* scope = va_arg(ap,
const char*);
2378 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2379 AAD_WELLKNOWN_authorization_endpoint);
2381 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2382 client_id, scope, redirect_uri);
2388static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2390 const rdpSettings* settings = cctx->context.settings;
2392 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2393 AAD_WELLKNOWN_authorization_endpoint);
2394 const char* scope = va_arg(ap,
const char*);
2395 const char* code = va_arg(ap,
const char*);
2396 const char* req_cnf = va_arg(ap,
const char*);
2398 if (!client_id || !ep || !scope || !code || !req_cnf)
2401 char* redirect_uri = get_redirect_uri(settings);
2410 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2411 code, client_id, scope, redirect_uri, req_cnf);
2417char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2426#if defined(WITH_AAD)
2427 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2428 str = aad_auth_request(cctx, ap);
2430 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2431 str = aad_token_request(cctx, ap);
2433 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2434 str = avd_auth_request(cctx, ap);
2436 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2437 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.