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/event.h>
41#include <freerdp/utils/smartcardlogon.h>
42#include <freerdp/session.h>
44#if defined(CHANNEL_AINPUT_CLIENT)
45#include <freerdp/client/ainput.h>
46#include <freerdp/channels/ainput.h>
49#if defined(CHANNEL_VIDEO_CLIENT)
50#include <freerdp/client/video.h>
51#include <freerdp/channels/video.h>
54#if defined(CHANNEL_RDPGFX_CLIENT)
55#include <freerdp/client/rdpgfx.h>
56#include <freerdp/channels/rdpgfx.h>
57#include <freerdp/gdi/gfx.h>
60#if defined(CHANNEL_GEOMETRY_CLIENT)
61#include <freerdp/client/geometry.h>
62#include <freerdp/channels/geometry.h>
65#if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
66#include <freerdp/gdi/video.h>
69#include <freerdp/channels/rdpewa.h>
72#include <freerdp/utils/http.h>
73#include <freerdp/utils/aad.h>
74#include <freerdp/client/aad_helper.h>
78#include "sso_mib_tokens.h"
83#include <freerdp/log.h>
84#define TAG CLIENT_TAG("common")
87static BOOL requireRdpClientContext(
const rdpContext* context)
91 WLog_ERR(TAG,
"[APPLICATION BUG] Function must be called with a context != NULL!");
95 freerdp* instance = context->instance;
99 "[APPLICATION BUG] Function must be called with a context->instance != NULL!");
103 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
106 WLog_ERR(TAG,
"[APPLICATION BUG] Function must be called with a "
107 "context->instance->pclientEntryPoints != NULL!");
113 if (
sizeof(rdpClientContext) > instance->ContextSize)
117 "[APPLICATION BUG] Function must be called with a context based on rdpClientContext!");
119 "[APPLICATION BUG] sizeof(rdpClientContext)[%" PRIuz
120 "] > instance->ContextSize[%" PRIuz
"])",
121 sizeof(rdpClientContext), instance->ContextSize);
128static void set_default_callbacks(freerdp* instance)
130 WINPR_ASSERT(instance);
131 instance->AuthenticateEx = client_cli_authenticate_ex;
132 instance->ChooseSmartcard = client_cli_choose_smartcard;
133 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
134 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
135 instance->PresentGatewayMessage = client_cli_present_gateway_message;
136 instance->LogonErrorInfo = client_cli_logon_error_info;
137 instance->GetAccessToken = client_cli_get_access_token;
138 instance->RetryDialog = client_common_retry_dialog;
140 WINPR_ASSERT(instance->context);
141 WINPR_ASSERT(instance->context->update);
142 instance->context->update->SaveSessionInfo = client_common_save_session_info;
145static void client_cli_user_notification(
void* context,
const UserNotificationEventArgs* e)
147 WINPR_UNUSED(context);
149 if (strcmp(e->e.Sender, RDPEWA_CHANNEL_NAME) != 0)
152 if (!e->message || e->message[0] ==
'\0')
154 (void)fprintf(stderr,
"[%s] Touch the security key\n", e->e.Sender);
155 (void)fflush(stderr);
159static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
161 WINPR_ASSERT(instance);
162 WINPR_ASSERT(context);
164 instance->LoadChannels = freerdp_client_load_channels;
165 set_default_callbacks(instance);
167 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
168 WINPR_ASSERT(pEntryPoints);
170 if (requireRdpClientContext(context))
172 rdpClientContext* cctx = (rdpClientContext*)context;
173 cctx->oauth2 = freerdp_oauth2_new();
178 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
181static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
183 WINPR_ASSERT(instance);
184 WINPR_ASSERT(context);
186 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
187 WINPR_ASSERT(pEntryPoints);
188 IFCALL(pEntryPoints->ClientFree, instance, context);
190 if (requireRdpClientContext(context))
192 rdpClientContext* cctx = (rdpClientContext*)context;
193 freerdp_oauth2_free(cctx->oauth2);
194 cctx->oauth2 =
nullptr;
200rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
202 freerdp* instance =
nullptr;
203 rdpContext* context =
nullptr;
208 if (!IFCALLRESULT(TRUE, pEntryPoints->GlobalInit))
211 instance = freerdp_new();
216 instance->ContextSize = pEntryPoints->ContextSize;
217 instance->ContextNew = freerdp_client_common_new;
218 instance->ContextFree = freerdp_client_common_free;
219 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
221 if (!instance->pClientEntryPoints)
224 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
226 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
229 context = instance->context;
230 context->instance = instance;
232#if defined(WITH_CLIENT_CHANNELS)
233 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
240 free(instance->pClientEntryPoints);
242 freerdp_free(instance);
246void freerdp_client_context_free(rdpContext* context)
248 freerdp* instance =
nullptr;
253 instance = context->instance;
257 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
258 freerdp_context_free(instance);
261 IFCALL(pEntryPoints->GlobalUninit);
263 free(instance->pClientEntryPoints);
264 freerdp_free(instance);
268int freerdp_client_start(rdpContext* context)
270 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
272 if (!context || !context->instance || !context->instance->pClientEntryPoints)
273 return ERROR_BAD_ARGUMENTS;
277 set_default_callbacks(context->instance);
281 PubSub_SubscribeUserNotification(context->pubSub, client_cli_user_notification);
288 if (requireRdpClientContext(context))
290 rdpClientContext* client_context = (rdpClientContext*)context;
291 client_context->mibClientWrapper = sso_mib_new(context);
292 if (!client_context->mibClientWrapper)
293 return ERROR_INTERNAL_ERROR;
297 pEntryPoints = context->instance->pClientEntryPoints;
298 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
301int freerdp_client_stop(rdpContext* context)
303 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
305 if (!context || !context->instance || !context->instance->pClientEntryPoints)
306 return ERROR_BAD_ARGUMENTS;
308 pEntryPoints = context->instance->pClientEntryPoints;
309 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
312 PubSub_UnsubscribeUserNotification(context->pubSub, client_cli_user_notification);
315 if (requireRdpClientContext(context))
317 rdpClientContext* client_context = (rdpClientContext*)context;
318 sso_mib_free(client_context->mibClientWrapper);
319 client_context->mibClientWrapper =
nullptr;
325freerdp* freerdp_client_get_instance(rdpContext* context)
327 if (!context || !context->instance)
330 return context->instance;
333HANDLE freerdp_client_get_thread(rdpContext* context)
338 WINPR_ASSERT(requireRdpClientContext(context));
339 if (!requireRdpClientContext(context))
342 return ((rdpClientContext*)context)->thread;
346static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
371 settings, FreeRDP_GatewayPassword,
409int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
413 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown,
414 nullptr, 0,
nullptr,
nullptr);
417int freerdp_client_settings_parse_command_line_ex(
419 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
429 status = freerdp_client_settings_parse_command_line_arguments_ex(
430 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
437 if (!freerdp_client_settings_post_process(settings))
440 const char* name = argv[0];
441 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
442 freerdp_get_build_config());
446int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
448 rdpFile* file =
nullptr;
450 file = freerdp_client_rdp_file_new();
455 if (!freerdp_client_parse_rdp_file(file, filename))
458 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
463 freerdp_client_rdp_file_free(file);
467int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
470 rdpFile* file =
nullptr;
472 file = freerdp_client_rdp_file_new();
477 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
478 freerdp_client_populate_settings_from_rdp_file(file, settings))
483 freerdp_client_rdp_file_free(file);
487int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
490 rdpFile* file =
nullptr;
492 file = freerdp_client_rdp_file_new();
497 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
500 if (!freerdp_client_write_rdp_file(file, filename, unicode))
505 freerdp_client_rdp_file_free(file);
509int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
513 char* filename =
nullptr;
514 char* password =
nullptr;
515 rdpAssistanceFile* file =
nullptr;
517 if (!settings || !argv || (argc < 2))
522 for (
int x = 2; x < argc; x++)
524 const char* key = strstr(argv[x],
"assistance:");
528 char* sep = strchr(key,
':');
536 file = freerdp_assistance_file_new();
541 status = freerdp_assistance_parse_file(file, filename, password);
546 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
551 freerdp_assistance_file_free(file);
556static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
559 WINPR_ASSERT(instance);
561 WINPR_ASSERT(result);
565 (void)fflush(stdout);
567 char* line =
nullptr;
568 if (suggestion && strlen(suggestion) > 0)
570 line = _strdup(suggestion);
571 size = strlen(suggestion);
574 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
577 char ebuffer[256] = WINPR_C_ARRAY_INIT;
578 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
579 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
589 line = StrSep(&line,
"\r");
590 line = StrSep(&line,
"\n");
612static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
613 char** password,
char** domain)
615 static const size_t password_size = 512;
616 const char* userAuth =
"Username: ";
617 const char* domainAuth =
"Domain: ";
618 const char* pwdAuth =
"Password: ";
619 BOOL pinOnly = FALSE;
620 BOOL queryAll = FALSE;
622 WINPR_ASSERT(instance);
623 WINPR_ASSERT(instance->context);
624 WINPR_ASSERT(instance->context->settings);
628 case AUTH_SMARTCARD_PIN:
629 pwdAuth =
"Smartcard-Pin: ";
633 pwdAuth =
"FIDO2 PIN: ";
646 userAuth =
"GatewayUsername: ";
647 domainAuth =
"GatewayDomain: ";
648 pwdAuth =
"GatewayPassword: ";
654 if (!username || !password || !domain)
659 const char* suggest = *username;
660 if (queryAll || !suggest)
662 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
670 const char* suggest = *domain;
671 if (queryAll || !suggest)
673 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
680 char* line = calloc(password_size,
sizeof(
char));
685 const BOOL fromStdin =
688 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
692 if (password_size > 0)
710BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
711 rdp_auth_reason reason)
713 WINPR_ASSERT(instance);
714 WINPR_ASSERT(username);
715 WINPR_ASSERT(password);
716 WINPR_ASSERT(domain);
726 case AUTH_SMARTCARD_PIN:
728 if ((*username) && (*password))
739 return client_cli_authenticate_raw(instance, reason, username, password, domain);
742BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
743 DWORD count, DWORD* choice, BOOL gateway)
745 unsigned long answer = 0;
748 printf(
"Multiple smartcards are available for use:\n");
749 for (DWORD i = 0; i < count; i++)
752 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
753 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
756 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
757 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
758 cert->issuer, cert->upn);
761 free(container_name);
766 char input[10] = WINPR_C_ARRAY_INIT;
768 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
769 gateway ?
"gateway authentication" :
"logon", count - 1);
770 (void)fflush(stdout);
771 if (!fgets(input, 10, stdin))
773 WLog_ERR(TAG,
"could not read from stdin");
777 answer = strtoul(input, &p, 10);
778 if ((*p ==
'\n' && p != input) && answer < count)
780 *choice = (UINT32)answer;
786#if defined(WITH_FREERDP_DEPRECATED)
787BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
791 WLog_INFO(TAG,
"Authentication via smartcard");
795 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
798BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
800 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
805static DWORD client_cli_accept_certificate(freerdp* instance)
809 WINPR_ASSERT(instance);
810 WINPR_ASSERT(instance->context);
812 const rdpSettings* settings = instance->context->settings;
813 WINPR_ASSERT(settings);
821 printf(
"Do you trust the above certificate? (Y/T/N) ");
822 (void)fflush(stdout);
823 answer = freerdp_interruptible_getc(instance->context, stdin);
825 if ((answer == EOF) || feof(stdin))
827 printf(
"\nError: Could not read answer from stdin.\n");
835 answer = freerdp_interruptible_getc(instance->context, stdin);
843 answer = freerdp_interruptible_getc(instance->context, stdin);
851 answer = freerdp_interruptible_getc(instance->context, stdin);
876#if defined(WITH_FREERDP_DEPRECATED)
877DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
878 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
880 WINPR_UNUSED(common_name);
881 WINPR_UNUSED(host_mismatch);
883 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
884 printf(
"Certificate details:\n");
885 printf(
"\tSubject: %s\n", subject);
886 printf(
"\tIssuer: %s\n", issuer);
887 printf(
"\tThumbprint: %s\n", fingerprint);
888 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
889 "the CA certificate in your certificate store, or the certificate has expired.\n"
890 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
891 return client_cli_accept_certificate(instance);
895WINPR_ATTR_MALLOC(free, 1)
896static
char* client_cli_pem_cert(const
char* pem)
898 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
902 char* fp = freerdp_certificate_get_fingerprint(cert);
903 char* start = freerdp_certificate_get_validity(cert, TRUE);
904 char* end = freerdp_certificate_get_validity(cert, FALSE);
905 freerdp_certificate_free(cert);
909 winpr_asprintf(&str, &slen,
912 "\tThumbprint: %s\n",
935DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
936 const char* common_name,
const char* subject,
937 const char* issuer,
const char* fingerprint, DWORD flags)
939 const char* type =
"RDP-Server";
941 WINPR_ASSERT(instance);
942 WINPR_ASSERT(instance->context);
943 WINPR_ASSERT(instance->context->settings);
945 if (flags & VERIFY_CERT_FLAG_GATEWAY)
946 type =
"RDP-Gateway";
948 if (flags & VERIFY_CERT_FLAG_REDIRECT)
949 type =
"RDP-Redirect";
951 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
952 printf(
"\tCommon Name: %s\n", common_name);
953 printf(
"\tSubject: %s\n", subject);
954 printf(
"\tIssuer: %s\n", issuer);
958 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
960 char* str = client_cli_pem_cert(fingerprint);
965 printf(
"\tThumbprint: %s\n", fingerprint);
967 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
968 "the CA certificate in your certificate store, or the certificate has expired.\n"
969 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
970 return client_cli_accept_certificate(instance);
988#if defined(WITH_FREERDP_DEPRECATED)
989DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
990 const char* subject,
const char* issuer,
991 const char* fingerprint,
const char* old_subject,
992 const char* old_issuer,
const char* old_fingerprint)
994 WINPR_UNUSED(common_name);
996 printf(
"WARNING: This callback is deprecated, migrate to "
997 "client_cli_verify_changed_certificate_ex\n");
998 printf(
"!!! Certificate has changed !!!\n");
1000 printf(
"New Certificate details:\n");
1001 printf(
"\tSubject: %s\n", subject);
1002 printf(
"\tIssuer: %s\n", issuer);
1003 printf(
"\tThumbprint: %s\n", fingerprint);
1005 printf(
"Old Certificate details:\n");
1006 printf(
"\tSubject: %s\n", old_subject);
1007 printf(
"\tIssuer: %s\n", old_issuer);
1008 printf(
"\tThumbprint: %s\n", old_fingerprint);
1010 printf(
"The above X.509 certificate does not match the certificate used for previous "
1012 "This may indicate that the certificate has been tampered with.\n"
1013 "Please contact the administrator of the RDP server and clarify.\n");
1014 return client_cli_accept_certificate(instance);
1037DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
1038 const char* common_name,
const char* subject,
1039 const char* issuer,
const char* fingerprint,
1040 const char* old_subject,
const char* old_issuer,
1041 const char* old_fingerprint, DWORD flags)
1043 const char* type =
"RDP-Server";
1045 WINPR_ASSERT(instance);
1046 WINPR_ASSERT(instance->context);
1047 WINPR_ASSERT(instance->context->settings);
1049 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1050 type =
"RDP-Gateway";
1052 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1053 type =
"RDP-Redirect";
1055 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
1057 printf(
"New Certificate details:\n");
1058 printf(
"\tCommon Name: %s\n", common_name);
1059 printf(
"\tSubject: %s\n", subject);
1060 printf(
"\tIssuer: %s\n", issuer);
1064 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1066 char* str = client_cli_pem_cert(fingerprint);
1071 printf(
"\tThumbprint: %s\n", fingerprint);
1073 printf(
"Old Certificate details:\n");
1074 printf(
"\tSubject: %s\n", old_subject);
1075 printf(
"\tIssuer: %s\n", old_issuer);
1079 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1081 char* str = client_cli_pem_cert(old_fingerprint);
1086 printf(
"\tThumbprint: %s\n", old_fingerprint);
1088 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
1090 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
1091 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
1092 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
1093 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
1096 printf(
"The above X.509 certificate does not match the certificate used for previous "
1098 "This may indicate that the certificate has been tampered with.\n"
1099 "Please contact the administrator of the RDP server and clarify.\n");
1100 return client_cli_accept_certificate(instance);
1103BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1104 BOOL isConsentMandatory,
size_t length,
1105 const WCHAR* message)
1107 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
1109 WINPR_ASSERT(instance);
1110 WINPR_ASSERT(instance->context);
1111 WINPR_ASSERT(instance->context->settings);
1113 if (!isDisplayMandatory && !isConsentMandatory)
1116 printf(
"%s:\n", msgType);
1118 printf(
"%.*S\n", (
int)length, message);
1121 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR),
nullptr);
1124 printf(
"Failed to convert message!\n");
1127 printf(
"%s\n", msg);
1132 while (isConsentMandatory)
1134 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1135 (void)fflush(stdout);
1136 const int answer = freerdp_interruptible_getc(instance->context, stdin);
1138 if ((answer == EOF) || feof(stdin))
1140 printf(
"\nError: Could not read answer from stdin.\n");
1144 const int confirm = freerdp_interruptible_getc(instance->context, stdin);
1150 return confirm != EOF;
1165#if defined(WITH_AAD)
1167static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1168 const char* req_cnf,
char** token)
1170 WINPR_ASSERT(instance);
1171 WINPR_ASSERT(instance->context);
1174 char* url =
nullptr;
1175 char* token_request =
nullptr;
1177 WINPR_ASSERT(scope);
1178 WINPR_ASSERT(req_cnf);
1179 WINPR_ASSERT(token);
1184 WINPR_ASSERT(requireRdpClientContext(instance->context));
1185 if (!requireRdpClientContext(instance->context))
1188 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1189 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1191 printf(
"Browse to: %s\n", request);
1192 winpr_zfree(request);
1193 printf(
"Paste redirect URL here: \n");
1195 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1200 freerdp_client_extract_aad_code((rdpClientContext*)instance->context, url, size);
1204 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1205 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1211 rc = client_common_get_access_token(instance, token_request, token);
1214 winpr_zfree(token_request);
1216 return rc && (*token !=
nullptr);
1220static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1222 WINPR_ASSERT(instance);
1223 WINPR_ASSERT(instance->context);
1225 WINPR_ASSERT(requireRdpClientContext(instance->context));
1226 if (!requireRdpClientContext(instance->context))
1230 char* url =
nullptr;
1231 char* token_request =
nullptr;
1233 WINPR_ASSERT(token);
1239 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1240 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1243 printf(
"Browse to: %s\n", request);
1244 winpr_zfree(request);
1245 printf(
"Paste redirect URL here: \n");
1247 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1252 freerdp_client_extract_aad_code((rdpClientContext*)instance->context, url, size);
1255 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1256 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1263 rc = client_common_get_access_token(instance, token_request, token);
1266 free(token_request);
1268 return rc && (*token !=
nullptr);
1273static BOOL client_cli_get_access_token_va(freerdp* instance,
1274 WINPR_ATTR_UNUSED AccessTokenType tokenType,
1275 char** token, WINPR_ATTR_UNUSED
size_t count, va_list ap)
1277 WINPR_ASSERT(instance);
1278 WINPR_ASSERT(token);
1281#if !defined(WITH_AAD)
1282 WLog_ERR(TAG,
"Build does not support AAD authentication");
1286 WINPR_ASSERT(instance->context);
1295 case ACCESS_TOKEN_TYPE_AAD:
1300 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1309 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1312 const char* scope = va_arg(ap,
const char*);
1313 const char* req_cnf = va_arg(ap,
const char*);
1314 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1318 case ACCESS_TOKEN_TYPE_AVD:
1321 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1324 rc = client_cli_get_avd_access_token(instance, token);
1327 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%u], aborting", tokenType);
1338BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1341 va_list ap = WINPR_C_ARRAY_INIT;
1342 va_start(ap, count);
1343 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
1348BOOL client_common_get_access_token(WINPR_ATTR_UNUSED freerdp* instance,
1349 WINPR_ATTR_UNUSED
const char* request,
1350 WINPR_ATTR_UNUSED
char** token)
1352 WINPR_ASSERT(request);
1353 WINPR_ASSERT(token);
1359 BYTE* response =
nullptr;
1360 size_t response_length = 0;
1362 wLog* log = WLog_Get(TAG);
1364 const char* token_ep =
1365 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1366 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1368 WLog_ERR(TAG,
"access token request failed");
1372 if (resp_code != HTTP_STATUS_OK)
1374 char buffer[64] = WINPR_C_ARRAY_INIT;
1376 WLog_Print(log, WLOG_ERROR,
1377 "Server unwilling to provide access token; returned status code %s",
1378 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1379 if (response_length > 0)
1380 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1384 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1392 WLog_ERR(TAG,
"Build does not support AAD authentication");
1397SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1400 WINPR_UNUSED(instance);
1401 WINPR_ASSERT(instance->context);
1402 WINPR_UNUSED(userarg);
1403 WINPR_ASSERT(instance);
1406 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1408 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1414 if (strcmp(what,
"arm-transport") == 0)
1415 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1418 const rdpSettings* settings = instance->context->settings;
1422 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1431 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1432 "tech support for help if this keeps happening.",
1437 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1438 what, current + 1, max, delay);
1439 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1442BOOL client_auto_reconnect(freerdp* instance)
1444 return client_auto_reconnect_ex(instance,
nullptr);
1447BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1451 UINT32 numRetries = 0;
1452 rdpSettings* settings =
nullptr;
1457 WINPR_ASSERT(instance->context);
1459 settings = instance->context->settings;
1460 WINPR_ASSERT(settings);
1462 const UINT32 maxRetries =
1466 error = freerdp_error_info(instance);
1469 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1471 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1472 freerdp_get_error_info_string(error));
1474 case ERRINFO_SUCCESS:
1476 WLog_INFO(TAG,
"Network disconnect!");
1479 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1486 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1490 const UINT err = freerdp_get_last_error(instance->context);
1493 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1494 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1495 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1496 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1497 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1498 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1499 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1500 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1501 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1502 freerdp_get_last_error_name(err));
1504 case FREERDP_ERROR_CONNECT_CANCELLED:
1505 WLog_WARN(TAG,
"Connection aborted by user");
1515 if ((maxRetries > 0) && (numRetries >= maxRetries))
1517 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1522 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1524 const SSIZE_T delay =
1525 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1530 if (freerdp_reconnect(instance))
1533 switch (freerdp_get_last_error(instance->context))
1535 case FREERDP_ERROR_CONNECT_CANCELLED:
1536 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1541 for (SSIZE_T x = 0; x < delay / 10; x++)
1543 if (!IFCALLRESULT(TRUE, window_events, instance))
1545 WLog_ERR(TAG,
"window_events failed!");
1553 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1557int freerdp_client_common_stop(rdpContext* context)
1559 freerdp_abort_connect_context(context);
1561 if (requireRdpClientContext(context))
1564 rdpClientContext* cctx = (rdpClientContext*)context;
1568 (void)WaitForSingleObject(cctx->thread, INFINITE);
1569 (void)CloseHandle(cctx->thread);
1570 cctx->thread =
nullptr;
1572#if defined(WITH_AAD)
1573 aad_auth_helper_stop(cctx->aadHelper);
1574 cctx->aadHelper =
nullptr;
1581#if defined(CHANNEL_ENCOMSP_CLIENT)
1582BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1589 rdpClientContext* cctx = (rdpClientContext*)encomsp->custom;
1591 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1592 if (!cctx || !requireRdpClientContext(&cctx->context))
1595 state = cctx->controlToggle;
1596 cctx->controlToggle = !cctx->controlToggle;
1597 return freerdp_client_encomsp_set_control(encomsp, state);
1600BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1607 pdu.ParticipantId = encomsp->participantId;
1608 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1611 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1613 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1614 return rc == CHANNEL_RC_OK;
1618client_encomsp_participant_created(EncomspClientContext* context,
1623 if (!context || !context->custom || !participantCreated)
1624 return ERROR_INVALID_PARAMETER;
1626 rdpClientContext* cctx = (rdpClientContext*)context->custom;
1628 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1629 if (!cctx || !requireRdpClientContext(&cctx->context))
1630 return ERROR_INVALID_PARAMETER;
1632 rdpSettings* settings = cctx->context.settings;
1633 WINPR_ASSERT(settings);
1635 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1636 context->participantId = participantCreated->ParticipantId;
1639 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1640 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1642 if (!freerdp_client_encomsp_set_control(context, TRUE))
1643 return ERROR_INTERNAL_ERROR;
1649 return ERROR_INTERNAL_ERROR;
1652 return CHANNEL_RC_OK;
1655static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1658 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1659 if (!cctx || !requireRdpClientContext(&cctx->context))
1662 cctx->encomsp = encomsp;
1663 encomsp->custom = (
void*)cctx;
1664 encomsp->ParticipantCreated = client_encomsp_participant_created;
1667static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1671 encomsp->custom =
nullptr;
1672 encomsp->ParticipantCreated =
nullptr;
1677 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1678 if (requireRdpClientContext(&cctx->context))
1679 cctx->encomsp =
nullptr;
1684void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1685 const ChannelConnectedEventArgs* e)
1687 rdpClientContext* cctx = (rdpClientContext*)context;
1695#if defined(CHANNEL_AINPUT_CLIENT)
1696 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1699 WINPR_ASSERT(requireRdpClientContext(context));
1700 if (!requireRdpClientContext(context))
1702 cctx->ainput = (AInputClientContext*)e->pInterface;
1705#if defined(CHANNEL_RDPEI_CLIENT)
1706 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1708 WINPR_ASSERT(requireRdpClientContext(context));
1709 if (!requireRdpClientContext(context))
1711 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1714#if defined(CHANNEL_RDPGFX_CLIENT)
1715 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1717 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1720#if defined(CHANNEL_GEOMETRY_CLIENT)
1721 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1723 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1726#if defined(CHANNEL_VIDEO_CLIENT)
1727 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1729 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1731 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1733 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1736#if defined(CHANNEL_ENCOMSP_CLIENT)
1737 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1739 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1744void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1745 const ChannelDisconnectedEventArgs* e)
1747 rdpClientContext* cctx = (rdpClientContext*)context;
1755#if defined(CHANNEL_AINPUT_CLIENT)
1756 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1758 WINPR_ASSERT(requireRdpClientContext(context));
1759 if (!requireRdpClientContext(context))
1761 cctx->ainput =
nullptr;
1764#if defined(CHANNEL_RDPEI_CLIENT)
1765 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1767 WINPR_ASSERT(requireRdpClientContext(context));
1768 if (!requireRdpClientContext(context))
1770 cctx->rdpei =
nullptr;
1773#if defined(CHANNEL_RDPGFX_CLIENT)
1774 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1776 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1779#if defined(CHANNEL_GEOMETRY_CLIENT)
1780 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1782 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1785#if defined(CHANNEL_VIDEO_CLIENT)
1786 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1788 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1790 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1792 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1795#if defined(CHANNEL_ENCOMSP_CLIENT)
1796 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1798 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1803BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1805 BOOL handled = FALSE;
1808 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1809 if (!cctx || !requireRdpClientContext(&cctx->context))
1812 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1813 if (state != CONNECTION_STATE_ACTIVE)
1816#if defined(CHANNEL_AINPUT_CLIENT)
1823 INT32 value = mflags & 0xFF;
1825 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1826 value = -1 * (0x100 - value);
1832 if (mflags & PTR_FLAGS_WHEEL)
1834 flags |= AINPUT_FLAGS_WHEEL;
1838 if (mflags & PTR_FLAGS_HWHEEL)
1840 flags |= AINPUT_FLAGS_WHEEL;
1844 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1845 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1846 if (rc == CHANNEL_RC_OK)
1852 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1857#if defined(CHANNEL_AINPUT_CLIENT)
1859static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1862 WINPR_ASSERT(cctx->ainput);
1863 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1864 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1866 if (!cctx || !requireRdpClientContext(&cctx->context))
1867 return ERROR_INVALID_PARAMETER;
1869 const UINT rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1871 return rc == CHANNEL_RC_OK;
1876static bool button_pressed(
const rdpClientContext* cctx)
1879 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1880 if (!cctx || !requireRdpClientContext(&cctx->context))
1883 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1885 const BOOL cur = cctx->pressed_buttons[x];
1892BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1895 BOOL handled = FALSE;
1898 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1899 if (!cctx || !requireRdpClientContext(&cctx->context))
1902 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1903 if (state != CONNECTION_STATE_ACTIVE)
1906 if (mflags & PTR_FLAGS_BUTTON1)
1907 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1908 if (mflags & PTR_FLAGS_BUTTON2)
1909 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1910 if (mflags & PTR_FLAGS_BUTTON3)
1911 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1913 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1916 if (!button_pressed(cctx))
1920 const BOOL haveRelative =
1922 if (relative && haveRelative)
1924 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1925 WINPR_ASSERTING_INT_CAST(int16_t, x),
1926 WINPR_ASSERTING_INT_CAST(int16_t, y));
1929#if defined(CHANNEL_AINPUT_CLIENT)
1934 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1935 flags |= AINPUT_FLAGS_HAVE_REL;
1938 flags |= AINPUT_FLAGS_REL;
1940 if (mflags & PTR_FLAGS_DOWN)
1941 flags |= AINPUT_FLAGS_DOWN;
1942 if (mflags & PTR_FLAGS_BUTTON1)
1943 flags |= AINPUT_FLAGS_BUTTON1;
1944 if (mflags & PTR_FLAGS_BUTTON2)
1945 flags |= AINPUT_FLAGS_BUTTON2;
1946 if (mflags & PTR_FLAGS_BUTTON3)
1947 flags |= AINPUT_FLAGS_BUTTON3;
1948 if (mflags & PTR_FLAGS_MOVE)
1949 flags |= AINPUT_FLAGS_MOVE;
1950 handled = ainput_send_diff_event(cctx, flags, x, y);
1960 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1967 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1968 (UINT16)cctx->lastY);
1973BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1976 BOOL handled = FALSE;
1978 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1980 if (!cctx || !requireRdpClientContext(&cctx->context))
1983 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1984 if (state != CONNECTION_STATE_ACTIVE)
1987 if (mflags & PTR_XFLAGS_BUTTON1)
1988 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
1989 if (mflags & PTR_XFLAGS_BUTTON2)
1990 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
1992 const BOOL haveRelative =
1994 if (relative && haveRelative)
1996 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1997 WINPR_ASSERTING_INT_CAST(int16_t, x),
1998 WINPR_ASSERTING_INT_CAST(int16_t, y));
2001#if defined(CHANNEL_AINPUT_CLIENT)
2007 flags |= AINPUT_FLAGS_REL;
2008 if (mflags & PTR_XFLAGS_DOWN)
2009 flags |= AINPUT_FLAGS_DOWN;
2010 if (mflags & PTR_XFLAGS_BUTTON1)
2011 flags |= AINPUT_XFLAGS_BUTTON1;
2012 if (mflags & PTR_XFLAGS_BUTTON2)
2013 flags |= AINPUT_XFLAGS_BUTTON2;
2015 handled = ainput_send_diff_event(cctx, flags, x, y);
2025 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2032 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2033 (UINT16)cctx->lastY);
2040static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
2044 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2045 if (!cctx || !requireRdpClientContext(&cctx->context))
2048 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
2049 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
2050 WINPR_ASSERT(contact);
2051 WINPR_ASSERT(contact->x <= UINT16_MAX);
2052 WINPR_ASSERT(contact->y <= UINT16_MAX);
2054 switch (contact->count)
2057 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
2058 contact->x, contact->y);
2060 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
2061 contact->x, contact->y);
2063 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
2064 contact->x, contact->y);
2066 return freerdp_client_send_extended_button_event(
2067 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2069 return freerdp_client_send_extended_button_event(
2070 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2078static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2081 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2082 WINPR_ASSERT(contact);
2084 if (!cctx || !requireRdpClientContext(&cctx->context))
2087#if defined(CHANNEL_RDPEI_CLIENT)
2088 RdpeiClientContext* rdpei = cctx->rdpei;
2091 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2095 if (rdpei->TouchRawEvent)
2097 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
2098 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2099 ? CONTACT_DATA_PRESSURE_PRESENT
2103 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2104 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2105 RDPINPUT_CONTACT_FLAG_INCONTACT,
2106 contactFlags, contact->pressure);
2107 if (rc1 != CHANNEL_RC_OK)
2110 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
2111 &contactId, flags, contactFlags, contact->pressure);
2112 if (rc2 != CHANNEL_RC_OK)
2117 WINPR_ASSERT(rdpei->TouchEnd);
2118 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2119 if (rc != CHANNEL_RC_OK)
2124 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2125 "-DCHANNEL_RDPEI_CLIENT=ON");
2126 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2131static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2134 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2135 WINPR_ASSERT(contact);
2137 if (!cctx || !requireRdpClientContext(&cctx->context))
2140#if defined(CHANNEL_RDPEI_CLIENT)
2141 RdpeiClientContext* rdpei = cctx->rdpei;
2145 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2149 if (rdpei->TouchRawEvent)
2151 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
2152 RDPINPUT_CONTACT_FLAG_INCONTACT;
2153 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2154 ? CONTACT_DATA_PRESSURE_PRESENT
2156 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2157 flags, contactFlags, contact->pressure);
2158 if (rc != CHANNEL_RC_OK)
2163 WINPR_ASSERT(rdpei->TouchBegin);
2164 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
2165 if (rc != CHANNEL_RC_OK)
2171 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2172 "-DCHANNEL_RDPEI_CLIENT=ON");
2173 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2178static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
2182 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2184 if (!cctx || !requireRdpClientContext(&cctx->context))
2187 const UINT16 flags = PTR_FLAGS_MOVE;
2189 WINPR_ASSERT(contact);
2190 WINPR_ASSERT(contact->x <= UINT16_MAX);
2191 WINPR_ASSERT(contact->y <= UINT16_MAX);
2192 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
2196static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2199 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2200 WINPR_ASSERT(contact);
2202 if (!cctx || !requireRdpClientContext(&cctx->context))
2205#if defined(CHANNEL_RDPEI_CLIENT)
2206 RdpeiClientContext* rdpei = cctx->rdpei;
2209 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2213 if (rdpei->TouchRawEvent)
2215 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2216 RDPINPUT_CONTACT_FLAG_INCONTACT;
2217 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2218 ? CONTACT_DATA_PRESSURE_PRESENT
2220 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2221 flags, contactFlags, contact->pressure);
2222 if (rc != CHANNEL_RC_OK)
2227 WINPR_ASSERT(rdpei->TouchUpdate);
2228 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2229 if (rc != CHANNEL_RC_OK)
2235 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2236 "-DCHANNEL_RDPEI_CLIENT=ON");
2237 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2242static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2245 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2246 WINPR_ASSERT(contact);
2248 if (!cctx || !requireRdpClientContext(&cctx->context))
2251#if defined(CHANNEL_RDPEI_CLIENT)
2252 RdpeiClientContext* rdpei = cctx->rdpei;
2255 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2259 if (rdpei->TouchRawEvent)
2261 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2262 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2263 ? CONTACT_DATA_PRESSURE_PRESENT
2265 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2266 flags, contactFlags, contact->pressure);
2267 if (rc != CHANNEL_RC_OK)
2272 WINPR_ASSERT(rdpei->TouchUpdate);
2273 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2274 if (rc != CHANNEL_RC_OK)
2280 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2281 "-DCHANNEL_RDPEI_CLIENT=ON");
2282 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2287static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2288 UINT32 pressure, INT32 x, INT32 y,
2292 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2293 WINPR_ASSERT(pcontact);
2295 if (!cctx || !requireRdpClientContext(&cctx->context))
2298 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2302 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2303 if (newcontact || (contact->id == touchId))
2305 contact->id = touchId;
2306 contact->flags = flags;
2307 contact->pressure = pressure;
2311 *pcontact = *contact;
2313 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2326BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2327 UINT32 pressure, INT32 x, INT32 y)
2330 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2332 if (!cctx || !requireRdpClientContext(&cctx->context))
2336 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2339 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2340 if (state != CONNECTION_STATE_ACTIVE)
2345 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2348 switch (flags & mask)
2350 case FREERDP_TOUCH_DOWN:
2351 return freerdp_handle_touch_down(cctx, &contact);
2352 case FREERDP_TOUCH_UP:
2353 return freerdp_handle_touch_up(cctx, &contact);
2354 case FREERDP_TOUCH_MOTION:
2355 return freerdp_handle_touch_motion(cctx, &contact);
2356 case FREERDP_TOUCH_CANCEL:
2357 return freerdp_handle_touch_cancel(cctx, &contact);
2359 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2364BOOL freerdp_client_load_channels(freerdp* instance)
2366 WINPR_ASSERT(instance);
2367 WINPR_ASSERT(instance->context);
2369 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2371 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2377int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2379 const char* str_data = freerdp_get_logon_error_info_data(data);
2380 const char* str_type = freerdp_get_logon_error_info_type(type);
2382 if (!instance || !instance->context)
2385 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2390static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2394 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2396 if (!cctx || !requireRdpClientContext(&cctx->context))
2399 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2402 if (deviceid == pen->deviceid)
2413static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2416 static const INT32 null_deviceid = 0;
2419 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2420 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2422 if (!cctx || !requireRdpClientContext(&cctx->context))
2425 if (freerdp_client_is_pen(cctx, deviceid))
2427 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2438 pen->deviceid = deviceid;
2439 pen->max_pressure = pressure;
2442 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2446 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2450BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2453 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2455 if (!cctx || !requireRdpClientContext(&cctx->context))
2458 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2459 if (state != CONNECTION_STATE_ACTIVE)
2462#if defined(CHANNEL_RDPEI_CLIENT)
2463 if ((flags & FREERDP_PEN_REGISTER) != 0)
2465 va_list args = WINPR_C_ARRAY_INIT;
2467 va_start(args, deviceid);
2468 double pressure = va_arg(args,
double);
2470 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2476 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2480 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2482 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2484 RdpeiClientContext* rdpei = cctx->rdpei;
2485 WINPR_ASSERT(rdpei);
2487 UINT32 normalizedpressure = 1024;
2490 UINT16 rotation = 0;
2493 va_list args = WINPR_C_ARRAY_INIT;
2494 va_start(args, deviceid);
2496 x = va_arg(args, INT32);
2497 y = va_arg(args, INT32);
2498 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2500 const double pressure = va_arg(args,
double);
2501 const double np = (pressure * 1024.0) / pen->max_pressure;
2502 normalizedpressure = (UINT32)lround(np);
2503 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2504 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2506 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2508 const unsigned arg = va_arg(args,
unsigned);
2509 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2510 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2512 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2514 const int arg = va_arg(args,
int);
2515 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2516 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2518 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2520 const int arg = va_arg(args,
int);
2521 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2522 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2526 if ((flags & FREERDP_PEN_PRESS) != 0)
2530 flags = FREERDP_PEN_MOTION |
2531 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2532 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2533 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2535 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2537 if (!pen->pressed ||
2538 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2539 flags = FREERDP_PEN_MOTION |
2540 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2542 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2545 flags |= pen->flags;
2546 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2547 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2548 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2549 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2553 if ((flags & FREERDP_PEN_PRESS) != 0)
2555 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2556 pen->hovering = FALSE;
2557 pen->pressed = TRUE;
2559 WINPR_ASSERT(rdpei->PenBegin);
2560 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2561 normalizedpressure, rotation, tiltX, tiltY);
2562 return rc == CHANNEL_RC_OK;
2564 else if ((flags & FREERDP_PEN_MOTION) != 0)
2566 UINT rc = ERROR_INTERNAL_ERROR;
2569 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2572 WINPR_ASSERT(rdpei->PenUpdate);
2573 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2574 rotation, tiltX, tiltY);
2576 else if (pen->hovering)
2578 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2580 WINPR_ASSERT(rdpei->PenHoverUpdate);
2581 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2582 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2586 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2587 pen->hovering = TRUE;
2589 WINPR_ASSERT(rdpei->PenHoverBegin);
2590 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2591 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2593 return rc == CHANNEL_RC_OK;
2595 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2597 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2598 pen->pressed = FALSE;
2599 pen->hovering = TRUE;
2601 WINPR_ASSERT(rdpei->PenUpdate);
2602 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2603 normalizedpressure, rotation, tiltX, tiltY);
2604 if (rc != CHANNEL_RC_OK)
2606 WINPR_ASSERT(rdpei->PenEnd);
2607 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2608 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2609 return re == CHANNEL_RC_OK;
2612 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2614 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2615 "-DCHANNEL_RDPEI_CLIENT=ON");
2621BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2624 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2626 if (!cctx || !requireRdpClientContext(&cctx->context))
2629 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2630 if (state != CONNECTION_STATE_ACTIVE)
2633#if defined(CHANNEL_RDPEI_CLIENT)
2634 RdpeiClientContext* rdpei = cctx->rdpei;
2639 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2644 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2645 pen->hovering = FALSE;
2647 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2648 if (rc != CHANNEL_RC_OK)
2654 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2655 "-DCHANNEL_RDPEI_CLIENT=ON");
2660BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2663 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2665 if (!cctx || !requireRdpClientContext(&cctx->context))
2671 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2674 if (pen->deviceid == deviceid)
2681BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2684 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2686 if (!cctx || !requireRdpClientContext(&cctx->context))
2689 const rdpSettings* settings = cctx->context.settings;
2692 BOOL ainput = FALSE;
2693#if defined(CHANNEL_AINPUT_CLIENT)
2694 ainput = cctx->ainput !=
nullptr;
2697 return useRelative && (haveRelative || ainput);
2700#if defined(WITH_AAD)
2701WINPR_ATTR_MALLOC(free, 1)
2702static
char* get_redirect_uri(const rdpSettings* settings)
2704 char* redirect_uri =
nullptr;
2708 const char* redirect_fmt =
2711 const char* tenantid =
"common";
2715 if (tenantid && redirect_fmt)
2720 size_t redirect_len = 0;
2721 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2727 const char* redirect_fmt =
2730 size_t redirect_len = 0;
2731 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2733 return redirect_uri;
2736WINPR_ATTR_MALLOC(free, 1)
2737static
char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2740 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2744 if (!cctx || !requireRdpClientContext(&cctx->context))
2747 const rdpSettings* settings = cctx->context.settings;
2749 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2750 AAD_WELLKNOWN_authorization_endpoint);
2753 if (!client_id || !ep || !scope)
2756 char* redirect_uri = get_redirect_uri(settings);
2760 char* url =
nullptr;
2761 winpr_asprintf(&url, plen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2762 client_id, scope, redirect_uri);
2767WINPR_ATTR_MALLOC(free, 1)
2768static
char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2771 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2775 if (!cctx || !requireRdpClientContext(&cctx->context))
2778 const rdpSettings* settings = cctx->context.settings;
2780 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2781 AAD_WELLKNOWN_authorization_endpoint);
2784 if (!client_id || !ep || !scope)
2787 char* redirect_uri = get_redirect_uri(settings);
2791 char* url =
nullptr;
2793 const char* code = va_arg(ap,
const char*);
2794 winpr_asprintf(&url, plen,
2795 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2796 code, client_id, scope, redirect_uri);
2801WINPR_ATTR_MALLOC(free, 1)
2802static
char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2805 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2809 if (!cctx || !requireRdpClientContext(&cctx->context))
2812 const rdpSettings* settings = cctx->context.settings;
2813 char* url =
nullptr;
2814 char* redirect_uri = get_redirect_uri(settings);
2817 if (!client_id || !redirect_uri)
2821 const char* scope = va_arg(ap,
const char*);
2826 const char* ep = freerdp_utils_aad_get_wellknown_string(
2827 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2828 winpr_asprintf(&url, plen,
2829 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2830 client_id, scope, redirect_uri);
2839WINPR_ATTR_MALLOC(free, 1)
2840static
char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2843 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2847 if (!cctx || !requireRdpClientContext(&cctx->context))
2850 const rdpSettings* settings = cctx->context.settings;
2852 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2853 AAD_WELLKNOWN_authorization_endpoint);
2854 const char* scope = va_arg(ap,
const char*);
2855 const char* code = va_arg(ap,
const char*);
2856 const char* req_cnf = va_arg(ap,
const char*);
2858 if (!client_id || !ep || !scope || !code || !req_cnf)
2861 char* redirect_uri = get_redirect_uri(settings);
2865 char* url =
nullptr;
2869 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2870 code, client_id, scope, redirect_uri, req_cnf);
2876char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2879 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2881 if (!cctx || !requireRdpClientContext(&cctx->context))
2884 char* str =
nullptr;
2887 va_list ap = WINPR_C_ARRAY_INIT;
2891#if defined(WITH_AAD)
2892 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2893 if (freerdp_oauth2_reset(cctx->oauth2))
2894 str = aad_auth_request(cctx, ap, &len);
2896 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2897 str = aad_token_request(cctx, ap, &len);
2899 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2900 if (freerdp_oauth2_reset(cctx->oauth2))
2901 str = avd_auth_request(cctx, ap, &len);
2903 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2904 str = avd_token_request(cctx, ap, &len);
2912 char* safestr = freerdp_oauth2_append_state(cctx->oauth2, str, len,
nullptr);
2917BOOL client_common_save_session_info(WINPR_ATTR_UNUSED rdpContext* context, UINT32 type,
2920 char buffer[128] = WINPR_C_ARRAY_INIT;
2921 WLog_INFO(TAG,
"%s [%s]", freerdp_session_logon_type_str(type),
2922 freerdp_session_logon_type_data_str(type, data, buffer,
sizeof(buffer)));
2926char* freerdp_client_extract_aad_code(rdpClientContext* cctx,
const char* data,
size_t length)
2929 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2931 if (!cctx || !requireRdpClientContext(&cctx->context))
2933 return freerdp_oauth2_extract_code(cctx->oauth2, data, length);
2937static BOOL client_helper_get_access_token_va(freerdp* instance,
2938 WINPR_ATTR_UNUSED AccessTokenType tokenType,
2939 WINPR_ATTR_UNUSED
char** token,
2940 WINPR_ATTR_UNUSED
size_t count, va_list ap)
2942 WINPR_ASSERT(instance);
2943 WINPR_ASSERT(token);
2947 WINPR_ASSERT(requireRdpClientContext(instance->context));
2949#if defined(WITH_AAD)
2950 rdpClientContext* cctx = (rdpClientContext*)instance->context;
2953 aad_auth_helper_stop(cctx->aadHelper);
2954 cctx->aadHelper = aad_auth_helper_start(cctx);
2955 if (!cctx->aadHelper)
2959 aad_auth_helper_get_access_token_v(cctx->aadHelper, tokenType, token, count, ap);
2960 aad_auth_helper_stop(cctx->aadHelper);
2961 cctx->aadHelper =
nullptr;
2964 WLog_ERR(TAG,
"Build does not support AAD authentication");
2969BOOL client_failsafe_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
2973 va_list ap = WINPR_C_ARRAY_INIT;
2974 va_start(ap, count);
2975 const BOOL rc = client_helper_get_access_token_va(instance, tokenType, token, count, ap);
2981 va_list ap = WINPR_C_ARRAY_INIT;
2982 va_start(ap, count);
2983 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
2989BOOL client_helper_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
2992 va_list ap = WINPR_C_ARRAY_INIT;
2993 va_start(ap, count);
2994 const BOOL rc = client_helper_get_access_token_va(instance, tokenType, token, count, ap);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.