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;
1050 char* redirect_uri = NULL;
1051 size_t redirec_uri_len = 0;
1053 WINPR_ASSERT(scope);
1054 WINPR_ASSERT(req_cnf);
1055 WINPR_ASSERT(token);
1060 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1061 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1063 printf(
"Browse to: %s\n", request);
1065 printf(
"Paste redirect URL here: \n");
1067 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1070 const char* code = extract_authorization_code(url);
1075 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1076 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1080 rc = client_common_get_access_token(instance, token_request, token);
1084 free(token_request);
1086 return rc && (*token != NULL);
1089static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1091 WINPR_ASSERT(instance);
1092 WINPR_ASSERT(instance->context);
1096 char* token_request = NULL;
1097 char* redirect_uri = NULL;
1099 WINPR_ASSERT(token);
1105 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1106 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1109 printf(
"Browse to: %s\n", request);
1111 printf(
"Paste redirect URL here: \n");
1113 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1116 const char* code = extract_authorization_code(url);
1120 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1121 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1126 rc = client_common_get_access_token(instance, token_request, token);
1130 free(token_request);
1132 return rc && (*token != NULL);
1136BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1139 WINPR_ASSERT(instance);
1140 WINPR_ASSERT(token);
1142#if !defined(WITH_AAD)
1143 WLog_ERR(TAG,
"Build does not support AAD authentication");
1148 case ACCESS_TOKEN_TYPE_AAD:
1153 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1160 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1164 va_start(ap, count);
1165 const char* scope = va_arg(ap,
const char*);
1166 const char* req_cnf = va_arg(ap,
const char*);
1167 BOOL rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1171 case ACCESS_TOKEN_TYPE_AVD:
1174 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1177 return client_cli_get_avd_access_token(instance, token);
1179 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%" PRIuz
"], aborting", tokenType);
1185BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1188 WINPR_ASSERT(request);
1189 WINPR_ASSERT(token);
1193 BYTE* response = NULL;
1194 size_t response_length = 0;
1196 wLog* log = WLog_Get(TAG);
1198 const char* token_ep =
1199 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1200 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1202 WLog_ERR(TAG,
"access token request failed");
1206 if (resp_code != HTTP_STATUS_OK)
1208 char buffer[64] = { 0 };
1210 WLog_Print(log, WLOG_ERROR,
1211 "Server unwilling to provide access token; returned status code %s",
1212 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1213 if (response_length > 0)
1214 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1218 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1230SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1233 WINPR_UNUSED(instance);
1234 WINPR_ASSERT(instance->context);
1235 WINPR_UNUSED(userarg);
1236 WINPR_ASSERT(instance);
1239 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1241 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1247 if (strcmp(what,
"arm-transport") == 0)
1248 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1251 const rdpSettings* settings = instance->context->settings;
1255 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1264 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1265 "tech support for help if this keeps happening.",
1270 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1271 what, current, max, delay);
1272 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1275BOOL client_auto_reconnect(freerdp* instance)
1277 return client_auto_reconnect_ex(instance, NULL);
1280BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1284 UINT32 numRetries = 0;
1285 rdpSettings* settings = NULL;
1290 WINPR_ASSERT(instance->context);
1292 settings = instance->context->settings;
1293 WINPR_ASSERT(settings);
1295 const UINT32 maxRetries =
1299 error = freerdp_error_info(instance);
1302 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1304 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1305 freerdp_get_error_info_string(error));
1307 case ERRINFO_SUCCESS:
1309 WLog_INFO(TAG,
"Network disconnect!");
1321 switch (freerdp_get_last_error(instance->context))
1323 case FREERDP_ERROR_CONNECT_CANCELLED:
1324 WLog_WARN(TAG,
"Connection aborted by user");
1334 if ((maxRetries > 0) && (numRetries++ >= maxRetries))
1340 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1342 IFCALL(instance->RetryDialog, instance,
"connection", numRetries, NULL);
1344 if (freerdp_reconnect(instance))
1347 switch (freerdp_get_last_error(instance->context))
1349 case FREERDP_ERROR_CONNECT_CANCELLED:
1350 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1355 for (UINT32 x = 0; x < 50; x++)
1357 if (!IFCALLRESULT(TRUE, window_events, instance))
1364 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1368int freerdp_client_common_stop(rdpContext* context)
1370 rdpClientContext* cctx = (rdpClientContext*)context;
1373 freerdp_abort_connect_context(&cctx->context);
1377 (void)WaitForSingleObject(cctx->thread, INFINITE);
1378 (void)CloseHandle(cctx->thread);
1379 cctx->thread = NULL;
1385#if defined(CHANNEL_ENCOMSP_CLIENT)
1386BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1388 rdpClientContext* cctx = NULL;
1394 cctx = (rdpClientContext*)encomsp->custom;
1396 state = cctx->controlToggle;
1397 cctx->controlToggle = !cctx->controlToggle;
1398 return freerdp_client_encomsp_set_control(encomsp, state);
1401BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1408 pdu.ParticipantId = encomsp->participantId;
1409 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1412 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1414 encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1420client_encomsp_participant_created(EncomspClientContext* context,
1423 rdpClientContext* cctx = NULL;
1424 rdpSettings* settings = NULL;
1427 if (!context || !context->custom || !participantCreated)
1428 return ERROR_INVALID_PARAMETER;
1430 cctx = (rdpClientContext*)context->custom;
1433 settings = cctx->context.settings;
1434 WINPR_ASSERT(settings);
1436 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1437 context->participantId = participantCreated->ParticipantId;
1440 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1441 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1443 if (!freerdp_client_encomsp_set_control(context, TRUE))
1444 return ERROR_INTERNAL_ERROR;
1450 return ERROR_INTERNAL_ERROR;
1453 return CHANNEL_RC_OK;
1456static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1458 cctx->encomsp = encomsp;
1459 encomsp->custom = (
void*)cctx;
1460 encomsp->ParticipantCreated = client_encomsp_participant_created;
1463static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1467 encomsp->custom = NULL;
1468 encomsp->ParticipantCreated = NULL;
1472 cctx->encomsp = NULL;
1476void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1477 const ChannelConnectedEventArgs* e)
1479 rdpClientContext* cctx = (rdpClientContext*)context;
1487#if defined(CHANNEL_AINPUT_CLIENT)
1488 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1489 cctx->ainput = (AInputClientContext*)e->pInterface;
1491#if defined(CHANNEL_RDPEI_CLIENT)
1492 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1494 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1497#if defined(CHANNEL_RDPGFX_CLIENT)
1498 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1500 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1503#if defined(CHANNEL_GEOMETRY_CLIENT)
1504 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1506 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1509#if defined(CHANNEL_VIDEO_CLIENT)
1510 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1512 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1514 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1516 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1519#if defined(CHANNEL_ENCOMSP_CLIENT)
1520 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1522 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1527void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1528 const ChannelDisconnectedEventArgs* e)
1530 rdpClientContext* cctx = (rdpClientContext*)context;
1538#if defined(CHANNEL_AINPUT_CLIENT)
1539 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1540 cctx->ainput = NULL;
1542#if defined(CHANNEL_RDPEI_CLIENT)
1543 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1548#if defined(CHANNEL_RDPGFX_CLIENT)
1549 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1551 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1554#if defined(CHANNEL_GEOMETRY_CLIENT)
1555 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1557 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1560#if defined(CHANNEL_VIDEO_CLIENT)
1561 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1563 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1565 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1567 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1570#if defined(CHANNEL_ENCOMSP_CLIENT)
1571 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1573 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1578BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1580 BOOL handled = FALSE;
1584#if defined(CHANNEL_AINPUT_CLIENT)
1591 INT32 value = mflags & 0xFF;
1593 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1594 value = -1 * (0x100 - value);
1600 if (mflags & PTR_FLAGS_WHEEL)
1602 flags |= AINPUT_FLAGS_WHEEL;
1606 if (mflags & PTR_FLAGS_HWHEEL)
1608 flags |= AINPUT_FLAGS_WHEEL;
1612 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1613 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1614 if (rc == CHANNEL_RC_OK)
1620 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1625#if defined(CHANNEL_AINPUT_CLIENT)
1626static INLINE BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1631 WINPR_ASSERT(cctx->ainput);
1632 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1634 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1636 return rc == CHANNEL_RC_OK;
1640BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1643 BOOL handled = FALSE;
1647 const BOOL haveRelative =
1649 if (relative && haveRelative)
1651 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1652 WINPR_ASSERTING_INT_CAST(int16_t, x),
1653 WINPR_ASSERTING_INT_CAST(int16_t, y));
1656#if defined(CHANNEL_AINPUT_CLIENT)
1661 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1662 flags |= AINPUT_FLAGS_HAVE_REL;
1665 flags |= AINPUT_FLAGS_REL;
1667 if (mflags & PTR_FLAGS_DOWN)
1668 flags |= AINPUT_FLAGS_DOWN;
1669 if (mflags & PTR_FLAGS_BUTTON1)
1670 flags |= AINPUT_FLAGS_BUTTON1;
1671 if (mflags & PTR_FLAGS_BUTTON2)
1672 flags |= AINPUT_FLAGS_BUTTON2;
1673 if (mflags & PTR_FLAGS_BUTTON3)
1674 flags |= AINPUT_FLAGS_BUTTON3;
1675 if (mflags & PTR_FLAGS_MOVE)
1676 flags |= AINPUT_FLAGS_MOVE;
1677 handled = ainput_send_diff_event(cctx, flags, x, y);
1687 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1694 freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1695 (UINT16)cctx->lastY);
1700BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1703 BOOL handled = FALSE;
1706 const BOOL haveRelative =
1708 if (relative && haveRelative)
1710 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1711 WINPR_ASSERTING_INT_CAST(int16_t, x),
1712 WINPR_ASSERTING_INT_CAST(int16_t, y));
1715#if defined(CHANNEL_AINPUT_CLIENT)
1721 flags |= AINPUT_FLAGS_REL;
1722 if (mflags & PTR_XFLAGS_DOWN)
1723 flags |= AINPUT_FLAGS_DOWN;
1724 if (mflags & PTR_XFLAGS_BUTTON1)
1725 flags |= AINPUT_XFLAGS_BUTTON1;
1726 if (mflags & PTR_XFLAGS_BUTTON2)
1727 flags |= AINPUT_XFLAGS_BUTTON2;
1729 handled = ainput_send_diff_event(cctx, flags, x, y);
1739 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1746 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1747 (UINT16)cctx->lastY);
1753static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1756 WINPR_ASSERT(contact);
1758#if defined(CHANNEL_RDPEI_CLIENT)
1759 RdpeiClientContext* rdpei = cctx->rdpei;
1764 flags |= PTR_FLAGS_BUTTON1;
1766 WINPR_ASSERT(contact->x <= UINT16_MAX);
1767 WINPR_ASSERT(contact->y <= UINT16_MAX);
1768 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1774 if (rdpei->TouchRawEvent)
1776 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1777 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1778 ? CONTACT_DATA_PRESSURE_PRESENT
1781 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1782 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1783 RDPINPUT_CONTACT_FLAG_INCONTACT,
1784 contactFlags, contact->pressure);
1785 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1786 contactFlags, contact->pressure);
1790 WINPR_ASSERT(rdpei->TouchEnd);
1791 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1795 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1796 "-DWITH_CHANNELS=ON");
1802static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1805 WINPR_ASSERT(contact);
1807#if defined(CHANNEL_RDPEI_CLIENT)
1808 RdpeiClientContext* rdpei = cctx->rdpei;
1814 flags |= PTR_FLAGS_DOWN;
1815 flags |= PTR_FLAGS_MOVE;
1816 flags |= PTR_FLAGS_BUTTON1;
1818 WINPR_ASSERT(contact->x <= UINT16_MAX);
1819 WINPR_ASSERT(contact->y <= UINT16_MAX);
1820 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1826 if (rdpei->TouchRawEvent)
1828 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1829 RDPINPUT_CONTACT_FLAG_INCONTACT;
1830 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1831 ? CONTACT_DATA_PRESSURE_PRESENT
1833 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1834 contactFlags, contact->pressure);
1838 WINPR_ASSERT(rdpei->TouchBegin);
1839 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1843 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1844 "-DWITH_CHANNELS=ON");
1850static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1853 WINPR_ASSERT(contact);
1855#if defined(CHANNEL_RDPEI_CLIENT)
1856 RdpeiClientContext* rdpei = cctx->rdpei;
1861 flags |= PTR_FLAGS_MOVE;
1863 WINPR_ASSERT(contact->x <= UINT16_MAX);
1864 WINPR_ASSERT(contact->y <= UINT16_MAX);
1865 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1871 if (rdpei->TouchRawEvent)
1873 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1874 RDPINPUT_CONTACT_FLAG_INCONTACT;
1875 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1876 ? CONTACT_DATA_PRESSURE_PRESENT
1878 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1879 contactFlags, contact->pressure);
1883 WINPR_ASSERT(rdpei->TouchUpdate);
1884 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1888 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1889 "-DWITH_CHANNELS=ON");
1895static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
1896 UINT32 pressure, INT32 x, INT32 y,
1900 WINPR_ASSERT(pcontact);
1902 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
1906 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
1907 if (newcontact || (contact->id == touchId))
1909 contact->id = touchId;
1910 contact->flags = flags;
1911 contact->pressure = pressure;
1915 *pcontact = *contact;
1917 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
1930BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
1931 UINT32 pressure, INT32 x, INT32 y)
1933 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
1938 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
1941 switch (flags & mask)
1943 case FREERDP_TOUCH_DOWN:
1944 return freerdp_handle_touch_down(cctx, &contact);
1945 case FREERDP_TOUCH_UP:
1946 return freerdp_handle_touch_up(cctx, &contact);
1947 case FREERDP_TOUCH_MOTION:
1948 return freerdp_handle_touch_motion(cctx, &contact);
1950 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %d, ignoring", flags);
1955BOOL freerdp_client_load_channels(freerdp* instance)
1957 WINPR_ASSERT(instance);
1958 WINPR_ASSERT(instance->context);
1960 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
1962 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
1968int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
1970 const char* str_data = freerdp_get_logon_error_info_data(data);
1971 const char* str_type = freerdp_get_logon_error_info_type(type);
1973 if (!instance || !instance->context)
1976 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
1980static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
1985 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
1988 if (deviceid == pen->deviceid)
1998static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2001 static const INT32 null_deviceid = 0;
2004 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2005 if (freerdp_client_is_pen(cctx, deviceid))
2007 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2018 pen->deviceid = deviceid;
2019 pen->max_pressure = pressure;
2022 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2026 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2030BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2032 if ((flags & FREERDP_PEN_REGISTER) != 0)
2036 va_start(args, deviceid);
2037 double pressure = va_arg(args,
double);
2039 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2045 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2049 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2051 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2053 RdpeiClientContext* rdpei = cctx->rdpei;
2054 WINPR_ASSERT(rdpei);
2056 UINT32 normalizedpressure = 1024;
2059 UINT16 rotation = 0;
2063 va_start(args, deviceid);
2065 x = va_arg(args, INT32);
2066 y = va_arg(args, INT32);
2067 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2069 const double pressure = va_arg(args,
double);
2070 const double np = (pressure * 1024.0) / pen->max_pressure;
2071 normalizedpressure = (UINT32)lround(np);
2072 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2073 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2075 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2077 const unsigned arg = va_arg(args,
unsigned);
2078 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2079 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2081 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2083 const int arg = va_arg(args,
int);
2084 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2085 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2087 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2089 const int arg = va_arg(args,
int);
2090 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2091 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2095 if ((flags & FREERDP_PEN_PRESS) != 0)
2099 flags = FREERDP_PEN_MOTION |
2100 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2101 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2102 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2104 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2106 if (!pen->pressed ||
2107 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2108 flags = FREERDP_PEN_MOTION |
2109 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2111 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2114 flags |= pen->flags;
2115 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2116 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2117 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2118 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2122 if ((flags & FREERDP_PEN_PRESS) != 0)
2124 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2125 pen->hovering = FALSE;
2126 pen->pressed = TRUE;
2128 WINPR_ASSERT(rdpei->PenBegin);
2129 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2130 normalizedpressure, rotation, tiltX, tiltY);
2131 return rc == CHANNEL_RC_OK;
2133 else if ((flags & FREERDP_PEN_MOTION) != 0)
2135 UINT rc = ERROR_INTERNAL_ERROR;
2138 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2141 WINPR_ASSERT(rdpei->PenUpdate);
2142 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2143 rotation, tiltX, tiltY);
2145 else if (pen->hovering)
2147 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2149 WINPR_ASSERT(rdpei->PenHoverUpdate);
2150 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2151 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2155 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2156 pen->hovering = TRUE;
2158 WINPR_ASSERT(rdpei->PenHoverBegin);
2159 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2160 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2162 return rc == CHANNEL_RC_OK;
2164 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2166 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2167 pen->pressed = FALSE;
2168 pen->hovering = TRUE;
2170 WINPR_ASSERT(rdpei->PenUpdate);
2171 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2172 normalizedpressure, rotation, tiltX, tiltY);
2173 if (rc != CHANNEL_RC_OK)
2175 WINPR_ASSERT(rdpei->PenEnd);
2176 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2177 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2178 return re == CHANNEL_RC_OK;
2181 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2185BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2189 RdpeiClientContext* rdpei = cctx->rdpei;
2194 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2199 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2200 pen->hovering = FALSE;
2201 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2207BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2214 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2217 if (pen->deviceid == deviceid)
2224BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2226 WINPR_ASSERT(ccontext);
2228 const rdpSettings* settings = ccontext->context.settings;
2231 BOOL ainput = FALSE;
2232#if defined(CHANNEL_AINPUT_CLIENT)
2233 ainput = ccontext->ainput != NULL;
2236 return useRelative && (haveRelative || ainput);
2239static char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2241 const rdpSettings* settings = cctx->context.settings;
2243 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2244 AAD_WELLKNOWN_authorization_endpoint);
2245 const char* redirect_fmt =
2249 if (!client_id || !ep || !redirect_fmt || !scope)
2252 char* redirect_uri = NULL;
2253 size_t redirect_len = 0;
2254 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2261 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2262 client_id, scope, redirect_uri);
2267static char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2269 const rdpSettings* settings = cctx->context.settings;
2271 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2272 AAD_WELLKNOWN_authorization_endpoint);
2273 const char* redirect_fmt =
2277 if (!client_id || !ep || !redirect_fmt || !scope)
2280 char* redirect_uri = NULL;
2281 size_t redirect_len = 0;
2282 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2290 const char* code = va_arg(ap,
const char*);
2291 winpr_asprintf(&url, &urllen,
2292 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2293 code, client_id, scope, redirect_uri);
2298static char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2300 const rdpSettings* settings = cctx->context.settings;
2303 char* redirect_uri = NULL;
2304 size_t redirect_len = 0;
2310 const char* urlFormatString =
2312 const char* scope = va_arg(ap,
const char*);
2313 if (!urlFormatString || !scope)
2317 const char* tenantid =
"common";
2320 if (!base || !tenantid || !client_id)
2323 winpr_asprintf(&redirect_uri, &redirect_len, urlFormatString, base, tenantid);
2327 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2328 AAD_WELLKNOWN_authorization_endpoint);
2330 winpr_asprintf(&url, &urllen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2331 client_id, scope, redirect_uri);
2337static char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap)
2339 const rdpSettings* settings = cctx->context.settings;
2341 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2342 AAD_WELLKNOWN_authorization_endpoint);
2343 const char* redirect_fmt =
2345 const char* scope = va_arg(ap,
const char*);
2346 const char* code = va_arg(ap,
const char*);
2347 const char* req_cnf = va_arg(ap,
const char*);
2349 if (!client_id || !ep || !redirect_fmt || !scope || !code || !req_cnf)
2352 char* redirect_uri = NULL;
2353 size_t redirect_len = 0;
2354 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2364 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2365 code, client_id, scope, redirect_uri, req_cnf);
2370char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2379 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2380 str = aad_auth_request(cctx, ap);
2382 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2383 str = aad_token_request(cctx, ap);
2385 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2386 str = avd_auth_request(cctx, ap);
2388 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2389 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.