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")
89 window_events_fkt_t window_events;
91} handle_window_events_t;
94static BOOL requireRdpClientContext(
const rdpContext* context)
98 WLog_ERR(TAG,
"[APPLICATION BUG] Function must be called with a context != NULL!");
102 freerdp* instance = context->instance;
106 "[APPLICATION BUG] Function must be called with a context->instance != NULL!");
110 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
113 WLog_ERR(TAG,
"[APPLICATION BUG] Function must be called with a "
114 "context->instance->pclientEntryPoints != NULL!");
120 if (
sizeof(rdpClientContext) > instance->ContextSize)
124 "[APPLICATION BUG] Function must be called with a context based on rdpClientContext!");
126 "[APPLICATION BUG] sizeof(rdpClientContext)[%" PRIuz
127 "] > instance->ContextSize[%" PRIuz
"])",
128 sizeof(rdpClientContext), instance->ContextSize);
135static void set_default_callbacks(freerdp* instance)
137 WINPR_ASSERT(instance);
138 instance->AuthenticateEx = client_cli_authenticate_ex;
139 instance->ChooseSmartcard = client_cli_choose_smartcard;
140 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
141 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
142 instance->PresentGatewayMessage = client_cli_present_gateway_message;
143 instance->LogonErrorInfo = client_cli_logon_error_info;
144 instance->GetAccessToken = client_cli_get_access_token;
145 instance->RetryDialog = client_common_retry_dialog;
147 WINPR_ASSERT(instance->context);
148 WINPR_ASSERT(instance->context->update);
149 instance->context->update->SaveSessionInfo = client_common_save_session_info;
152static void client_cli_user_notification(
void* context,
const UserNotificationEventArgs* e)
154 WINPR_UNUSED(context);
156 if (strcmp(e->e.Sender, RDPEWA_CHANNEL_NAME) != 0)
159 if (!e->message || e->message[0] ==
'\0')
161 (void)fprintf(stderr,
"[%s] Touch the security key\n", e->e.Sender);
162 (void)fflush(stderr);
166static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
168 WINPR_ASSERT(instance);
169 WINPR_ASSERT(context);
171 instance->LoadChannels = freerdp_client_load_channels;
172 set_default_callbacks(instance);
174 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
175 WINPR_ASSERT(pEntryPoints);
177 if (requireRdpClientContext(context))
179 rdpClientContext* cctx = (rdpClientContext*)context;
180 cctx->oauth2 = freerdp_oauth2_new();
185 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
188static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
190 WINPR_ASSERT(instance);
191 WINPR_ASSERT(context);
193 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
194 WINPR_ASSERT(pEntryPoints);
195 IFCALL(pEntryPoints->ClientFree, instance, context);
197 if (requireRdpClientContext(context))
199 rdpClientContext* cctx = (rdpClientContext*)context;
200 freerdp_oauth2_free(cctx->oauth2);
201 cctx->oauth2 =
nullptr;
207rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
209 freerdp* instance =
nullptr;
210 rdpContext* context =
nullptr;
215 if (!IFCALLRESULT(TRUE, pEntryPoints->GlobalInit))
218 instance = freerdp_new();
223 instance->ContextSize = pEntryPoints->ContextSize;
224 instance->ContextNew = freerdp_client_common_new;
225 instance->ContextFree = freerdp_client_common_free;
226 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
228 if (!instance->pClientEntryPoints)
231 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
233 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
236 context = instance->context;
237 context->instance = instance;
239#if defined(WITH_CLIENT_CHANNELS)
240 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
247 free(instance->pClientEntryPoints);
249 freerdp_free(instance);
253void freerdp_client_context_free(rdpContext* context)
255 freerdp* instance =
nullptr;
260 instance = context->instance;
264 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
265 freerdp_context_free(instance);
268 IFCALL(pEntryPoints->GlobalUninit);
270 free(instance->pClientEntryPoints);
271 freerdp_free(instance);
275int freerdp_client_start(rdpContext* context)
277 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
279 if (!context || !context->instance || !context->instance->pClientEntryPoints)
280 return ERROR_BAD_ARGUMENTS;
284 set_default_callbacks(context->instance);
288 PubSub_SubscribeUserNotification(context->pubSub, client_cli_user_notification);
295 if (requireRdpClientContext(context))
297 rdpClientContext* client_context = (rdpClientContext*)context;
298 client_context->mibClientWrapper = sso_mib_new(context);
299 if (!client_context->mibClientWrapper)
300 return ERROR_INTERNAL_ERROR;
304 pEntryPoints = context->instance->pClientEntryPoints;
305 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
308int freerdp_client_stop(rdpContext* context)
310 RDP_CLIENT_ENTRY_POINTS* pEntryPoints =
nullptr;
312 if (!context || !context->instance || !context->instance->pClientEntryPoints)
313 return ERROR_BAD_ARGUMENTS;
315 pEntryPoints = context->instance->pClientEntryPoints;
316 const int rc = IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
319 PubSub_UnsubscribeUserNotification(context->pubSub, client_cli_user_notification);
322 if (requireRdpClientContext(context))
324 rdpClientContext* client_context = (rdpClientContext*)context;
325 sso_mib_free(client_context->mibClientWrapper);
326 client_context->mibClientWrapper =
nullptr;
332freerdp* freerdp_client_get_instance(rdpContext* context)
334 if (!context || !context->instance)
337 return context->instance;
340HANDLE freerdp_client_get_thread(rdpContext* context)
345 WINPR_ASSERT(requireRdpClientContext(context));
346 if (!requireRdpClientContext(context))
349 return ((rdpClientContext*)context)->thread;
353static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
378 settings, FreeRDP_GatewayPassword,
416int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
420 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown,
421 nullptr, 0,
nullptr,
nullptr);
424int freerdp_client_settings_parse_command_line_ex(
426 size_t count, freerdp_command_line_handle_option_t handle_option,
void* handle_userdata)
436 status = freerdp_client_settings_parse_command_line_arguments_ex(
437 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
444 if (!freerdp_client_settings_post_process(settings))
447 const char* name = argv[0];
448 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
449 freerdp_get_build_config());
453int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
455 rdpFile* file =
nullptr;
457 file = freerdp_client_rdp_file_new();
462 if (!freerdp_client_parse_rdp_file(file, filename))
465 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
470 freerdp_client_rdp_file_free(file);
474int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
477 rdpFile* file =
nullptr;
479 file = freerdp_client_rdp_file_new();
484 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
485 freerdp_client_populate_settings_from_rdp_file(file, settings))
490 freerdp_client_rdp_file_free(file);
494int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
497 rdpFile* file =
nullptr;
499 file = freerdp_client_rdp_file_new();
504 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
507 if (!freerdp_client_write_rdp_file(file, filename, unicode))
512 freerdp_client_rdp_file_free(file);
516int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
520 char* filename =
nullptr;
521 char* password =
nullptr;
522 rdpAssistanceFile* file =
nullptr;
524 if (!settings || !argv || (argc < 2))
529 for (
int x = 2; x < argc; x++)
531 const char* key = strstr(argv[x],
"assistance:");
535 char* sep = strchr(key,
':');
543 file = freerdp_assistance_file_new();
548 status = freerdp_assistance_parse_file(file, filename, password);
553 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
558 freerdp_assistance_file_free(file);
563static int client_cli_read_string(freerdp* instance,
const char* what,
const char* suggestion,
566 WINPR_ASSERT(instance);
568 WINPR_ASSERT(result);
572 (void)fflush(stdout);
574 char* line =
nullptr;
575 if (suggestion && strlen(suggestion) > 0)
577 line = _strdup(suggestion);
578 size = strlen(suggestion);
581 const SSIZE_T rc = freerdp_interruptible_get_line(instance->context, &line, &size, stdin);
584 char ebuffer[256] = WINPR_C_ARRAY_INIT;
585 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
586 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
596 line = StrSep(&line,
"\r");
597 line = StrSep(&line,
"\n");
619static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
620 char** password,
char** domain)
622 static const size_t password_size = 512;
623 const char* userAuth =
"Username: ";
624 const char* domainAuth =
"Domain: ";
625 const char* pwdAuth =
"Password: ";
626 BOOL pinOnly = FALSE;
627 BOOL queryAll = FALSE;
629 WINPR_ASSERT(instance);
630 WINPR_ASSERT(instance->context);
631 WINPR_ASSERT(instance->context->settings);
635 case AUTH_SMARTCARD_PIN:
636 pwdAuth =
"Smartcard-Pin: ";
640 pwdAuth =
"FIDO2 PIN: ";
653 userAuth =
"GatewayUsername: ";
654 domainAuth =
"GatewayDomain: ";
655 pwdAuth =
"GatewayPassword: ";
661 if (!username || !password || !domain)
666 const char* suggest = *username;
667 if (queryAll || !suggest)
669 const int rc = client_cli_read_string(instance, userAuth, suggest, username);
677 const char* suggest = *domain;
678 if (queryAll || !suggest)
680 const int rc = client_cli_read_string(instance, domainAuth, suggest, domain);
687 char* line = calloc(password_size,
sizeof(
char));
692 const BOOL fromStdin =
695 freerdp_passphrase_read(instance->context, pwdAuth, line, password_size, fromStdin);
699 if (password_size > 0)
717BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
718 rdp_auth_reason reason)
720 WINPR_ASSERT(instance);
721 WINPR_ASSERT(username);
722 WINPR_ASSERT(password);
723 WINPR_ASSERT(domain);
733 case AUTH_SMARTCARD_PIN:
735 if ((*username) && (*password))
746 return client_cli_authenticate_raw(instance, reason, username, password, domain);
749BOOL client_cli_choose_smartcard(WINPR_ATTR_UNUSED freerdp* instance,
SmartcardCertInfo** cert_list,
750 DWORD count, DWORD* choice, BOOL gateway)
752 unsigned long answer = 0;
755 printf(
"Multiple smartcards are available for use:\n");
756 for (DWORD i = 0; i < count; i++)
759 char* reader = ConvertWCharToUtf8Alloc(cert->reader,
nullptr);
760 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName,
nullptr);
763 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
764 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
765 cert->issuer, cert->upn);
768 free(container_name);
773 char input[10] = WINPR_C_ARRAY_INIT;
775 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
776 gateway ?
"gateway authentication" :
"logon", count - 1);
777 (void)fflush(stdout);
778 if (!fgets(input, 10, stdin))
780 WLog_ERR(TAG,
"could not read from stdin");
784 answer = strtoul(input, &p, 10);
785 if ((*p ==
'\n' && p != input) && answer < count)
787 *choice = (UINT32)answer;
793#if defined(WITH_FREERDP_DEPRECATED)
794BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
798 WLog_INFO(TAG,
"Authentication via smartcard");
802 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
805BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
807 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
812static DWORD client_cli_accept_certificate(freerdp* instance)
816 WINPR_ASSERT(instance);
817 WINPR_ASSERT(instance->context);
819 const rdpSettings* settings = instance->context->settings;
820 WINPR_ASSERT(settings);
828 printf(
"Do you trust the above certificate? (Y/T/N) ");
829 (void)fflush(stdout);
830 answer = freerdp_interruptible_getc(instance->context, stdin);
832 if ((answer == EOF) || feof(stdin))
834 printf(
"\nError: Could not read answer from stdin.\n");
842 answer = freerdp_interruptible_getc(instance->context, stdin);
850 answer = freerdp_interruptible_getc(instance->context, stdin);
858 answer = freerdp_interruptible_getc(instance->context, stdin);
883#if defined(WITH_FREERDP_DEPRECATED)
884DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
885 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
887 WINPR_UNUSED(common_name);
888 WINPR_UNUSED(host_mismatch);
890 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
891 printf(
"Certificate details:\n");
892 printf(
"\tSubject: %s\n", subject);
893 printf(
"\tIssuer: %s\n", issuer);
894 printf(
"\tThumbprint: %s\n", fingerprint);
895 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
896 "the CA certificate in your certificate store, or the certificate has expired.\n"
897 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
898 return client_cli_accept_certificate(instance);
902WINPR_ATTR_MALLOC(free, 1)
903static
char* client_cli_pem_cert(const
char* pem)
905 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
909 char* fp = freerdp_certificate_get_fingerprint(cert);
910 char* start = freerdp_certificate_get_validity(cert, TRUE);
911 char* end = freerdp_certificate_get_validity(cert, FALSE);
912 freerdp_certificate_free(cert);
916 winpr_asprintf(&str, &slen,
919 "\tThumbprint: %s\n",
942DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
943 const char* common_name,
const char* subject,
944 const char* issuer,
const char* fingerprint, DWORD flags)
946 const char* type =
"RDP-Server";
948 WINPR_ASSERT(instance);
949 WINPR_ASSERT(instance->context);
950 WINPR_ASSERT(instance->context->settings);
952 if (flags & VERIFY_CERT_FLAG_GATEWAY)
953 type =
"RDP-Gateway";
955 if (flags & VERIFY_CERT_FLAG_REDIRECT)
956 type =
"RDP-Redirect";
958 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
959 printf(
"\tCommon Name: %s\n", common_name);
960 printf(
"\tSubject: %s\n", subject);
961 printf(
"\tIssuer: %s\n", issuer);
965 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
967 char* str = client_cli_pem_cert(fingerprint);
972 printf(
"\tThumbprint: %s\n", fingerprint);
974 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
975 "the CA certificate in your certificate store, or the certificate has expired.\n"
976 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
977 return client_cli_accept_certificate(instance);
995#if defined(WITH_FREERDP_DEPRECATED)
996DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
997 const char* subject,
const char* issuer,
998 const char* fingerprint,
const char* old_subject,
999 const char* old_issuer,
const char* old_fingerprint)
1001 WINPR_UNUSED(common_name);
1003 printf(
"WARNING: This callback is deprecated, migrate to "
1004 "client_cli_verify_changed_certificate_ex\n");
1005 printf(
"!!! Certificate has changed !!!\n");
1007 printf(
"New Certificate details:\n");
1008 printf(
"\tSubject: %s\n", subject);
1009 printf(
"\tIssuer: %s\n", issuer);
1010 printf(
"\tThumbprint: %s\n", fingerprint);
1012 printf(
"Old Certificate details:\n");
1013 printf(
"\tSubject: %s\n", old_subject);
1014 printf(
"\tIssuer: %s\n", old_issuer);
1015 printf(
"\tThumbprint: %s\n", old_fingerprint);
1017 printf(
"The above X.509 certificate does not match the certificate used for previous "
1019 "This may indicate that the certificate has been tampered with.\n"
1020 "Please contact the administrator of the RDP server and clarify.\n");
1021 return client_cli_accept_certificate(instance);
1044DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
1045 const char* common_name,
const char* subject,
1046 const char* issuer,
const char* fingerprint,
1047 const char* old_subject,
const char* old_issuer,
1048 const char* old_fingerprint, DWORD flags)
1050 const char* type =
"RDP-Server";
1052 WINPR_ASSERT(instance);
1053 WINPR_ASSERT(instance->context);
1054 WINPR_ASSERT(instance->context->settings);
1056 if (flags & VERIFY_CERT_FLAG_GATEWAY)
1057 type =
"RDP-Gateway";
1059 if (flags & VERIFY_CERT_FLAG_REDIRECT)
1060 type =
"RDP-Redirect";
1062 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
1064 printf(
"New Certificate details:\n");
1065 printf(
"\tCommon Name: %s\n", common_name);
1066 printf(
"\tSubject: %s\n", subject);
1067 printf(
"\tIssuer: %s\n", issuer);
1071 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1073 char* str = client_cli_pem_cert(fingerprint);
1078 printf(
"\tThumbprint: %s\n", fingerprint);
1080 printf(
"Old Certificate details:\n");
1081 printf(
"\tSubject: %s\n", old_subject);
1082 printf(
"\tIssuer: %s\n", old_issuer);
1086 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
1088 char* str = client_cli_pem_cert(old_fingerprint);
1093 printf(
"\tThumbprint: %s\n", old_fingerprint);
1095 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
1097 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
1098 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
1099 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
1100 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
1103 printf(
"The above X.509 certificate does not match the certificate used for previous "
1105 "This may indicate that the certificate has been tampered with.\n"
1106 "Please contact the administrator of the RDP server and clarify.\n");
1107 return client_cli_accept_certificate(instance);
1110BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
1111 BOOL isConsentMandatory,
size_t length,
1112 const WCHAR* message)
1114 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
1116 WINPR_ASSERT(instance);
1117 WINPR_ASSERT(instance->context);
1118 WINPR_ASSERT(instance->context->settings);
1120 if (!isDisplayMandatory && !isConsentMandatory)
1123 printf(
"%s:\n", msgType);
1125 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR),
nullptr);
1128 printf(
"Failed to convert message!\n");
1131 printf(
"%s\n", msg);
1135 while (isConsentMandatory)
1137 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
1138 (void)fflush(stdout);
1139 const int answer = freerdp_interruptible_getc(instance->context, stdin);
1141 if ((answer == EOF) || feof(stdin))
1143 printf(
"\nError: Could not read answer from stdin.\n");
1147 const int confirm = freerdp_interruptible_getc(instance->context, stdin);
1153 return confirm != EOF;
1168#if defined(WITH_AAD)
1170static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1171 const char* req_cnf,
char** token)
1173 WINPR_ASSERT(instance);
1174 WINPR_ASSERT(instance->context);
1177 char* url =
nullptr;
1178 char* token_request =
nullptr;
1180 WINPR_ASSERT(scope);
1181 WINPR_ASSERT(req_cnf);
1182 WINPR_ASSERT(token);
1187 WINPR_ASSERT(requireRdpClientContext(instance->context));
1188 if (!requireRdpClientContext(instance->context))
1191 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1192 FREERDP_CLIENT_AAD_AUTH_REQUEST, scope);
1194 printf(
"Browse to: %s\n", request);
1195 winpr_zfree(request);
1196 printf(
"Paste redirect URL here: \n");
1198 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1203 freerdp_client_extract_aad_code((rdpClientContext*)instance->context, url, size);
1207 freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1208 FREERDP_CLIENT_AAD_TOKEN_REQUEST, scope, code, req_cnf);
1214 rc = client_common_get_access_token(instance, token_request, token);
1217 winpr_zfree(token_request);
1219 return rc && (*token !=
nullptr);
1223static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1225 WINPR_ASSERT(instance);
1226 WINPR_ASSERT(instance->context);
1228 WINPR_ASSERT(requireRdpClientContext(instance->context));
1229 if (!requireRdpClientContext(instance->context))
1233 char* url =
nullptr;
1234 char* token_request =
nullptr;
1236 WINPR_ASSERT(token);
1242 char* request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1243 FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST);
1246 printf(
"Browse to: %s\n", request);
1247 winpr_zfree(request);
1248 printf(
"Paste redirect URL here: \n");
1250 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1255 freerdp_client_extract_aad_code((rdpClientContext*)instance->context, url, size);
1258 token_request = freerdp_client_get_aad_url((rdpClientContext*)instance->context,
1259 FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST, code);
1266 rc = client_common_get_access_token(instance, token_request, token);
1269 free(token_request);
1271 return rc && (*token !=
nullptr);
1276static BOOL client_cli_get_access_token_va(freerdp* instance,
1277 WINPR_ATTR_UNUSED AccessTokenType tokenType,
1278 char** token, WINPR_ATTR_UNUSED
size_t count, va_list ap)
1280 WINPR_ASSERT(instance);
1281 WINPR_ASSERT(token);
1284#if !defined(WITH_AAD)
1285 WLog_ERR(TAG,
"Build does not support AAD authentication");
1289 WINPR_ASSERT(instance->context);
1298 case ACCESS_TOKEN_TYPE_AAD:
1303 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1312 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1315 const char* scope = va_arg(ap,
const char*);
1316 const char* req_cnf = va_arg(ap,
const char*);
1317 rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1321 case ACCESS_TOKEN_TYPE_AVD:
1324 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1327 rc = client_cli_get_avd_access_token(instance, token);
1330 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%u], aborting", tokenType);
1341BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1344 va_list ap = WINPR_C_ARRAY_INIT;
1345 va_start(ap, count);
1346 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
1351BOOL client_common_get_access_token(WINPR_ATTR_UNUSED freerdp* instance,
1352 WINPR_ATTR_UNUSED
const char* request,
1353 WINPR_ATTR_UNUSED
char** token)
1355 WINPR_ASSERT(request);
1356 WINPR_ASSERT(token);
1362 BYTE* response =
nullptr;
1363 size_t response_length = 0;
1365 wLog* log = WLog_Get(TAG);
1367 const char* token_ep =
1368 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1369 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1371 WLog_ERR(TAG,
"access token request failed");
1375 if (resp_code != HTTP_STATUS_OK)
1377 char buffer[64] = WINPR_C_ARRAY_INIT;
1379 WLog_Print(log, WLOG_ERROR,
1380 "Server unwilling to provide access token; returned status code %s",
1381 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1382 if (response_length > 0)
1383 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1387 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1395 WLog_ERR(TAG,
"Build does not support AAD authentication");
1400SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1403 WINPR_UNUSED(instance);
1404 WINPR_ASSERT(instance->context);
1405 WINPR_UNUSED(userarg);
1406 WINPR_ASSERT(instance);
1409 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1411 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1417 if (strcmp(what,
"arm-transport") == 0)
1418 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1421 const rdpSettings* settings = instance->context->settings;
1425 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1434 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1435 "tech support for help if this keeps happening.",
1440 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1441 what, current + 1, max, delay);
1442 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1445BOOL client_auto_reconnect(freerdp* instance)
1447 return client_auto_reconnect_ex(instance,
nullptr);
1451static BOOL client_auto_reconnect_do(freerdp* instance, BOOL retry, UINT32 numRetries,
1454 WINPR_ASSERT(instance);
1460 if ((maxRetries > 0) && (numRetries >= maxRetries))
1462 WLog_DBG(TAG,
"AutoReconnect retries exceeded.");
1467 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1469 const SSIZE_T delay =
1470 IFCALLRESULT(5000, instance->RetryDialog, instance,
"connection", numRetries,
nullptr);
1475 if (freerdp_reconnect(instance))
1478 switch (freerdp_get_last_error(instance->context))
1480 case FREERDP_ERROR_CONNECT_CANCELLED:
1481 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1487 for (SSIZE_T x = 0; x < delay / 10; x++)
1491 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1496static DWORD WINAPI handle_window_events(
void* parg)
1498 handle_window_events_t* arg = parg;
1501 while (arg->running)
1503 WINPR_ASSERT(arg->window_events);
1504 if (!arg->window_events(arg->instance))
1506 WLog_ERR(TAG,
"window_events failed!");
1513BOOL client_auto_reconnect_ex(freerdp* instance, window_events_fkt_t window_events)
1517 UINT32 numRetries = 0;
1518 rdpSettings* settings =
nullptr;
1523 WINPR_ASSERT(instance->context);
1525 settings = instance->context->settings;
1526 WINPR_ASSERT(settings);
1528 const UINT32 maxRetries =
1532 error = freerdp_error_info(instance);
1535 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1537 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1538 freerdp_get_error_info_string(error));
1540 case ERRINFO_SUCCESS:
1542 WLog_INFO(TAG,
"Network disconnect!");
1545 WLog_DBG(TAG,
"Other error: %s", freerdp_get_error_info_string(error));
1552 WLog_DBG(TAG,
"AutoReconnect not enabled, quitting.");
1556 const UINT err = freerdp_get_last_error(instance->context);
1559 case FREERDP_ERROR_CONNECT_LOGON_FAILURE:
1560 case FREERDP_ERROR_CONNECT_CLIENT_REVOKED:
1561 case FREERDP_ERROR_CONNECT_WRONG_PASSWORD:
1562 case FREERDP_ERROR_CONNECT_ACCESS_DENIED:
1563 case FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION:
1564 case FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT:
1565 case FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED:
1566 case FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS:
1567 WLog_WARN(TAG,
"Connection aborted: credentials do not work [%s]",
1568 freerdp_get_last_error_name(err));
1570 case FREERDP_ERROR_CONNECT_CANCELLED:
1571 WLog_WARN(TAG,
"Connection aborted by user");
1577 handle_window_events_t arg = { .instance = instance,
1578 .window_events = window_events,
1580 HANDLE thread =
nullptr;
1582 thread = CreateThread(
nullptr, 0, handle_window_events, &arg, 0,
nullptr);
1583 const BOOL rc = client_auto_reconnect_do(instance, retry, numRetries, maxRetries);
1586 arg.running = FALSE;
1587 WaitForSingleObject(thread, INFINITE);
1588 CloseHandle(thread);
1593int freerdp_client_common_stop(rdpContext* context)
1595 freerdp_abort_connect_context(context);
1597 if (requireRdpClientContext(context))
1600 rdpClientContext* cctx = (rdpClientContext*)context;
1604 (void)WaitForSingleObject(cctx->thread, INFINITE);
1605 (void)CloseHandle(cctx->thread);
1606 cctx->thread =
nullptr;
1608#if defined(WITH_AAD)
1609 aad_auth_helper_stop(cctx->aadHelper);
1610 cctx->aadHelper =
nullptr;
1617#if defined(CHANNEL_ENCOMSP_CLIENT)
1618BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1625 rdpClientContext* cctx = (rdpClientContext*)encomsp->custom;
1627 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1628 if (!cctx || !requireRdpClientContext(&cctx->context))
1631 state = cctx->controlToggle;
1632 cctx->controlToggle = !cctx->controlToggle;
1633 return freerdp_client_encomsp_set_control(encomsp, state);
1636BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1643 pdu.ParticipantId = encomsp->participantId;
1644 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1647 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1649 const UINT rc = encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1650 return rc == CHANNEL_RC_OK;
1654client_encomsp_participant_created(EncomspClientContext* context,
1659 if (!context || !context->custom || !participantCreated)
1660 return ERROR_INVALID_PARAMETER;
1662 rdpClientContext* cctx = (rdpClientContext*)context->custom;
1664 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1665 if (!cctx || !requireRdpClientContext(&cctx->context))
1666 return ERROR_INVALID_PARAMETER;
1668 rdpSettings* settings = cctx->context.settings;
1669 WINPR_ASSERT(settings);
1671 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1672 context->participantId = participantCreated->ParticipantId;
1675 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1676 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1678 if (!freerdp_client_encomsp_set_control(context, TRUE))
1679 return ERROR_INTERNAL_ERROR;
1685 return ERROR_INTERNAL_ERROR;
1688 return CHANNEL_RC_OK;
1691static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1694 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1695 if (!cctx || !requireRdpClientContext(&cctx->context))
1698 cctx->encomsp = encomsp;
1699 encomsp->custom = (
void*)cctx;
1700 encomsp->ParticipantCreated = client_encomsp_participant_created;
1703static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1707 encomsp->custom =
nullptr;
1708 encomsp->ParticipantCreated =
nullptr;
1713 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1714 if (requireRdpClientContext(&cctx->context))
1715 cctx->encomsp =
nullptr;
1720void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1721 const ChannelConnectedEventArgs* e)
1723 rdpClientContext* cctx = (rdpClientContext*)context;
1731#if defined(CHANNEL_AINPUT_CLIENT)
1732 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1735 WINPR_ASSERT(requireRdpClientContext(context));
1736 if (!requireRdpClientContext(context))
1738 cctx->ainput = (AInputClientContext*)e->pInterface;
1741#if defined(CHANNEL_RDPEI_CLIENT)
1742 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1744 WINPR_ASSERT(requireRdpClientContext(context));
1745 if (!requireRdpClientContext(context))
1747 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1750#if defined(CHANNEL_RDPGFX_CLIENT)
1751 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1753 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1756#if defined(CHANNEL_GEOMETRY_CLIENT)
1757 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1759 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1762#if defined(CHANNEL_VIDEO_CLIENT)
1763 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1765 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1767 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1769 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1772#if defined(CHANNEL_ENCOMSP_CLIENT)
1773 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1775 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1780void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1781 const ChannelDisconnectedEventArgs* e)
1783 rdpClientContext* cctx = (rdpClientContext*)context;
1791#if defined(CHANNEL_AINPUT_CLIENT)
1792 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1794 WINPR_ASSERT(requireRdpClientContext(context));
1795 if (!requireRdpClientContext(context))
1797 cctx->ainput =
nullptr;
1800#if defined(CHANNEL_RDPEI_CLIENT)
1801 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1803 WINPR_ASSERT(requireRdpClientContext(context));
1804 if (!requireRdpClientContext(context))
1806 cctx->rdpei =
nullptr;
1809#if defined(CHANNEL_RDPGFX_CLIENT)
1810 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1812 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1815#if defined(CHANNEL_GEOMETRY_CLIENT)
1816 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1818 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1821#if defined(CHANNEL_VIDEO_CLIENT)
1822 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1824 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1826 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1828 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1831#if defined(CHANNEL_ENCOMSP_CLIENT)
1832 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1834 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1839BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1841 BOOL handled = FALSE;
1844 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1845 if (!cctx || !requireRdpClientContext(&cctx->context))
1848 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1849 if (state != CONNECTION_STATE_ACTIVE)
1852#if defined(CHANNEL_AINPUT_CLIENT)
1859 INT32 value = mflags & 0xFF;
1861 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1862 value = -1 * (0x100 - value);
1868 if (mflags & PTR_FLAGS_WHEEL)
1870 flags |= AINPUT_FLAGS_WHEEL;
1874 if (mflags & PTR_FLAGS_HWHEEL)
1876 flags |= AINPUT_FLAGS_WHEEL;
1880 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1881 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1882 if (rc == CHANNEL_RC_OK)
1888 return freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1893#if defined(CHANNEL_AINPUT_CLIENT)
1895static inline BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1898 WINPR_ASSERT(cctx->ainput);
1899 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1900 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1902 if (!cctx || !requireRdpClientContext(&cctx->context))
1903 return ERROR_INVALID_PARAMETER;
1905 const UINT rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1907 return rc == CHANNEL_RC_OK;
1912static bool button_pressed(
const rdpClientContext* cctx)
1915 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1916 if (!cctx || !requireRdpClientContext(&cctx->context))
1919 for (
size_t x = 0; x < ARRAYSIZE(cctx->pressed_buttons); x++)
1921 const BOOL cur = cctx->pressed_buttons[x];
1928BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1931 BOOL handled = FALSE;
1934 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
1935 if (!cctx || !requireRdpClientContext(&cctx->context))
1938 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
1939 if (state != CONNECTION_STATE_ACTIVE)
1942 if (mflags & PTR_FLAGS_BUTTON1)
1943 cctx->pressed_buttons[0] = mflags & PTR_FLAGS_DOWN;
1944 if (mflags & PTR_FLAGS_BUTTON2)
1945 cctx->pressed_buttons[1] = mflags & PTR_FLAGS_DOWN;
1946 if (mflags & PTR_FLAGS_BUTTON3)
1947 cctx->pressed_buttons[2] = mflags & PTR_FLAGS_DOWN;
1949 if (((mflags & PTR_FLAGS_MOVE) != 0) &&
1952 if (!button_pressed(cctx))
1956 const BOOL haveRelative =
1958 if (relative && haveRelative)
1960 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1961 WINPR_ASSERTING_INT_CAST(int16_t, x),
1962 WINPR_ASSERTING_INT_CAST(int16_t, y));
1965#if defined(CHANNEL_AINPUT_CLIENT)
1970 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1971 flags |= AINPUT_FLAGS_HAVE_REL;
1974 flags |= AINPUT_FLAGS_REL;
1976 if (mflags & PTR_FLAGS_DOWN)
1977 flags |= AINPUT_FLAGS_DOWN;
1978 if (mflags & PTR_FLAGS_BUTTON1)
1979 flags |= AINPUT_FLAGS_BUTTON1;
1980 if (mflags & PTR_FLAGS_BUTTON2)
1981 flags |= AINPUT_FLAGS_BUTTON2;
1982 if (mflags & PTR_FLAGS_BUTTON3)
1983 flags |= AINPUT_FLAGS_BUTTON3;
1984 if (mflags & PTR_FLAGS_MOVE)
1985 flags |= AINPUT_FLAGS_MOVE;
1986 handled = ainput_send_diff_event(cctx, flags, x, y);
1996 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2003 return freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2004 (UINT16)cctx->lastY);
2009BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
2012 BOOL handled = FALSE;
2014 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2016 if (!cctx || !requireRdpClientContext(&cctx->context))
2019 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2020 if (state != CONNECTION_STATE_ACTIVE)
2023 if (mflags & PTR_XFLAGS_BUTTON1)
2024 cctx->pressed_buttons[3] = mflags & PTR_XFLAGS_DOWN;
2025 if (mflags & PTR_XFLAGS_BUTTON2)
2026 cctx->pressed_buttons[4] = mflags & PTR_XFLAGS_DOWN;
2028 const BOOL haveRelative =
2030 if (relative && haveRelative)
2032 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
2033 WINPR_ASSERTING_INT_CAST(int16_t, x),
2034 WINPR_ASSERTING_INT_CAST(int16_t, y));
2037#if defined(CHANNEL_AINPUT_CLIENT)
2043 flags |= AINPUT_FLAGS_REL;
2044 if (mflags & PTR_XFLAGS_DOWN)
2045 flags |= AINPUT_FLAGS_DOWN;
2046 if (mflags & PTR_XFLAGS_BUTTON1)
2047 flags |= AINPUT_XFLAGS_BUTTON1;
2048 if (mflags & PTR_XFLAGS_BUTTON2)
2049 flags |= AINPUT_XFLAGS_BUTTON2;
2051 handled = ainput_send_diff_event(cctx, flags, x, y);
2061 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
2068 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
2069 (UINT16)cctx->lastY);
2076static BOOL freerdp_handle_touch_to_mouse(rdpClientContext* cctx, BOOL down,
2080 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2081 if (!cctx || !requireRdpClientContext(&cctx->context))
2084 const UINT16 flags = PTR_FLAGS_MOVE | (down ? PTR_FLAGS_DOWN : 0);
2085 const UINT16 xflags = down ? PTR_XFLAGS_DOWN : 0;
2086 WINPR_ASSERT(contact);
2087 WINPR_ASSERT(contact->x <= UINT16_MAX);
2088 WINPR_ASSERT(contact->y <= UINT16_MAX);
2090 switch (contact->count)
2093 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON1,
2094 contact->x, contact->y);
2096 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON2,
2097 contact->x, contact->y);
2099 return freerdp_client_send_button_event(cctx, FALSE, flags | PTR_FLAGS_BUTTON3,
2100 contact->x, contact->y);
2102 return freerdp_client_send_extended_button_event(
2103 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2105 return freerdp_client_send_extended_button_event(
2106 cctx, FALSE, xflags | PTR_XFLAGS_BUTTON1, contact->x, contact->y);
2114static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2117 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2118 WINPR_ASSERT(contact);
2120 if (!cctx || !requireRdpClientContext(&cctx->context))
2123#if defined(CHANNEL_RDPEI_CLIENT)
2124 RdpeiClientContext* rdpei = cctx->rdpei;
2127 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2131 if (rdpei->TouchRawEvent)
2133 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
2134 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2135 ? CONTACT_DATA_PRESSURE_PRESENT
2139 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2140 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2141 RDPINPUT_CONTACT_FLAG_INCONTACT,
2142 contactFlags, contact->pressure);
2143 if (rc1 != CHANNEL_RC_OK)
2146 const UINT rc2 = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y,
2147 &contactId, flags, contactFlags, contact->pressure);
2148 if (rc2 != CHANNEL_RC_OK)
2153 WINPR_ASSERT(rdpei->TouchEnd);
2154 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2155 if (rc != CHANNEL_RC_OK)
2160 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2161 "-DCHANNEL_RDPEI_CLIENT=ON");
2162 return freerdp_handle_touch_to_mouse(cctx, FALSE, contact);
2167static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2170 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2171 WINPR_ASSERT(contact);
2173 if (!cctx || !requireRdpClientContext(&cctx->context))
2176#if defined(CHANNEL_RDPEI_CLIENT)
2177 RdpeiClientContext* rdpei = cctx->rdpei;
2181 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2185 if (rdpei->TouchRawEvent)
2187 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
2188 RDPINPUT_CONTACT_FLAG_INCONTACT;
2189 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2190 ? CONTACT_DATA_PRESSURE_PRESENT
2192 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2193 flags, contactFlags, contact->pressure);
2194 if (rc != CHANNEL_RC_OK)
2199 WINPR_ASSERT(rdpei->TouchBegin);
2200 const UINT rc = rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
2201 if (rc != CHANNEL_RC_OK)
2207 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2208 "-DCHANNEL_RDPEI_CLIENT=ON");
2209 return freerdp_handle_touch_to_mouse(cctx, TRUE, contact);
2214static BOOL freerdp_handle_touch_motion_to_mouse(rdpClientContext* cctx,
2218 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2220 if (!cctx || !requireRdpClientContext(&cctx->context))
2223 const UINT16 flags = PTR_FLAGS_MOVE;
2225 WINPR_ASSERT(contact);
2226 WINPR_ASSERT(contact->x <= UINT16_MAX);
2227 WINPR_ASSERT(contact->y <= UINT16_MAX);
2228 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
2232static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2235 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2236 WINPR_ASSERT(contact);
2238 if (!cctx || !requireRdpClientContext(&cctx->context))
2241#if defined(CHANNEL_RDPEI_CLIENT)
2242 RdpeiClientContext* rdpei = cctx->rdpei;
2245 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2249 if (rdpei->TouchRawEvent)
2251 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
2252 RDPINPUT_CONTACT_FLAG_INCONTACT;
2253 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2254 ? CONTACT_DATA_PRESSURE_PRESENT
2256 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2257 flags, contactFlags, contact->pressure);
2258 if (rc != CHANNEL_RC_OK)
2263 WINPR_ASSERT(rdpei->TouchUpdate);
2264 const UINT rc = rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
2265 if (rc != CHANNEL_RC_OK)
2271 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2272 "-DCHANNEL_RDPEI_CLIENT=ON");
2273 return freerdp_handle_touch_motion_to_mouse(cctx, contact);
2278static BOOL freerdp_handle_touch_cancel(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
2281 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2282 WINPR_ASSERT(contact);
2284 if (!cctx || !requireRdpClientContext(&cctx->context))
2287#if defined(CHANNEL_RDPEI_CLIENT)
2288 RdpeiClientContext* rdpei = cctx->rdpei;
2291 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2295 if (rdpei->TouchRawEvent)
2297 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_CANCELED;
2298 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
2299 ? CONTACT_DATA_PRESSURE_PRESENT
2301 const UINT rc = rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
2302 flags, contactFlags, contact->pressure);
2303 if (rc != CHANNEL_RC_OK)
2308 WINPR_ASSERT(rdpei->TouchUpdate);
2309 const UINT rc = rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
2310 if (rc != CHANNEL_RC_OK)
2316 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
2317 "-DCHANNEL_RDPEI_CLIENT=ON");
2318 return freerdp_handle_touch_to_mouse(cctx,
false, contact);
2323static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
2324 UINT32 pressure, INT32 x, INT32 y,
2328 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2329 WINPR_ASSERT(pcontact);
2331 if (!cctx || !requireRdpClientContext(&cctx->context))
2334 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
2338 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
2339 if (newcontact || (contact->id == touchId))
2341 contact->id = touchId;
2342 contact->flags = flags;
2343 contact->pressure = pressure;
2347 *pcontact = *contact;
2349 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
2362BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
2363 UINT32 pressure, INT32 x, INT32 y)
2366 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2368 if (!cctx || !requireRdpClientContext(&cctx->context))
2372 FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION | FREERDP_TOUCH_CANCEL;
2375 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2376 if (state != CONNECTION_STATE_ACTIVE)
2381 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
2384 switch (flags & mask)
2386 case FREERDP_TOUCH_DOWN:
2387 return freerdp_handle_touch_down(cctx, &contact);
2388 case FREERDP_TOUCH_UP:
2389 return freerdp_handle_touch_up(cctx, &contact);
2390 case FREERDP_TOUCH_MOTION:
2391 return freerdp_handle_touch_motion(cctx, &contact);
2392 case FREERDP_TOUCH_CANCEL:
2393 return freerdp_handle_touch_cancel(cctx, &contact);
2395 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %" PRIu32
", ignoring", flags);
2400BOOL freerdp_client_load_channels(freerdp* instance)
2402 WINPR_ASSERT(instance);
2403 WINPR_ASSERT(instance->context);
2405 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
2407 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
2413int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
2415 const char* str_data = freerdp_get_logon_error_info_data(data);
2416 const char* str_type = freerdp_get_logon_error_info_type(type);
2418 if (!instance || !instance->context)
2421 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
2426static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
2430 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2432 if (!cctx || !requireRdpClientContext(&cctx->context))
2435 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2438 if (deviceid == pen->deviceid)
2449static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2452 static const INT32 null_deviceid = 0;
2455 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2456 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2458 if (!cctx || !requireRdpClientContext(&cctx->context))
2461 if (freerdp_client_is_pen(cctx, deviceid))
2463 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2474 pen->deviceid = deviceid;
2475 pen->max_pressure = pressure;
2478 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2482 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2486BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2489 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2491 if (!cctx || !requireRdpClientContext(&cctx->context))
2494 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2495 if (state != CONNECTION_STATE_ACTIVE)
2498#if defined(CHANNEL_RDPEI_CLIENT)
2499 if ((flags & FREERDP_PEN_REGISTER) != 0)
2501 va_list args = WINPR_C_ARRAY_INIT;
2503 va_start(args, deviceid);
2504 double pressure = va_arg(args,
double);
2506 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2512 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2516 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2518 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2520 RdpeiClientContext* rdpei = cctx->rdpei;
2521 WINPR_ASSERT(rdpei);
2523 UINT32 normalizedpressure = 1024;
2526 UINT16 rotation = 0;
2529 va_list args = WINPR_C_ARRAY_INIT;
2530 va_start(args, deviceid);
2532 x = va_arg(args, INT32);
2533 y = va_arg(args, INT32);
2534 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2536 const double pressure = va_arg(args,
double);
2537 const double np = (pressure * 1024.0) / pen->max_pressure;
2538 normalizedpressure = (UINT32)lround(np);
2539 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2540 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2542 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2544 const unsigned arg = va_arg(args,
unsigned);
2545 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2546 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2548 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2550 const int arg = va_arg(args,
int);
2551 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2552 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2554 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2556 const int arg = va_arg(args,
int);
2557 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2558 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2562 if ((flags & FREERDP_PEN_PRESS) != 0)
2566 flags = FREERDP_PEN_MOTION |
2567 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2568 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2569 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2571 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2573 if (!pen->pressed ||
2574 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2575 flags = FREERDP_PEN_MOTION |
2576 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2578 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2581 flags |= pen->flags;
2582 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2583 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2584 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2585 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2589 if ((flags & FREERDP_PEN_PRESS) != 0)
2591 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2592 pen->hovering = FALSE;
2593 pen->pressed = TRUE;
2595 WINPR_ASSERT(rdpei->PenBegin);
2596 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2597 normalizedpressure, rotation, tiltX, tiltY);
2598 return rc == CHANNEL_RC_OK;
2600 else if ((flags & FREERDP_PEN_MOTION) != 0)
2602 UINT rc = ERROR_INTERNAL_ERROR;
2605 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2608 WINPR_ASSERT(rdpei->PenUpdate);
2609 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2610 rotation, tiltX, tiltY);
2612 else if (pen->hovering)
2614 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2616 WINPR_ASSERT(rdpei->PenHoverUpdate);
2617 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2618 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2622 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2623 pen->hovering = TRUE;
2625 WINPR_ASSERT(rdpei->PenHoverBegin);
2626 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2627 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2629 return rc == CHANNEL_RC_OK;
2631 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2633 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2634 pen->pressed = FALSE;
2635 pen->hovering = TRUE;
2637 WINPR_ASSERT(rdpei->PenUpdate);
2638 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2639 normalizedpressure, rotation, tiltX, tiltY);
2640 if (rc != CHANNEL_RC_OK)
2642 WINPR_ASSERT(rdpei->PenEnd);
2643 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2644 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2645 return re == CHANNEL_RC_OK;
2648 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2650 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2651 "-DCHANNEL_RDPEI_CLIENT=ON");
2657BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2660 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2662 if (!cctx || !requireRdpClientContext(&cctx->context))
2665 const CONNECTION_STATE state = freerdp_get_state(&cctx->context);
2666 if (state != CONNECTION_STATE_ACTIVE)
2669#if defined(CHANNEL_RDPEI_CLIENT)
2670 RdpeiClientContext* rdpei = cctx->rdpei;
2675 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2680 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2681 pen->hovering = FALSE;
2683 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2684 if (rc != CHANNEL_RC_OK)
2690 WLog_WARN(TAG,
"Pen event detected but RDPEI support not compiled in. Recompile with "
2691 "-DCHANNEL_RDPEI_CLIENT=ON");
2696BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2699 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2701 if (!cctx || !requireRdpClientContext(&cctx->context))
2707 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2710 if (pen->deviceid == deviceid)
2717BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* cctx)
2720 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2722 if (!cctx || !requireRdpClientContext(&cctx->context))
2725 const rdpSettings* settings = cctx->context.settings;
2728 BOOL ainput = FALSE;
2729#if defined(CHANNEL_AINPUT_CLIENT)
2730 ainput = cctx->ainput !=
nullptr;
2733 return useRelative && (haveRelative || ainput);
2736#if defined(WITH_AAD)
2737WINPR_ATTR_MALLOC(free, 1)
2738static
char* get_redirect_uri(const rdpSettings* settings)
2740 char* redirect_uri =
nullptr;
2744 const char* redirect_fmt =
2747 const char* tenantid =
"common";
2751 if (tenantid && redirect_fmt)
2756 size_t redirect_len = 0;
2757 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, url, tenantid);
2763 const char* redirect_fmt =
2766 size_t redirect_len = 0;
2767 winpr_asprintf(&redirect_uri, &redirect_len, redirect_fmt, client_id);
2769 return redirect_uri;
2772WINPR_ATTR_MALLOC(free, 1)
2773static
char* avd_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2776 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2780 if (!cctx || !requireRdpClientContext(&cctx->context))
2783 const rdpSettings* settings = cctx->context.settings;
2785 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2786 AAD_WELLKNOWN_authorization_endpoint);
2789 if (!client_id || !ep || !scope)
2792 char* redirect_uri = get_redirect_uri(settings);
2796 char* url =
nullptr;
2797 winpr_asprintf(&url, plen,
"%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2798 client_id, scope, redirect_uri);
2803WINPR_ATTR_MALLOC(free, 1)
2804static
char* avd_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2807 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2811 if (!cctx || !requireRdpClientContext(&cctx->context))
2814 const rdpSettings* settings = cctx->context.settings;
2816 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2817 AAD_WELLKNOWN_authorization_endpoint);
2820 if (!client_id || !ep || !scope)
2823 char* redirect_uri = get_redirect_uri(settings);
2827 char* url =
nullptr;
2829 const char* code = va_arg(ap,
const char*);
2830 winpr_asprintf(&url, plen,
2831 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s",
2832 code, client_id, scope, redirect_uri);
2837WINPR_ATTR_MALLOC(free, 1)
2838static
char* aad_auth_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2841 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2845 if (!cctx || !requireRdpClientContext(&cctx->context))
2848 const rdpSettings* settings = cctx->context.settings;
2849 char* url =
nullptr;
2850 char* redirect_uri = get_redirect_uri(settings);
2853 if (!client_id || !redirect_uri)
2857 const char* scope = va_arg(ap,
const char*);
2862 const char* ep = freerdp_utils_aad_get_wellknown_string(
2863 &cctx->context, AAD_WELLKNOWN_authorization_endpoint);
2864 winpr_asprintf(&url, plen,
2865 "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s", ep,
2866 client_id, scope, redirect_uri);
2875WINPR_ATTR_MALLOC(free, 1)
2876static
char* aad_token_request(rdpClientContext* cctx, WINPR_ATTR_UNUSED va_list ap,
size_t* plen)
2879 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2883 if (!cctx || !requireRdpClientContext(&cctx->context))
2886 const rdpSettings* settings = cctx->context.settings;
2888 const char* ep = freerdp_utils_aad_get_wellknown_string(&cctx->context,
2889 AAD_WELLKNOWN_authorization_endpoint);
2890 const char* scope = va_arg(ap,
const char*);
2891 const char* code = va_arg(ap,
const char*);
2892 const char* req_cnf = va_arg(ap,
const char*);
2894 if (!client_id || !ep || !scope || !code || !req_cnf)
2897 char* redirect_uri = get_redirect_uri(settings);
2901 char* url =
nullptr;
2905 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s&req_cnf=%s",
2906 code, client_id, scope, redirect_uri, req_cnf);
2912char* freerdp_client_get_aad_url(rdpClientContext* cctx, freerdp_client_aad_type type, ...)
2915 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2917 if (!cctx || !requireRdpClientContext(&cctx->context))
2920 char* str =
nullptr;
2923 va_list ap = WINPR_C_ARRAY_INIT;
2927#if defined(WITH_AAD)
2928 case FREERDP_CLIENT_AAD_AUTH_REQUEST:
2929 if (freerdp_oauth2_reset(cctx->oauth2))
2930 str = aad_auth_request(cctx, ap, &len);
2932 case FREERDP_CLIENT_AAD_TOKEN_REQUEST:
2933 str = aad_token_request(cctx, ap, &len);
2935 case FREERDP_CLIENT_AAD_AVD_AUTH_REQUEST:
2936 if (freerdp_oauth2_reset(cctx->oauth2))
2937 str = avd_auth_request(cctx, ap, &len);
2939 case FREERDP_CLIENT_AAD_AVD_TOKEN_REQUEST:
2940 str = avd_token_request(cctx, ap, &len);
2948 char* safestr = freerdp_oauth2_append_state(cctx->oauth2, str, len,
nullptr);
2953BOOL client_common_save_session_info(WINPR_ATTR_UNUSED rdpContext* context, UINT32 type,
2956 char buffer[128] = WINPR_C_ARRAY_INIT;
2957 WLog_INFO(TAG,
"%s [%s]", freerdp_session_logon_type_str(type),
2958 freerdp_session_logon_type_data_str(type, data, buffer,
sizeof(buffer)));
2962char* freerdp_client_extract_aad_code(rdpClientContext* cctx,
const char* data,
size_t length)
2965 WINPR_ASSERT(requireRdpClientContext(&cctx->context));
2967 if (!cctx || !requireRdpClientContext(&cctx->context))
2969 return freerdp_oauth2_extract_code(cctx->oauth2, data, length);
2973static BOOL client_helper_get_access_token_va(freerdp* instance,
2974 WINPR_ATTR_UNUSED AccessTokenType tokenType,
2975 WINPR_ATTR_UNUSED
char** token,
2976 WINPR_ATTR_UNUSED
size_t count, va_list ap)
2978 WINPR_ASSERT(instance);
2979 WINPR_ASSERT(token);
2983 WINPR_ASSERT(requireRdpClientContext(instance->context));
2985#if defined(WITH_AAD)
2986 rdpClientContext* cctx = (rdpClientContext*)instance->context;
2989 aad_auth_helper_stop(cctx->aadHelper);
2990 cctx->aadHelper = aad_auth_helper_start(cctx);
2991 if (!cctx->aadHelper)
2995 aad_auth_helper_get_access_token_v(cctx->aadHelper, tokenType, token, count, ap);
2996 aad_auth_helper_stop(cctx->aadHelper);
2997 cctx->aadHelper =
nullptr;
3000 WLog_ERR(TAG,
"Build does not support AAD authentication");
3005BOOL client_failsafe_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
3009 va_list ap = WINPR_C_ARRAY_INIT;
3010 va_start(ap, count);
3011 const BOOL rc = client_helper_get_access_token_va(instance, tokenType, token, count, ap);
3017 va_list ap = WINPR_C_ARRAY_INIT;
3018 va_start(ap, count);
3019 const BOOL rc = client_cli_get_access_token_va(instance, tokenType, token, count, ap);
3025BOOL client_helper_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
3028 va_list ap = WINPR_C_ARRAY_INIT;
3029 va_start(ap, count);
3030 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.