21#include <winpr/cast.h>
22#include <winpr/i18n.h>
24#include <freerdp/config.h>
32#include <freerdp/client.h>
34#include <freerdp/freerdp.h>
35#include <freerdp/addin.h>
36#include <freerdp/assistance.h>
37#include <freerdp/client/file.h>
38#include <freerdp/utils/passphrase.h>
39#include <freerdp/client/cmdline.h>
40#include <freerdp/client/channels.h>
41#include <freerdp/event.h>
42#include <freerdp/utils/smartcardlogon.h>
43#include <freerdp/session.h>
45#if defined(CHANNEL_AINPUT_CLIENT)
46#include <freerdp/client/ainput.h>
47#include <freerdp/channels/ainput.h>
50#if defined(CHANNEL_VIDEO_CLIENT)
51#include <freerdp/client/video.h>
52#include <freerdp/channels/video.h>
55#if defined(CHANNEL_RDPGFX_CLIENT)
56#include <freerdp/client/rdpgfx.h>
57#include <freerdp/channels/rdpgfx.h>
58#include <freerdp/gdi/gfx.h>
61#if defined(CHANNEL_GEOMETRY_CLIENT)
62#include <freerdp/client/geometry.h>
63#include <freerdp/channels/geometry.h>
66#if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
67#include <freerdp/gdi/video.h>
70#include <freerdp/channels/rdpewa.h>
73#include <freerdp/utils/http.h>
74#include <freerdp/utils/aad.h>
75#include <freerdp/client/aad_helper.h>
79#include "sso_mib_tokens.h"
84#include <freerdp/log.h>
86BOOL freerdp_client_enable_translation(
const char* locale,
const char* searchPath)
88 return freerdp_enable_translation(locale, searchPath) &&
89 winpr_i18n_bind_domain(
"freerdp-client", searchPath);
91#define TAG CLIENT_TAG("common")
96 window_events_fkt_t window_events;
98} handle_window_events_t;
101static BOOL requireRdpClientContext(
const rdpContext* context)
105 WLog_ERR(TAG,
"[APPLICATION BUG] Function must be called with a context != NULL!");
109 freerdp* instance = context->instance;
113 "[APPLICATION BUG] Function must be called with a context->instance != NULL!");
117 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
120 WLog_ERR(TAG,
"[APPLICATION BUG] Function must be called with a "
121 "context->instance->pclientEntryPoints != NULL!");
127 if (
sizeof(rdpClientContext) > instance->ContextSize)
131 "[APPLICATION BUG] Function must be called with a context based on rdpClientContext!");
133 "[APPLICATION BUG] sizeof(rdpClientContext)[%" PRIuz
134 "] > instance->ContextSize[%" PRIuz
"])",
135 sizeof(rdpClientContext), instance->ContextSize);
142static void set_default_callbacks(freerdp* instance)
144 WINPR_ASSERT(instance);
145 instance->AuthenticateEx = client_cli_authenticate_ex;
146 instance->ChooseSmartcard = client_cli_choose_smartcard;
147 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
148 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
149 instance->PresentGatewayMessage = client_cli_present_gateway_message;
150 instance->LogonErrorInfo = client_cli_logon_error_info;
151 instance->GetAccessToken = client_cli_get_access_token;
152 instance->RetryDialog = client_common_retry_dialog;
154 WINPR_ASSERT(instance->context);
155 WINPR_ASSERT(instance->context->update);
156 instance->context->update->SaveSessionInfo = client_common_save_session_info;
159static void client_cli_user_notification(
void* context,
const UserNotificationEventArgs* e)
161 WINPR_UNUSED(context);
163 if (strcmp(e->e.Sender, RDPEWA_CHANNEL_NAME) != 0)
166 if (!e->message || e->message[0] ==
'\0')
168 (void)fprintf(stderr,
"[%s] Touch the security key\n", e->e.Sender);
169 (void)fflush(stderr);
173static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
175 WINPR_ASSERT(instance);
176 WINPR_ASSERT(context);
178 instance->LoadChannels = freerdp_client_load_channels;
179 set_default_callbacks(instance);
181 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
182 WINPR_ASSERT(pEntryPoints);
184 if (requireRdpClientContext(context))
186 rdpClientContext* cctx = (rdpClientContext*)context;
187 cctx->oauth2 = freerdp_oauth2_new();
192 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
195static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
197 WINPR_ASSERT(instance);
198 WINPR_ASSERT(context);
200 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
201 WINPR_ASSERT(pEntryPoints);
202 IFCALL(pEntryPoints->ClientFree, instance, context);
204 if (requireRdpClientContext(context))
206 rdpClientContext* cctx = (rdpClientContext*)context;
207 freerdp_oauth2_free(cctx->oauth2);
208 cctx->oauth2 =
nullptr;
214rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
216 freerdp* instance =
nullptr;
217 rdpContext* context =
nullptr;
222 if (!IFCALLRESULT(TRUE, pEntryPoints->GlobalInit))
225 instance = freerdp_new();
230 instance->ContextSize = pEntryPoints->ContextSize;
231 instance->ContextNew = freerdp_client_common_new;
232 instance->ContextFree = freerdp_client_common_free;
233 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
235 if (!instance->pClientEntryPoints)
238 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
240 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
243 context = instance->context;
244 context->instance = instance;
246#if defined(WITH_CLIENT_CHANNELS)
247 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
254 free(instance->pClientEntryPoints);
256 freerdp_free(instance);
260void freerdp_client_context_free(rdpContext* context)
262 freerdp* instance =
nullptr;
267 instance = context->instance;
271 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
272 freerdp_context_free(instance);
275 IFCALL(pEntryPoints->GlobalUninit);
277 free(instance->pClientEntryPoints);
278 freerdp_free(instance);
282int freerdp_client_start(rdpContext* context)
284 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
286 if (!context || !context->instance || !context->instance->pClientEntryPoints)
287 return ERROR_BAD_ARGUMENTS;
291 set_default_callbacks(context->instance);
295 PubSub_SubscribeUserNotification(context->pubSub, client_cli_user_notification);
302 if (requireRdpClientContext(context))
304 rdpClientContext* client_context = (rdpClientContext*)context;
305 client_context->mibClientWrapper = sso_mib_new(context);
306 if (!client_context->mibClientWrapper)
307 return ERROR_INTERNAL_ERROR;
311 pEntryPoints = context->instance->pClientEntryPoints;
312 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
315int freerdp_client_stop(rdpContext* context)
317 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
319 if (!context || !context->instance || !context->instance->pClientEntryPoints)
320 return ERROR_BAD_ARGUMENTS;
322 pEntryPoints = context->instance->pClientEntryPoints;
323 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
326 PubSub_UnsubscribeUserNotification(context->pubSub, client_cli_user_notification);
329 if (requireRdpClientContext(context))
331 rdpClientContext* client_context = (rdpClientContext*)context;
332 sso_mib_free(client_context->mibClientWrapper);
333 client_context->mibClientWrapper =
nullptr;
339freerdp* freerdp_client_get_instance(rdpContext* context)
341 if (!context || !context->instance)
344 return context->instance;
347HANDLE freerdp_client_get_thread(rdpContext* context)
352 WINPR_ASSERT(requireRdpClientContext(context));
353 if (!requireRdpClientContext(context))
356 return ((rdpClientContext*)context)->thread;
360static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
385 settings, FreeRDP_GatewayPassword,
423int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
427 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown,
428 nullptr, 0,
nullptr,
nullptr);
431int freerdp_client_settings_parse_command_line_ex(
433 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
443 status = freerdp_client_settings_parse_command_line_arguments_ex(
444 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
451 if (!freerdp_client_settings_post_process(settings))
454 const char* name = argv[0];
455 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
456 freerdp_get_build_config());
460int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
462 rdpFile* file =
nullptr;
464 file = freerdp_client_rdp_file_new();
469 if (!freerdp_client_parse_rdp_file(file, filename))
472 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
477 freerdp_client_rdp_file_free(file);
481int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
484 rdpFile* file =
nullptr;
486 file = freerdp_client_rdp_file_new();
491 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
492 freerdp_client_populate_settings_from_rdp_file(file, settings))
497 freerdp_client_rdp_file_free(file);
501int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
504 rdpFile* file =
nullptr;
506 file = freerdp_client_rdp_file_new();
511 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
514 if (!freerdp_client_write_rdp_file(file, filename, unicode))
519 freerdp_client_rdp_file_free(file);
523int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
527 char* filename =
nullptr;
528 char* password =
nullptr;
529 rdpAssistanceFile* file =
nullptr;
531 if (!settings || !argv || (argc < 2))
536 for (
int x = 2; x < argc; x++)
538 const char* key = strstr(argv[x],
"assistance:");
542 char* sep = strchr(key,
':');
550 file = freerdp_assistance_file_new();
555 status = freerdp_assistance_parse_file(file, filename, password);
560 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
565 freerdp_assistance_file_free(file);
570static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
573 WINPR_ASSERT(instance);
575 WINPR_ASSERT(result);
579 (void)fflush(stdout);
581 char* line =
nullptr;
582 if (suggestion && strlen(suggestion) > 0)
584 line = _strdup(suggestion);
585 size = strlen(suggestion);
588 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
591 char ebuffer[256] = WINPR_C_ARRAY_INIT;
592 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
593 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
603 line = StrSep(&line,
"\r");
604 line = StrSep(&line,
"\n");
626static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
627 char** password,
char** domain)
629 static const size_t password_size = 512;
630 const char* userAuth =
"Username: ";
631 const char* domainAuth =
"Domain: ";
632 const char* pwdAuth =
"Password: ";
633 BOOL pinOnly = FALSE;
634 BOOL queryAll = FALSE;
636 WINPR_ASSERT(instance);
637 WINPR_ASSERT(instance->context);
638 WINPR_ASSERT(instance->context->settings);
642 case AUTH_SMARTCARD_PIN:
643 pwdAuth =
"Smartcard-Pin: ";
647 pwdAuth =
"FIDO2 PIN: ";
660 userAuth =
"GatewayUsername: ";
661 domainAuth =
"GatewayDomain: ";
662 pwdAuth =
"GatewayPassword: ";
668 if (!username || !password || !domain)
673 const char* suggest = *username;
674 if (queryAll || !suggest)
676 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
684 const char* suggest = *domain;
685 if (queryAll || !suggest)
687 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
694 char* line = calloc(password_size,
sizeof(
char));
699 const BOOL fromStdin =
702 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
706 if (password_size > 0)
724BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
725 rdp_auth_reason reason)
727 WINPR_ASSERT(instance);
728 WINPR_ASSERT(username);
729 WINPR_ASSERT(password);
730 WINPR_ASSERT(domain);
740 case AUTH_SMARTCARD_PIN:
742 if ((*username) && (*password))
753 return client_cli_authenticate_raw(instance, reason, username, password, domain);
756BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
757 DWORD count, DWORD* choice, BOOL gateway)
759 unsigned long answer = 0;
762 printf(
"Multiple smartcards are available for use:\n");
763 for (DWORD i = 0; i < count; i++)
766 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
767 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
770 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
771 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
772 cert->issuer, cert->upn);
775 free(container_name);
780 char input[10] = WINPR_C_ARRAY_INIT;
782 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
783 gateway ?
"gateway authentication" :
"logon", count - 1);
784 (void)fflush(stdout);
785 if (!fgets(input, 10, stdin))
787 WLog_ERR(TAG,
"could not read from stdin");
791 answer = strtoul(input, &p, 10);
792 if ((*p ==
'\n' && p != input) && answer < count)
794 *choice = (UINT32)answer;
800#if defined(WITH_FREERDP_DEPRECATED)
801BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
805 WLog_INFO(TAG,
"Authentication via smartcard");
809 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
812BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
814 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
819static DWORD client_cli_accept_certificate(freerdp* instance)
823 WINPR_ASSERT(instance);
824 WINPR_ASSERT(instance->context);
826 const rdpSettings* settings = instance->context->settings;
827 WINPR_ASSERT(settings);
835 printf(
"Do you trust the above certificate? (Y/T/N) ");
836 (void)fflush(stdout);
837 answer = freerdp_interruptible_getc(instance->context, stdin);
839 if ((answer == EOF) || feof(stdin))
841 printf(
"\nError: Could not read answer from stdin.\n");
849 answer = freerdp_interruptible_getc(instance->context, stdin);
857 answer = freerdp_interruptible_getc(instance->context, stdin);
865 answer = freerdp_interruptible_getc(instance->context, stdin);
890#if defined(WITH_FREERDP_DEPRECATED)
891DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
892 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
894 WINPR_UNUSED(common_name);
895 WINPR_UNUSED(host_mismatch);
897 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
898 printf(
"Certificate details:\n");
899 printf(
"\tSubject: %s\n", subject);
900 printf(
"\tIssuer: %s\n", issuer);
901 printf(
"\tThumbprint: %s\n", fingerprint);
902 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
903 "the CA certificate in your certificate store, or the certificate has expired.\n"
904 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
905 return client_cli_accept_certificate(instance);
909WINPR_ATTR_MALLOC(free, 1)
910static
char* client_cli_pem_cert(const
char* pem)
912 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
916 char* fp = freerdp_certificate_get_fingerprint(cert);
917 char* start = freerdp_certificate_get_validity(cert, TRUE);
918 char* end = freerdp_certificate_get_validity(cert, FALSE);
919 freerdp_certificate_free(cert);
923 winpr_asprintf(&str, &slen,
926 "\tThumbprint: %s\n",
949DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
950 const char* common_name,
const char* subject,
951 const char* issuer,
const char* fingerprint, DWORD flags)
953 const char* type =
"RDP-Server";
955 WINPR_ASSERT(instance);
956 WINPR_ASSERT(instance->context);
957 WINPR_ASSERT(instance->context->settings);
959 if (flags & VERIFY_CERT_FLAG_GATEWAY)
960 type =
"RDP-Gateway";
962 if (flags & VERIFY_CERT_FLAG_REDIRECT)
963 type =
"RDP-Redirect";
965 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
966 printf(
"\tCommon Name: %s\n", common_name);
967 printf(
"\tSubject: %s\n", subject);
968 printf(
"\tIssuer: %s\n", issuer);
972 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
974 char* str = client_cli_pem_cert(fingerprint);
979 printf(
"\tThumbprint: %s\n", fingerprint);
981 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
982 "the CA certificate in your certificate store, or the certificate has expired.\n"
983 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
984 return client_cli_accept_certificate(instance);
1002#if defined(WITH_FREERDP_DEPRECATED)
1003DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
1004 const char* subject,
const char* issuer,
1005 const char* fingerprint,
const char* old_subject,
1006 const char* old_issuer,
const char* old_fingerprint)
1008 WINPR_UNUSED(common_name);
1010 printf(
"WARNING: This callback is deprecated, migrate to "
1011 "client_cli_verify_changed_certificate_ex\n");
1012 printf(
"!!! Certificate has changed !!!\n");
1014 printf(
"New Certificate details:\n");
1015 printf(
"\tSubject: %s\n", subject);
1016 printf(
"\tIssuer: %s\n", issuer);
1017 printf(
"\tThumbprint: %s\n", fingerprint);
1019 printf(
"Old Certificate details:\n");
1020 printf(
"\tSubject: %s\n", old_subject);
1021 printf(
"\tIssuer: %s\n", old_issuer);
1022 printf(
"\tThumbprint: %s\n", old_fingerprint);
1024 printf(
"The above X.509 certificate does not match the certificate used for previous "
1026 "This may indicate that the certificate has been tampered with.\n"
1027 "Please contact the administrator of the RDP server and clarify.\n");
1028 return client_cli_accept_certificate(instance);
1051DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
1052 const char* common_name,
const char* subject,
1053 const char* issuer,
const char* fingerprint,
1054 const char* old_subject,
const char* old_issuer,
1055 const char* old_fingerprint, DWORD flags)
1057 const char* type =
"RDP-Server";
1059 WINPR_ASSERT(instance);
1060 WINPR_ASSERT(instance->context);
1061 WINPR_ASSERT(instance->context->settings);
1063 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1064 type =
"RDP-Gateway";
1066 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1067 type =
"RDP-Redirect";
1069 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
1071 printf(
"New Certificate details:\n");
1072 printf(
"\tCommon Name: %s\n", common_name);
1073 printf(
"\tSubject: %s\n", subject);
1074 printf(
"\tIssuer: %s\n", issuer);
1078 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1080 char* str = client_cli_pem_cert(fingerprint);
1085 printf(
"\tThumbprint: %s\n", fingerprint);
1087 printf(
"Old Certificate details:\n");
1088 printf(
"\tSubject: %s\n", old_subject);
1089 printf(
"\tIssuer: %s\n", old_issuer);
1093 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1095 char* str = client_cli_pem_cert(old_fingerprint);
1100 printf(
"\tThumbprint: %s\n", old_fingerprint);
1102 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
1104 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
1105 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
1106 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
1107 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
1110 printf(
"The above X.509 certificate does not match the certificate used for previous "
1112 "This may indicate that the certificate has been tampered with.\n"
1113 "Please contact the administrator of the RDP server and clarify.\n");
1114 return client_cli_accept_certificate(instance);
1117BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1118 BOOL isConsentMandatory,
size_t length,
1119 const WCHAR* message)
1121 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
1123 WINPR_ASSERT(instance);
1124 WINPR_ASSERT(instance->context);
1125 WINPR_ASSERT(instance->context->settings);
1127 if (!isDisplayMandatory && !isConsentMandatory)
1130 printf(
"%s:\n", msgType);
1132 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR),
nullptr);
1135 printf(
"Failed to convert message!\n");
1138 printf(
"%s\n", msg);
1142 while (isConsentMandatory)
1144 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1145 (void)fflush(stdout);
1146 const int answer = freerdp_interruptible_getc(instance->context, stdin);
1148 if ((answer == EOF) || feof(stdin))
1150 printf(
"\nError: Could not read answer from stdin.\n");
1154 const int confirm = freerdp_interruptible_getc(instance->context, stdin);
1160 return confirm != EOF;
1175#if defined(WITH_AAD)
1177static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1178 const char* req_cnf,
char** token)
1180 WINPR_ASSERT(instance);
1181 WINPR_ASSERT(instance->context);
1184 char* url =
nullptr;
1185 char* token_request =
nullptr;
1187 WINPR_ASSERT(scope);
1188 WINPR_ASSERT(req_cnf);
1189 WINPR_ASSERT(token);
1194 WINPR_ASSERT(requireRdpClientContext(instance->context));
1195 if (!requireRdpClientContext(instance->context))
1198 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1199 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1201 printf(
"Browse to: %s\n", request);
1202 winpr_zfree(request);
1203 printf(
"Paste redirect URL here: \n");
1205 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1210 freerdp_client_extract_aad_code((rdpClientContext*)instance->context, url, size);
1214 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1215 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1221 rc = client_common_get_access_token(instance, token_request, token);
1224 winpr_zfree(token_request);
1226 return rc && (*token !=
nullptr);
1230static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1232 WINPR_ASSERT(instance);
1233 WINPR_ASSERT(instance->context);
1235 WINPR_ASSERT(requireRdpClientContext(instance->context));
1236 if (!requireRdpClientContext(instance->context))
1240 char* url =
nullptr;
1241 char* token_request =
nullptr;
1243 WINPR_ASSERT(token);
1249 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1250 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1253 printf(
"Browse to: %s\n", request);
1254 winpr_zfree(request);
1255 printf(
"Paste redirect URL here: \n");
1257 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1262 freerdp_client_extract_aad_code((rdpClientContext*)instance->context, url, size);
1265 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1266 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1273 rc = client_common_get_access_token(instance, token_request, token);
1276 free(token_request);
1278 return rc && (*token !=
nullptr);
1283static BOOL client_cli_get_access_token_va(freerdp* instance,
1284 WINPR_ATTR_UNUSED AccessTokenType tokenType,
1285 char** token, WINPR_ATTR_UNUSED
size_t count, va_list ap)
1287 WINPR_ASSERT(instance);
1288 WINPR_ASSERT(token);
1291#if !defined(WITH_AAD)
1292 WLog_ERR(TAG,
"Build does not support AAD authentication");
1296 WINPR_ASSERT(instance->context);
1305 case ACCESS_TOKEN_TYPE_AAD:
1310 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1319 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1322 const char* scope = va_arg(ap,
const char*);
1323 const char* req_cnf = va_arg(ap,
const char*);
1324 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1328 case ACCESS_TOKEN_TYPE_AVD:
1331 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1334 rc = client_cli_get_avd_access_token(instance, token);
1337 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%u], aborting", tokenType);
1348BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1351 va_list ap = WINPR_C_ARRAY_INIT;
1352 va_start(ap, count);
1353 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
1358BOOL client_common_get_access_token(WINPR_ATTR_UNUSED freerdp* instance,
1359 WINPR_ATTR_UNUSED
const char* request,
1360 WINPR_ATTR_UNUSED
char** token)
1362 WINPR_ASSERT(request);
1363 WINPR_ASSERT(token);
1369 BYTE* response =
nullptr;
1370 size_t response_length = 0;
1372 wLog* log = WLog_Get(TAG);
1374 const char* token_ep =
1375 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1376 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1378 WLog_ERR(TAG,
"access token request failed");
1382 if (resp_code != HTTP_STATUS_OK)
1384 char buffer[64] = WINPR_C_ARRAY_INIT;
1386 WLog_Print(log, WLOG_ERROR,
1387 "Server unwilling to provide access token; returned status code %s",
1388 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1389 if (response_length > 0)
1390 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1394 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1402 WLog_ERR(TAG,
"Build does not support AAD authentication");
1407SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1410 WINPR_UNUSED(instance);
1411 WINPR_ASSERT(instance->context);
1412 WINPR_UNUSED(userarg);
1413 WINPR_ASSERT(instance);
1416 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1418 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1424 if (strcmp(what,
"arm-transport") == 0)
1425 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1428 const rdpSettings* settings = instance->context->settings;
1432 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1441 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1442 "tech support for help if this keeps happening.",
1447 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1448 what, current + 1, max, delay);
1449 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1452BOOL client_auto_reconnect(freerdp* instance)
1454 return client_auto_reconnect_ex(instance,
nullptr);
1458static BOOL client_auto_reconnect_do(freerdp* instance, BOOL retry, UINT32 numRetries,
1461 WINPR_ASSERT(instance);
1467 if ((maxRetries > 0) && (numRetries >= maxRetries))
1469 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1474 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1476 const SSIZE_T delay =
1477 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1482 if (freerdp_reconnect(instance))
1485 switch (freerdp_get_last_error(instance->context))
1487 case FREERDP_ERROR_CONNECT_CANCELLED:
1488 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1494 for (SSIZE_T x = 0; x < delay / 10; x++)
1498 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1503static DWORD WINAPI handle_window_events(
void* parg)
1505 handle_window_events_t* arg = parg;
1508 while (arg->running)
1510 WINPR_ASSERT(arg->window_events);
1511 if (!arg->window_events(arg->instance))
1513 WLog_ERR(TAG,
"window_events failed!");
1520BOOL client_auto_reconnect_ex(freerdp* instance, window_events_fkt_t window_events)
1524 UINT32 numRetries = 0;
1525 rdpSettings* settings =
nullptr;
1530 WINPR_ASSERT(instance->context);
1532 settings = instance->context->settings;
1533 WINPR_ASSERT(settings);
1535 const UINT32 maxRetries =
1539 error = freerdp_error_info(instance);
1542 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1544 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1545 freerdp_get_error_info_string(error));
1547 case ERRINFO_SUCCESS:
1549 WLog_INFO(TAG,
"Network disconnect!");
1552 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1559 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1563 const UINT err = freerdp_get_last_error(instance->context);
1566 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1567 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1568 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1569 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1570 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1571 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1572 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1573 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1574 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1575 freerdp_get_last_error_name(err));
1577 case FREERDP_ERROR_CONNECT_CANCELLED:
1578 WLog_WARN(TAG,
"Connection aborted by user");
1584 handle_window_events_t arg = { .instance = instance,
1585 .window_events = window_events,
1587 HANDLE thread =
nullptr;
1589 thread = CreateThread(
nullptr, 0, handle_window_events, &arg, 0,
nullptr);
1590 const BOOL rc = client_auto_reconnect_do(instance, retry, numRetries, maxRetries);
1593 arg.running = FALSE;
1594 WaitForSingleObject(thread, INFINITE);
1595 CloseHandle(thread);
1600int freerdp_client_common_stop(rdpContext* context)
1602 freerdp_abort_connect_context(context);
1604 if (requireRdpClientContext(context))
1607 rdpClientContext* cctx = (rdpClientContext*)context;
1611 (void)WaitForSingleObject(cctx->thread, INFINITE);
1612 (void)CloseHandle(cctx->thread);
1613 cctx->thread =
nullptr;
1615#if defined(WITH_AAD)
1616 aad_auth_helper_stop(cctx->aadHelper);
1617 cctx->aadHelper =
nullptr;
1624#if defined(CHANNEL_ENCOMSP_CLIENT)
1625BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1632 rdpClientContext* cctx = (rdpClientContext*)encomsp->custom;
1634 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1635 if (!cctx || !requireRdpClientContext(&cctx->context))
1638 state = cctx->controlToggle;
1639 cctx->controlToggle = !cctx->controlToggle;
1640 return freerdp_client_encomsp_set_control(encomsp, state);
1643BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1650 pdu.ParticipantId = encomsp->participantId;
1651 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1654 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1656 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1657 return rc == CHANNEL_RC_OK;
1661client_encomsp_participant_created(EncomspClientContext* context,
1666 if (!context || !context->custom || !participantCreated)
1667 return ERROR_INVALID_PARAMETER;
1669 rdpClientContext* cctx = (rdpClientContext*)context->custom;
1671 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1672 if (!cctx || !requireRdpClientContext(&cctx->context))
1673 return ERROR_INVALID_PARAMETER;
1675 rdpSettings* settings = cctx->context.settings;
1676 WINPR_ASSERT(settings);
1678 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1679 context->participantId = participantCreated->ParticipantId;
1682 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1683 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1685 if (!freerdp_client_encomsp_set_control(context, TRUE))
1686 return ERROR_INTERNAL_ERROR;
1692 return ERROR_INTERNAL_ERROR;
1695 return CHANNEL_RC_OK;
1698static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1701 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1702 if (!cctx || !requireRdpClientContext(&cctx->context))
1705 cctx->encomsp = encomsp;
1706 encomsp->custom = (
void*)cctx;
1707 encomsp->ParticipantCreated = client_encomsp_participant_created;
1710static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1714 encomsp->custom =
nullptr;
1715 encomsp->ParticipantCreated =
nullptr;
1720 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1721 if (requireRdpClientContext(&cctx->context))
1722 cctx->encomsp =
nullptr;
1727void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1728 const ChannelConnectedEventArgs* e)
1730 rdpClientContext* cctx = (rdpClientContext*)context;
1738#if defined(CHANNEL_AINPUT_CLIENT)
1739 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1742 WINPR_ASSERT(requireRdpClientContext(context));
1743 if (!requireRdpClientContext(context))
1745 cctx->ainput = (AInputClientContext*)e->pInterface;
1748#if defined(CHANNEL_RDPEI_CLIENT)
1749 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1751 WINPR_ASSERT(requireRdpClientContext(context));
1752 if (!requireRdpClientContext(context))
1754 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1757#if defined(CHANNEL_RDPGFX_CLIENT)
1758 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1760 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1763#if defined(CHANNEL_GEOMETRY_CLIENT)
1764 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1766 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1769#if defined(CHANNEL_VIDEO_CLIENT)
1770 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1772 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1774 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1776 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1779#if defined(CHANNEL_ENCOMSP_CLIENT)
1780 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1782 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1787void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1788 const ChannelDisconnectedEventArgs* e)
1790 rdpClientContext* cctx = (rdpClientContext*)context;
1798#if defined(CHANNEL_AINPUT_CLIENT)
1799 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1801 WINPR_ASSERT(requireRdpClientContext(context));
1802 if (!requireRdpClientContext(context))
1804 cctx->ainput =
nullptr;
1807#if defined(CHANNEL_RDPEI_CLIENT)
1808 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1810 WINPR_ASSERT(requireRdpClientContext(context));
1811 if (!requireRdpClientContext(context))
1813 cctx->rdpei =
nullptr;
1816#if defined(CHANNEL_RDPGFX_CLIENT)
1817 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1819 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1822#if defined(CHANNEL_GEOMETRY_CLIENT)
1823 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1825 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1828#if defined(CHANNEL_VIDEO_CLIENT)
1829 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1831 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1833 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1835 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1838#if defined(CHANNEL_ENCOMSP_CLIENT)
1839 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1841 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1846BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1848 BOOL handled = FALSE;
1851 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1852 if (!cctx || !requireRdpClientContext(&cctx->context))
1855 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1856 if (state != CONNECTION_STATE_ACTIVE)
1859#if defined(CHANNEL_AINPUT_CLIENT)
1866 INT32 value = mflags & 0xFF;
1868 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1869 value = -1 * (0x100 - value);
1875 if (mflags & PTR_FLAGS_WHEEL)
1877 flags |= AINPUT_FLAGS_WHEEL;
1881 if (mflags & PTR_FLAGS_HWHEEL)
1883 flags |= AINPUT_FLAGS_WHEEL;
1887 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1888 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1889 if (rc == CHANNEL_RC_OK)
1895 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1900#if defined(CHANNEL_AINPUT_CLIENT)
1902static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1905 WINPR_ASSERT(cctx->ainput);
1906 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1907 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1909 if (!cctx || !requireRdpClientContext(&cctx->context))
1910 return ERROR_INVALID_PARAMETER;
1912 const UINT rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1914 return rc == CHANNEL_RC_OK;
1919static bool button_pressed(
const rdpClientContext* cctx)
1922 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1923 if (!cctx || !requireRdpClientContext(&cctx->context))
1926 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1928 const BOOL cur = cctx->pressed_buttons[x];
1935BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1938 BOOL handled = FALSE;
1941 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1942 if (!cctx || !requireRdpClientContext(&cctx->context))
1945 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1946 if (state != CONNECTION_STATE_ACTIVE)
1949 if (mflags & PTR_FLAGS_BUTTON1)
1950 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1951 if (mflags & PTR_FLAGS_BUTTON2)
1952 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1953 if (mflags & PTR_FLAGS_BUTTON3)
1954 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1956 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1959 if (!button_pressed(cctx))
1963 const BOOL haveRelative =
1965 if (relative && haveRelative)
1967 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1968 WINPR_ASSERTING_INT_CAST(int16_t, x),
1969 WINPR_ASSERTING_INT_CAST(int16_t, y));
1972#if defined(CHANNEL_AINPUT_CLIENT)
1977 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1978 flags |= AINPUT_FLAGS_HAVE_REL;
1981 flags |= AINPUT_FLAGS_REL;
1983 if (mflags & PTR_FLAGS_DOWN)
1984 flags |= AINPUT_FLAGS_DOWN;
1985 if (mflags & PTR_FLAGS_BUTTON1)
1986 flags |= AINPUT_FLAGS_BUTTON1;
1987 if (mflags & PTR_FLAGS_BUTTON2)
1988 flags |= AINPUT_FLAGS_BUTTON2;
1989 if (mflags & PTR_FLAGS_BUTTON3)
1990 flags |= AINPUT_FLAGS_BUTTON3;
1991 if (mflags & PTR_FLAGS_MOVE)
1992 flags |= AINPUT_FLAGS_MOVE;
1993 handled = ainput_send_diff_event(cctx, flags, x, y);
2003 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2010 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2011 (UINT16)cctx->lastY);
2016BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
2019 BOOL handled = FALSE;
2021 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2023 if (!cctx || !requireRdpClientContext(&cctx->context))
2026 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2027 if (state != CONNECTION_STATE_ACTIVE)
2030 if (mflags & PTR_XFLAGS_BUTTON1)
2031 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
2032 if (mflags & PTR_XFLAGS_BUTTON2)
2033 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
2035 const BOOL haveRelative =
2037 if (relative && haveRelative)
2039 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
2040 WINPR_ASSERTING_INT_CAST(int16_t, x),
2041 WINPR_ASSERTING_INT_CAST(int16_t, y));
2044#if defined(CHANNEL_AINPUT_CLIENT)
2050 flags |= AINPUT_FLAGS_REL;
2051 if (mflags & PTR_XFLAGS_DOWN)
2052 flags |= AINPUT_FLAGS_DOWN;
2053 if (mflags & PTR_XFLAGS_BUTTON1)
2054 flags |= AINPUT_XFLAGS_BUTTON1;
2055 if (mflags & PTR_XFLAGS_BUTTON2)
2056 flags |= AINPUT_XFLAGS_BUTTON2;
2058 handled = ainput_send_diff_event(cctx, flags, x, y);
2068 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2075 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2076 (UINT16)cctx->lastY);
2083static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
2087 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2088 if (!cctx || !requireRdpClientContext(&cctx->context))
2091 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
2092 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
2093 WINPR_ASSERT(contact);
2094 WINPR_ASSERT(contact->x <= UINT16_MAX);
2095 WINPR_ASSERT(contact->y <= UINT16_MAX);
2097 switch (contact->count)
2100 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
2101 contact->x, contact->y);
2103 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
2104 contact->x, contact->y);
2106 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
2107 contact->x, contact->y);
2109 return freerdp_client_send_extended_button_event(
2110 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2112 return freerdp_client_send_extended_button_event(
2113 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2121static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2124 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2125 WINPR_ASSERT(contact);
2127 if (!cctx || !requireRdpClientContext(&cctx->context))
2130#if defined(CHANNEL_RDPEI_CLIENT)
2131 RdpeiClientContext* rdpei = cctx->rdpei;
2134 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2138 if (rdpei->TouchRawEvent)
2140 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
2141 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2142 ? CONTACT_DATA_PRESSURE_PRESENT
2146 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2147 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2148 RDPINPUT_CONTACT_FLAG_INCONTACT,
2149 contactFlags, contact->pressure);
2150 if (rc1 != CHANNEL_RC_OK)
2153 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
2154 &contactId, flags, contactFlags, contact->pressure);
2155 if (rc2 != CHANNEL_RC_OK)
2160 WINPR_ASSERT(rdpei->TouchEnd);
2161 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2162 if (rc != CHANNEL_RC_OK)
2167 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2168 "-DCHANNEL_RDPEI_CLIENT=ON");
2169 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2174static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2177 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2178 WINPR_ASSERT(contact);
2180 if (!cctx || !requireRdpClientContext(&cctx->context))
2183#if defined(CHANNEL_RDPEI_CLIENT)
2184 RdpeiClientContext* rdpei = cctx->rdpei;
2188 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2192 if (rdpei->TouchRawEvent)
2194 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
2195 RDPINPUT_CONTACT_FLAG_INCONTACT;
2196 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2197 ? CONTACT_DATA_PRESSURE_PRESENT
2199 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2200 flags, contactFlags, contact->pressure);
2201 if (rc != CHANNEL_RC_OK)
2206 WINPR_ASSERT(rdpei->TouchBegin);
2207 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
2208 if (rc != CHANNEL_RC_OK)
2214 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2215 "-DCHANNEL_RDPEI_CLIENT=ON");
2216 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2221static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
2225 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2227 if (!cctx || !requireRdpClientContext(&cctx->context))
2230 const UINT16 flags = PTR_FLAGS_MOVE;
2232 WINPR_ASSERT(contact);
2233 WINPR_ASSERT(contact->x <= UINT16_MAX);
2234 WINPR_ASSERT(contact->y <= UINT16_MAX);
2235 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
2239static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2242 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2243 WINPR_ASSERT(contact);
2245 if (!cctx || !requireRdpClientContext(&cctx->context))
2248#if defined(CHANNEL_RDPEI_CLIENT)
2249 RdpeiClientContext* rdpei = cctx->rdpei;
2252 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2256 if (rdpei->TouchRawEvent)
2258 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2259 RDPINPUT_CONTACT_FLAG_INCONTACT;
2260 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2261 ? CONTACT_DATA_PRESSURE_PRESENT
2263 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2264 flags, contactFlags, contact->pressure);
2265 if (rc != CHANNEL_RC_OK)
2270 WINPR_ASSERT(rdpei->TouchUpdate);
2271 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2272 if (rc != CHANNEL_RC_OK)
2278 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2279 "-DCHANNEL_RDPEI_CLIENT=ON");
2280 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2285static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2288 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2289 WINPR_ASSERT(contact);
2291 if (!cctx || !requireRdpClientContext(&cctx->context))
2294#if defined(CHANNEL_RDPEI_CLIENT)
2295 RdpeiClientContext* rdpei = cctx->rdpei;
2298 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2302 if (rdpei->TouchRawEvent)
2304 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2305 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2306 ? CONTACT_DATA_PRESSURE_PRESENT
2308 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2309 flags, contactFlags, contact->pressure);
2310 if (rc != CHANNEL_RC_OK)
2315 WINPR_ASSERT(rdpei->TouchUpdate);
2316 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2317 if (rc != CHANNEL_RC_OK)
2323 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2324 "-DCHANNEL_RDPEI_CLIENT=ON");
2325 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2330static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2331 UINT32 pressure, INT32 x, INT32 y,
2335 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2336 WINPR_ASSERT(pcontact);
2338 if (!cctx || !requireRdpClientContext(&cctx->context))
2341 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2345 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2346 if (newcontact || (contact->id == touchId))
2348 contact->id = touchId;
2349 contact->flags = flags;
2350 contact->pressure = pressure;
2354 *pcontact = *contact;
2356 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2369BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2370 UINT32 pressure, INT32 x, INT32 y)
2373 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2375 if (!cctx || !requireRdpClientContext(&cctx->context))
2379 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2382 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2383 if (state != CONNECTION_STATE_ACTIVE)
2388 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2391 switch (flags & mask)
2393 case FREERDP_TOUCH_DOWN:
2394 return freerdp_handle_touch_down(cctx, &contact);
2395 case FREERDP_TOUCH_UP:
2396 return freerdp_handle_touch_up(cctx, &contact);
2397 case FREERDP_TOUCH_MOTION:
2398 return freerdp_handle_touch_motion(cctx, &contact);
2399 case FREERDP_TOUCH_CANCEL:
2400 return freerdp_handle_touch_cancel(cctx, &contact);
2402 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2407BOOL freerdp_client_load_channels(freerdp* instance)
2409 WINPR_ASSERT(instance);
2410 WINPR_ASSERT(instance->context);
2412 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2414 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2420int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2422 const char* str_data = freerdp_get_logon_error_info_data(data);
2423 const char* str_type = freerdp_get_logon_error_info_type(type);
2425 if (!instance || !instance->context)
2428 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2433static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2437 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2439 if (!cctx || !requireRdpClientContext(&cctx->context))
2442 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2445 if (deviceid == pen->deviceid)
2456static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2459 static const INT32 null_deviceid = 0;
2462 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2463 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2465 if (!cctx || !requireRdpClientContext(&cctx->context))
2468 if (freerdp_client_is_pen(cctx, deviceid))
2470 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2481 pen->deviceid = deviceid;
2482 pen->max_pressure = pressure;
2485 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2489 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2493BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2496 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2498 if (!cctx || !requireRdpClientContext(&cctx->context))
2501 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2502 if (state != CONNECTION_STATE_ACTIVE)
2505#if defined(CHANNEL_RDPEI_CLIENT)
2506 if ((flags & FREERDP_PEN_REGISTER) != 0)
2508 va_list args = WINPR_C_ARRAY_INIT;
2510 va_start(args, deviceid);
2511 double pressure = va_arg(args,
double);
2513 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2519 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2523 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2525 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2527 RdpeiClientContext* rdpei = cctx->rdpei;
2528 WINPR_ASSERT(rdpei);
2530 UINT32 normalizedpressure = 1024;
2533 UINT16 rotation = 0;
2536 va_list args = WINPR_C_ARRAY_INIT;
2537 va_start(args, deviceid);
2539 x = va_arg(args, INT32);
2540 y = va_arg(args, INT32);
2541 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2543 const double pressure = va_arg(args,
double);
2544 const double np = (pressure * 1024.0) / pen->max_pressure;
2545 normalizedpressure = (UINT32)lround(np);
2546 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2547 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2549 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2551 const unsigned arg = va_arg(args,
unsigned);
2552 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2553 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2555 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2557 const int arg = va_arg(args,
int);
2558 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2559 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2561 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2563 const int arg = va_arg(args,
int);
2564 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2565 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2569 if ((flags & FREERDP_PEN_PRESS) != 0)
2573 flags = FREERDP_PEN_MOTION |
2574 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2575 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2576 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2578 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2580 if (!pen->pressed ||
2581 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2582 flags = FREERDP_PEN_MOTION |
2583 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2585 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2588 flags |= pen->flags;
2589 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2590 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2591 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2592 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2596 if ((flags & FREERDP_PEN_PRESS) != 0)
2598 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2599 pen->hovering = FALSE;
2600 pen->pressed = TRUE;
2602 WINPR_ASSERT(rdpei->PenBegin);
2603 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2604 normalizedpressure, rotation, tiltX, tiltY);
2605 return rc == CHANNEL_RC_OK;
2607 else if ((flags & FREERDP_PEN_MOTION) != 0)
2609 UINT rc = ERROR_INTERNAL_ERROR;
2612 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2615 WINPR_ASSERT(rdpei->PenUpdate);
2616 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2617 rotation, tiltX, tiltY);
2619 else if (pen->hovering)
2621 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2623 WINPR_ASSERT(rdpei->PenHoverUpdate);
2624 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2625 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2629 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2630 pen->hovering = TRUE;
2632 WINPR_ASSERT(rdpei->PenHoverBegin);
2633 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2634 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2636 return rc == CHANNEL_RC_OK;
2638 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2640 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2641 pen->pressed = FALSE;
2642 pen->hovering = TRUE;
2644 WINPR_ASSERT(rdpei->PenUpdate);
2645 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2646 normalizedpressure, rotation, tiltX, tiltY);
2647 if (rc != CHANNEL_RC_OK)
2649 WINPR_ASSERT(rdpei->PenEnd);
2650 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2651 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2652 return re == CHANNEL_RC_OK;
2655 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2657 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2658 "-DCHANNEL_RDPEI_CLIENT=ON");
2664BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2667 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2669 if (!cctx || !requireRdpClientContext(&cctx->context))
2672 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2673 if (state != CONNECTION_STATE_ACTIVE)
2676#if defined(CHANNEL_RDPEI_CLIENT)
2677 RdpeiClientContext* rdpei = cctx->rdpei;
2682 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2687 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2688 pen->hovering = FALSE;
2690 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2691 if (rc != CHANNEL_RC_OK)
2697 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2698 "-DCHANNEL_RDPEI_CLIENT=ON");
2703BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2706 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2708 if (!cctx || !requireRdpClientContext(&cctx->context))
2714 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2717 if (pen->deviceid == deviceid)
2724BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2727 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2729 if (!cctx || !requireRdpClientContext(&cctx->context))
2732 const rdpSettings* settings = cctx->context.settings;
2735 BOOL ainput = FALSE;
2736#if defined(CHANNEL_AINPUT_CLIENT)
2737 ainput = cctx->ainput !=
nullptr;
2740 return useRelative && (haveRelative || ainput);
2743#if defined(WITH_AAD)
2744WINPR_ATTR_MALLOC(free, 1)
2745static
char* get_redirect_uri(const rdpSettings* settings)
2747 char* redirect_uri =
nullptr;
2751 const char* redirect_fmt =
2754 const char* tenantid =
"common";
2758 if (tenantid && redirect_fmt)
2763 size_t redirect_len = 0;
2764 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2770 const char* redirect_fmt =
2773 size_t redirect_len = 0;
2774 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2776 return redirect_uri;
2781WINPR_ATTR_MALLOC(free, 1)
2782static
char* get_login_hint(const rdpSettings* settings, FreeRDP_Settings_Keys_String primary,
2783 FreeRDP_Settings_Keys_String secondary)
2785 const FreeRDP_Settings_Keys_String keys[] = { primary, secondary };
2786 for (
size_t x = 0; x < ARRAYSIZE(keys); x++)
2791 if (!user || !strchr(user,
'@') || strchr(user,
'\\'))
2794 char* encoded = winpr_str_url_encode(user, strlen(user));
2798 char* param =
nullptr;
2800 winpr_asprintf(¶m, &len,
"&login_hint=%s", encoded);
2807WINPR_ATTR_MALLOC(free, 1)
2808static
char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2811 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2815 if (!cctx || !requireRdpClientContext(&cctx->context))
2818 const rdpSettings* settings = cctx->context.settings;
2820 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2821 AAD_WELLKNOWN_authorization_endpoint);
2824 if (!client_id || !ep || !scope)
2827 char* redirect_uri = get_redirect_uri(settings);
2829 char* login_hint = get_login_hint(settings, FreeRDP_GatewayUsername, FreeRDP_Username);
2830 char* url =
nullptr;
2831 if (redirect_uri && login_hint)
2832 winpr_asprintf(&url, plen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s%s",
2833 ep, client_id, scope, redirect_uri, login_hint);
2839WINPR_ATTR_MALLOC(free, 1)
2840static
char* avd_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);
2856 if (!client_id || !ep || !scope)
2859 char* redirect_uri = get_redirect_uri(settings);
2863 char* url =
nullptr;
2865 const char* code = va_arg(ap,
const char*);
2866 winpr_asprintf(&url, plen,
2867 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2868 code, client_id, scope, redirect_uri);
2873WINPR_ATTR_MALLOC(free, 1)
2874static
char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2877 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2881 if (!cctx || !requireRdpClientContext(&cctx->context))
2884 const rdpSettings* settings = cctx->context.settings;
2885 char* url =
nullptr;
2886 char* redirect_uri = get_redirect_uri(settings);
2888 char* login_hint = get_login_hint(settings, FreeRDP_Username, FreeRDP_GatewayUsername);
2891 if (!client_id || !redirect_uri || !login_hint)
2895 const char* scope = va_arg(ap,
const char*);
2900 const char* ep = freerdp_utils_aad_get_wellknown_string(
2901 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2902 winpr_asprintf(&url, plen,
2903 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s%s", ep,
2904 client_id, scope, redirect_uri, login_hint);
2914WINPR_ATTR_MALLOC(free, 1)
2915static
char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2918 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2922 if (!cctx || !requireRdpClientContext(&cctx->context))
2925 const rdpSettings* settings = cctx->context.settings;
2927 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2928 AAD_WELLKNOWN_authorization_endpoint);
2929 const char* scope = va_arg(ap,
const char*);
2930 const char* code = va_arg(ap,
const char*);
2931 const char* req_cnf = va_arg(ap,
const char*);
2933 if (!client_id || !ep || !scope || !code || !req_cnf)
2936 char* redirect_uri = get_redirect_uri(settings);
2940 char* url =
nullptr;
2944 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2945 code, client_id, scope, redirect_uri, req_cnf);
2951char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2954 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2956 if (!cctx || !requireRdpClientContext(&cctx->context))
2959 char* str =
nullptr;
2962 va_list ap = WINPR_C_ARRAY_INIT;
2966#if defined(WITH_AAD)
2967 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2968 if (freerdp_oauth2_reset(cctx->oauth2))
2969 str = aad_auth_request(cctx, ap, &len);
2971 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2972 str = aad_token_request(cctx, ap, &len);
2974 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2975 if (freerdp_oauth2_reset(cctx->oauth2))
2976 str = avd_auth_request(cctx, ap, &len);
2978 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2979 str = avd_token_request(cctx, ap, &len);
2987 char* safestr = freerdp_oauth2_append_state(cctx->oauth2, str, len,
nullptr);
2992BOOL client_common_save_session_info(WINPR_ATTR_UNUSED rdpContext* context, UINT32 type,
2995 char buffer[128] = WINPR_C_ARRAY_INIT;
2996 WLog_INFO(TAG,
"%s [%s]", freerdp_session_logon_type_str(type),
2997 freerdp_session_logon_type_data_str(type, data, buffer,
sizeof(buffer)));
3001char* freerdp_client_extract_aad_code(rdpClientContext* cctx,
const char* data,
size_t length)
3004 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
3006 if (!cctx || !requireRdpClientContext(&cctx->context))
3008 return freerdp_oauth2_extract_code(cctx->oauth2, data, length);
3012static BOOL client_helper_get_access_token_va(freerdp* instance,
3013 WINPR_ATTR_UNUSED AccessTokenType tokenType,
3014 WINPR_ATTR_UNUSED
char** token,
3015 WINPR_ATTR_UNUSED
size_t count, va_list ap)
3017 WINPR_ASSERT(instance);
3018 WINPR_ASSERT(token);
3022 WINPR_ASSERT(requireRdpClientContext(instance->context));
3024#if defined(WITH_AAD)
3025 rdpClientContext* cctx = (rdpClientContext*)instance->context;
3032 if (!aad_auth_helper_is_running(cctx->aadHelper))
3034 aad_auth_helper_stop(cctx->aadHelper);
3035 cctx->aadHelper = aad_auth_helper_start(cctx);
3036 if (!cctx->aadHelper)
3041 aad_auth_helper_get_access_token_v(cctx->aadHelper, tokenType, token, count, ap);
3044 if (!rc && !aad_auth_helper_is_running(cctx->aadHelper))
3046 aad_auth_helper_stop(cctx->aadHelper);
3047 cctx->aadHelper =
nullptr;
3051 WLog_ERR(TAG,
"Build does not support AAD authentication");
3056BOOL client_failsafe_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
3060 va_list ap = WINPR_C_ARRAY_INIT;
3061 va_start(ap, count);
3062 const BOOL rc = client_helper_get_access_token_va(instance, tokenType, token, count, ap);
3068 va_list ap = WINPR_C_ARRAY_INIT;
3069 va_start(ap, count);
3070 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
3076BOOL client_helper_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
3079 va_list ap = WINPR_C_ARRAY_INIT;
3080 va_start(ap, count);
3081 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.