FreeRDP
Loading...
Searching...
No Matches
freerdp.c
1
22#include <freerdp/config.h>
23
24#include "settings.h"
25
26#include <string.h>
27#include <stdarg.h>
28#include <time.h>
29
30#include "rdp.h"
31#include "input.h"
32#include "update.h"
33#include "surface.h"
34#include "transport.h"
35#include "connection.h"
36#include "message.h"
37#include <freerdp/buildflags.h>
38#include "gateway/rpc_fault.h"
39#include "../cache/cache.h"
40
41#include <winpr/assert.h>
42
43#include <winpr/crt.h>
44#include <winpr/string.h>
45#include <winpr/stream.h>
46#include <winpr/wtsapi.h>
47#include <winpr/ssl.h>
48#include <winpr/debug.h>
49#include <winpr/i18n.h>
50
51#include <freerdp/freerdp.h>
52#include <freerdp/streamdump.h>
53#include <freerdp/error.h>
54#include <freerdp/event.h>
55#include <freerdp/locale/keyboard.h>
56#include <freerdp/locale/locale.h>
57#include <freerdp/channels/channels.h>
58#include <freerdp/version.h>
59#include <freerdp/log.h>
60#include <freerdp/utils/signal.h>
61
62#include "../cache/pointer.h"
63#include "utils.h"
64
65#define TAG FREERDP_TAG("core")
66
67BOOL freerdp_enable_translation(const char* locale, const char* searchPath)
68{
69 return winpr_i18n_enable_translation(locale) && winpr_i18n_bind_domain("freerdp", searchPath);
70}
71
72static void sig_abort_connect(int signum, const char* signame, void* ctx)
73{
74 rdpContext* context = (rdpContext*)ctx;
75
76 WLog_INFO(TAG, "Signal %s [%d], terminating session %p", signame, signum,
77 WINPR_CXX_COMPAT_CAST(const void*, context));
78 if (context)
79 freerdp_abort_connect_context(context);
80}
81
93static int freerdp_connect_begin(freerdp* instance)
94{
95 BOOL rc = 0;
96 rdpRdp* rdp = nullptr;
97 BOOL status = TRUE;
98 rdpSettings* settings = nullptr;
99
100 if (!instance)
101 return -1;
102
103 WINPR_ASSERT(instance->context);
104
105 /* We always set the return code to 0 before we start the connect sequence*/
106 instance->ConnectionCallbackState = CLIENT_STATE_INITIAL;
107 freerdp_set_last_error_log(instance->context, FREERDP_ERROR_SUCCESS);
108 clearChannelError(instance->context);
109 if (!utils_reset_abort(instance->context->rdp))
110 return -1;
111
112 rdp = instance->context->rdp;
113 WINPR_ASSERT(rdp);
114
115 settings = instance->context->settings;
116 WINPR_ASSERT(settings);
117
118 freerdp_channels_register_instance(instance->context->channels, instance);
119
120 if (!freerdp_settings_set_default_order_support(settings))
121 return -1;
122
123 if (!freerdp_add_signal_cleanup_handler(instance->context, sig_abort_connect))
124 return -1;
125
126 IFCALLRET(instance->PreConnect, status, instance);
127 instance->ConnectionCallbackState = CLIENT_STATE_PRECONNECT_PASSED;
128
129 freerdp_settings_print_warnings(settings);
130 if (status)
131 status = freerdp_settings_enforce_monitor_exists(settings);
132
133 if (status)
134 status = freerdp_settings_enforce_consistency(settings);
135
136 if (status)
137 status = freerdp_settings_check_client_after_preconnect(settings);
138
139 if (status)
140 status = rdp_set_backup_settings(rdp);
141 if (status)
142 status = utils_reload_channels(instance->context);
143
144 const UINT32 cp = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardCodePage);
145 int64_t KeyboardLayout = freerdp_get_keyboard_default_layout_for_locale(cp);
146 if (KeyboardLayout == 0)
147 KeyboardLayout = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout);
148
149 switch (KeyboardLayout)
150 {
151 case KBD_JAPANESE:
152 case KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002:
153 {
154 if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType,
155 WINPR_KBD_TYPE_JAPANESE))
156 return -1;
157 if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType, 2))
158 return -1;
159 if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey, 12))
160 return -1;
161 }
162 break;
163 default:
164 break;
165 }
166
167 if (!status)
168 {
169 rdpContext* context = instance->context;
170 WINPR_ASSERT(context);
171 freerdp_set_last_error_if_not(context, FREERDP_ERROR_PRE_CONNECT_FAILED);
172
173 WLog_Print(context->log, WLOG_ERROR, "freerdp_pre_connect failed: %s",
174 rdp_client_connection_state_string(instance->ConnectionCallbackState));
175 return 0;
176 }
177
178 rc = rdp_client_connect(rdp);
179
180 /* --authonly tests the connection without a UI */
181 if (freerdp_settings_get_bool(rdp->settings, FreeRDP_AuthenticationOnly))
182 {
183 rdpContext* context = rdp->context;
184 WINPR_ASSERT(context);
185 WLog_Print(context->log, WLOG_ERROR, "Authentication only, exit status %" PRId32 "", rc);
186 return 0;
187 }
188
189 return rc ? 1 : 0;
190}
191
192BOOL freerdp_connect(freerdp* instance)
193{
194 BOOL status = FALSE;
195 ConnectionResultEventArgs e = WINPR_C_ARRAY_INIT;
196 const int rc = freerdp_connect_begin(instance);
197 rdpRdp* rdp = nullptr;
198 UINT status2 = ERROR_INTERNAL_ERROR;
199
200 WINPR_ASSERT(instance);
201 WINPR_ASSERT(instance->context);
202
203 rdp = instance->context->rdp;
204 WINPR_ASSERT(rdp);
205 WINPR_ASSERT(rdp->settings);
206
207 if (rc > 0)
208 /* Pointers might have changed in between */
209 {
210 rdp_update_internal* up = update_cast(rdp->update);
211
212 if (freerdp_settings_get_bool(rdp->settings, FreeRDP_DumpRemoteFx))
213 {
214 up->pcap_rfx = pcap_open(
215 freerdp_settings_get_string(rdp->settings, FreeRDP_DumpRemoteFxFile), TRUE);
216
217 if (up->pcap_rfx)
218 up->dump_rfx = TRUE;
219 }
220
221 pointer_cache_register_callbacks(instance->context->update);
222 status = IFCALLRESULT(TRUE, instance->PostConnect, instance);
223 instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
224
225 if (status)
226 status2 = freerdp_channels_post_connect(instance->context->channels, instance);
227 }
228 else
229 {
230 status2 = CHANNEL_RC_OK;
231 if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
232 status = freerdp_reconnect(instance);
233 else
234 goto freerdp_connect_finally;
235 }
236
237 if (!status || (status2 != CHANNEL_RC_OK) || !update_post_connect(instance->context->update))
238 {
239 rdpContext* context = instance->context;
240 WINPR_ASSERT(context);
241 WLog_Print(context->log, WLOG_ERROR, "freerdp_post_connect failed");
242
243 freerdp_set_last_error_if_not(context, FREERDP_ERROR_POST_CONNECT_FAILED);
244
245 status = FALSE;
246 goto freerdp_connect_finally;
247 }
248
249 if (freerdp_settings_get_bool(rdp->settings, FreeRDP_PlayRemoteFx))
250 {
251 wStream* s = nullptr;
252 rdp_update_internal* update = update_cast(instance->context->update);
253 pcap_record record = WINPR_C_ARRAY_INIT;
254
255 WINPR_ASSERT(update);
256 const char* PlayRemoteFxFile =
257 freerdp_settings_get_string(rdp->settings, FreeRDP_PlayRemoteFxFile);
258 update->pcap_rfx = pcap_open(PlayRemoteFxFile, FALSE);
259 status = FALSE;
260
261 if (!update->pcap_rfx)
262 goto freerdp_connect_finally;
263 else
264 update->play_rfx = TRUE;
265
266 status = TRUE;
267
268 while (pcap_has_next_record(update->pcap_rfx) && status)
269 {
270 if (!pcap_get_next_record_header(update->pcap_rfx, &record))
271 break;
272
273 s = transport_take_from_pool(rdp->transport, record.length);
274 if (!s)
275 break;
276
277 record.data = Stream_Buffer(s);
278 if (!pcap_get_next_record_content(update->pcap_rfx, &record))
279 break;
280 if (!Stream_SetLength(s, record.length))
281 {
282 status = FALSE;
283 continue;
284 }
285 Stream_ResetPosition(s);
286
287 if (!update_begin_paint(&update->common))
288 status = FALSE;
289 else
290 {
291 if (!update_recv_surfcmds(&update->common, s))
292 status = FALSE;
293
294 if (!update_end_paint(&update->common))
295 status = FALSE;
296 }
297
298 Stream_Release(s);
299 }
300
301 pcap_close(update->pcap_rfx);
302 update->pcap_rfx = nullptr;
303 goto freerdp_connect_finally;
304 }
305
306 if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
307 freerdp_set_last_error_log(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
308
309 if (status)
310 status = transport_set_connected_event(rdp->transport);
311
312freerdp_connect_finally:
313 EventArgsInit(&e, "freerdp");
314 e.result = status ? 0 : -1;
315 if (PubSub_OnConnectionResult(rdp->pubSub, instance->context, &e) < 0)
316 return FALSE;
317
318 if (!status)
319 freerdp_disconnect(instance);
320
321 return status;
322}
323
324#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
325BOOL freerdp_abort_connect(freerdp* instance)
326{
327 if (!instance)
328 return FALSE;
329
330 return freerdp_abort_connect_context(instance->context);
331}
332#endif
333
334BOOL freerdp_abort_connect_context(rdpContext* context)
335{
336 if (!context)
337 return FALSE;
338
339 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
340 return utils_abort_connect(context->rdp);
341}
342
343#if defined(WITH_FREERDP_DEPRECATED)
344BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, WINPR_ATTR_UNUSED void** wfds,
345 WINPR_ATTR_UNUSED int* wcount)
346{
347 rdpRdp* rdp = nullptr;
348
349 WINPR_ASSERT(instance);
350 WINPR_ASSERT(instance->context);
351
352 rdp = instance->context->rdp;
353 WINPR_ASSERT(rdp);
354
355 transport_get_fds(rdp->transport, rfds, rcount);
356 return TRUE;
357}
358#endif
359
360BOOL freerdp_check_fds(freerdp* instance)
361{
362 int status = 0;
363 rdpRdp* rdp = nullptr;
364
365 if (!instance)
366 return FALSE;
367
368 if (!instance->context)
369 return FALSE;
370
371 if (!instance->context->rdp)
372 return FALSE;
373
374 rdp = instance->context->rdp;
375 status = rdp_check_fds(rdp);
376
377 if (status < 0)
378 {
379 TerminateEventArgs e;
380 rdpContext* context = instance->context;
381 WINPR_ASSERT(context);
382
383 WLog_Print(context->log, WLOG_DEBUG, "rdp_check_fds() - %i", status);
384 EventArgsInit(&e, "freerdp");
385 e.code = 0;
386 if (PubSub_OnTerminate(rdp->pubSub, context, &e) < 0)
387 return FALSE;
388 return FALSE;
389 }
390
391 return TRUE;
392}
393
394DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events, DWORD count)
395{
396 DWORD nCount = 0;
397
398 WINPR_ASSERT(context);
399 WINPR_ASSERT(context->rdp);
400 WINPR_ASSERT(events || (count == 0));
401
402 const size_t rrc = rdp_get_event_handles(context->rdp, &events[nCount], count - nCount);
403 if (rrc == 0)
404 return 0;
405
406 nCount += WINPR_ASSERTING_INT_CAST(uint32_t, rrc);
407
408 if (events && (nCount < count + 2))
409 {
410 events[nCount++] = freerdp_channels_get_event_handle(context->instance);
411 events[nCount++] = getChannelErrorEventHandle(context);
412 }
413 else
414 return 0;
415
416 const SSIZE_T rc = freerdp_client_channel_get_registered_event_handles(
417 context->channels, &events[nCount], count - nCount);
418 if (rc < 0)
419 return 0;
420 return nCount + (DWORD)rc;
421}
422
423/* Resend mouse cursor position to prevent session lock in prevent-session-lock mode */
424static BOOL freerdp_prevent_session_lock(rdpContext* context)
425{
426 WINPR_ASSERT(context);
427 WINPR_ASSERT(context->input);
428
429 rdp_input_internal* in = input_cast(context->input);
430
431 UINT32 FakeMouseMotionInterval =
432 freerdp_settings_get_uint32(context->settings, FreeRDP_FakeMouseMotionInterval);
433 if (FakeMouseMotionInterval && in->lastInputTimestamp)
434 {
435 const time_t now = time(nullptr);
436 if (WINPR_ASSERTING_INT_CAST(size_t, now) - in->lastInputTimestamp >
437 FakeMouseMotionInterval)
438 {
439 WLog_Print(context->log, WLOG_DEBUG,
440 "fake mouse move: x=%d y=%d lastInputTimestamp=%" PRIu64 " "
441 "FakeMouseMotionInterval=%" PRIu32,
442 in->lastX, in->lastY, in->lastInputTimestamp, FakeMouseMotionInterval);
443
444 BOOL status = freerdp_input_send_mouse_event(context->input, PTR_FLAGS_MOVE, in->lastX,
445 in->lastY);
446 if (!status)
447 {
448 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
449 WLog_Print(context->log, WLOG_ERROR,
450 "freerdp_prevent_session_lock() failed - %" PRIi32 "", status);
451
452 return FALSE;
453 }
454
455 return status;
456 }
457 }
458
459 return TRUE;
460}
461
462BOOL freerdp_check_event_handles(rdpContext* context)
463{
464 WINPR_ASSERT(context);
465
466 BOOL status = freerdp_check_fds(context->instance);
467
468 if (!status)
469 {
470 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
471 WLog_Print(context->log, WLOG_ERROR, "freerdp_check_fds() failed - %" PRIi32 "",
472 status);
473
474 return FALSE;
475 }
476
477 status = freerdp_channels_check_fds(context->channels, context->instance);
478
479 if (!status)
480 {
481 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
482 WLog_Print(context->log, WLOG_ERROR,
483 "freerdp_channels_check_fds() failed - %" PRIi32 "", status);
484
485 return FALSE;
486 }
487
488 status = checkChannelErrorEvent(context);
489
490 if (!status)
491 {
492 if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
493 WLog_Print(context->log, WLOG_ERROR, "checkChannelErrorEvent() failed - %" PRIi32 "",
494 status);
495
496 return FALSE;
497 }
498
499 status = freerdp_prevent_session_lock(context);
500
501 return status;
502}
503
504wMessageQueue* freerdp_get_message_queue(freerdp* instance, DWORD id)
505{
506 wMessageQueue* queue = nullptr;
507
508 WINPR_ASSERT(instance);
509
510 rdpContext* context = instance->context;
511 WINPR_ASSERT(context);
512
513 switch (id)
514 {
515 case FREERDP_UPDATE_MESSAGE_QUEUE:
516 {
517 rdp_update_internal* update = update_cast(context->update);
518 queue = update->queue;
519 }
520 break;
521
522 case FREERDP_INPUT_MESSAGE_QUEUE:
523 {
524 rdp_input_internal* input = input_cast(context->input);
525 queue = input->queue;
526 }
527 break;
528 default:
529 break;
530 }
531
532 return queue;
533}
534
535HANDLE freerdp_get_message_queue_event_handle(freerdp* instance, DWORD id)
536{
537 HANDLE event = nullptr;
538 wMessageQueue* queue = freerdp_get_message_queue(instance, id);
539
540 if (queue)
541 event = MessageQueue_Event(queue);
542
543 return event;
544}
545
546int freerdp_message_queue_process_message(freerdp* instance, DWORD id, wMessage* message)
547{
548 int status = -1;
549 rdpContext* context = nullptr;
550
551 WINPR_ASSERT(instance);
552
553 context = instance->context;
554 WINPR_ASSERT(context);
555
556 switch (id)
557 {
558 case FREERDP_UPDATE_MESSAGE_QUEUE:
559 status = update_message_queue_process_message(context->update, message);
560 break;
561
562 case FREERDP_INPUT_MESSAGE_QUEUE:
563 status = input_message_queue_process_message(context->input, message);
564 break;
565 default:
566 break;
567 }
568
569 return status;
570}
571
572int freerdp_message_queue_process_pending_messages(freerdp* instance, DWORD id)
573{
574 int status = -1;
575 rdpContext* context = nullptr;
576
577 WINPR_ASSERT(instance);
578
579 context = instance->context;
580 WINPR_ASSERT(context);
581
582 switch (id)
583 {
584 case FREERDP_UPDATE_MESSAGE_QUEUE:
585 status = update_message_queue_process_pending_messages(context->update);
586 break;
587
588 case FREERDP_INPUT_MESSAGE_QUEUE:
589 status = input_message_queue_process_pending_messages(context->input);
590 break;
591 default:
592 break;
593 }
594
595 return status;
596}
597
598static BOOL freerdp_send_channel_data(freerdp* instance, UINT16 channelId, const BYTE* data,
599 size_t size)
600{
601 WINPR_ASSERT(instance);
602 WINPR_ASSERT(instance->context);
603 WINPR_ASSERT(instance->context->rdp);
604 return rdp_send_channel_data(instance->context->rdp, channelId, data, size);
605}
606
607static BOOL freerdp_send_channel_packet(freerdp* instance, UINT16 channelId, size_t totalSize,
608 UINT32 flags, const BYTE* data, size_t chunkSize)
609{
610 WINPR_ASSERT(instance);
611 WINPR_ASSERT(instance->context);
612 WINPR_ASSERT(instance->context->rdp);
613 return rdp_channel_send_packet(instance->context->rdp, channelId, totalSize, flags, data,
614 chunkSize);
615}
616
617BOOL freerdp_disconnect(freerdp* instance)
618{
619 BOOL rc = TRUE;
620
621 if (!instance || !instance->context)
622 return FALSE;
623
624 rdpRdp* rdp = instance->context->rdp;
625 if (rdp)
626 {
627 /* Try to send a [MS-RDPBCGR] 1.3.1.4.1 User-Initiated on Client PDU, we don't care about
628 * success */
629 if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_CANCELLED)
630 {
631 (void)mcs_send_disconnect_provider_ultimatum(rdp->mcs,
632 Disconnect_Ultimatum_user_requested);
633 }
634 }
635
636 utils_abort_connect(rdp);
637
638 if (!rdp_client_disconnect(rdp))
639 rc = FALSE;
640
641 rdp_update_internal* up = nullptr;
642 if (rdp && rdp->update)
643 {
644 up = update_cast(rdp->update);
645
646 update_post_disconnect(rdp->update);
647 }
648
649 IFCALL(instance->PostDisconnect, instance);
650 cache_free(instance->context->cache);
651 instance->context->cache = nullptr;
652
653 if (up)
654 {
655 update_dump_stats(rdp->update);
656 if (up->pcap_rfx)
657 {
658 up->dump_rfx = FALSE;
659 pcap_close(up->pcap_rfx);
660 up->pcap_rfx = nullptr;
661 }
662 }
663
664 if (instance->context->channels)
665 freerdp_channels_close(instance->context->channels, instance);
666
667 IFCALL(instance->PostFinalDisconnect, instance);
668
669 freerdp_del_signal_cleanup_handler(instance->context, sig_abort_connect);
670 return rc;
671}
672
673#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
674BOOL freerdp_disconnect_before_reconnect(freerdp* instance)
675{
676 WINPR_ASSERT(instance);
677 return freerdp_disconnect_before_reconnect_context(instance->context);
678}
679#endif
680
681BOOL freerdp_disconnect_before_reconnect_context(rdpContext* context)
682{
683 rdpRdp* rdp = nullptr;
684
685 WINPR_ASSERT(context);
686
687 rdp = context->rdp;
688 return rdp_client_disconnect_and_clear(rdp);
689}
690
691BOOL freerdp_reconnect(freerdp* instance)
692{
693 rdpRdp* rdp = nullptr;
694
695 WINPR_ASSERT(instance);
696 WINPR_ASSERT(instance->context);
697
698 if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_CANCELLED)
699 return FALSE;
700
701 rdp = instance->context->rdp;
702
703 if (!utils_reset_abort(instance->context->rdp))
704 return FALSE;
705 return rdp_client_reconnect(rdp);
706}
707
708#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
709BOOL freerdp_shall_disconnect(const freerdp* instance)
710{
711 if (!instance)
712 return FALSE;
713
714 return freerdp_shall_disconnect_context(instance->context);
715}
716#endif
717
718BOOL freerdp_shall_disconnect_context(const rdpContext* context)
719{
720 if (!context)
721 return FALSE;
722
723 return utils_abort_event_is_set(context->rdp);
724}
725
726BOOL freerdp_focus_required(freerdp* instance)
727{
728 rdpRdp* rdp = nullptr;
729 BOOL bRetCode = FALSE;
730
731 WINPR_ASSERT(instance);
732 WINPR_ASSERT(instance->context);
733
734 rdp = instance->context->rdp;
735 WINPR_ASSERT(rdp);
736
737 if (rdp->resendFocus)
738 {
739 bRetCode = TRUE;
740 rdp->resendFocus = FALSE;
741 }
742
743 return bRetCode;
744}
745
746void freerdp_set_focus(freerdp* instance)
747{
748 rdpRdp* rdp = nullptr;
749
750 WINPR_ASSERT(instance);
751 WINPR_ASSERT(instance->context);
752
753 rdp = instance->context->rdp;
754 WINPR_ASSERT(rdp);
755
756 rdp->resendFocus = TRUE;
757}
758
759void freerdp_get_version(int* major, int* minor, int* revision)
760{
761 if (major != nullptr)
762 *major = FREERDP_VERSION_MAJOR;
763
764 if (minor != nullptr)
765 *minor = FREERDP_VERSION_MINOR;
766
767 if (revision != nullptr)
768 *revision = FREERDP_VERSION_REVISION;
769}
770
771const char* freerdp_get_version_string(void)
772{
773 return FREERDP_VERSION_FULL;
774}
775
776const char* freerdp_get_build_config(void)
777{
778 WINPR_PRAGMA_DIAG_PUSH
779 WINPR_PRAGMA_DIAG_IGNORED_OVERLENGTH_STRINGS
780 static const char build_config[] =
781 "Build configuration: " FREERDP_BUILD_CONFIG "\n"
782 "Build type: " FREERDP_BUILD_TYPE "\n"
783 "CFLAGS: " FREERDP_CFLAGS "\n"
784 "Compiler: " FREERDP_COMPILER_ID ", " FREERDP_COMPILER_VERSION "\n"
785 "Target architecture: " FREERDP_TARGET_ARCH "\n";
786 WINPR_PRAGMA_DIAG_POP
787 return build_config;
788}
789
790const char* freerdp_get_build_revision(void)
791{
792 return FREERDP_GIT_REVISION;
793}
794
795static wEventType FreeRDP_Events[] = {
796 DEFINE_EVENT_ENTRY(WindowStateChange), DEFINE_EVENT_ENTRY(ResizeWindow),
797 DEFINE_EVENT_ENTRY(LocalResizeWindow), DEFINE_EVENT_ENTRY(EmbedWindow),
798 DEFINE_EVENT_ENTRY(PanningChange), DEFINE_EVENT_ENTRY(ZoomingChange),
799 DEFINE_EVENT_ENTRY(ErrorInfo), DEFINE_EVENT_ENTRY(Terminate),
800 DEFINE_EVENT_ENTRY(ConnectionResult), DEFINE_EVENT_ENTRY(ChannelConnected),
801 DEFINE_EVENT_ENTRY(ChannelDisconnected), DEFINE_EVENT_ENTRY(MouseEvent),
802 DEFINE_EVENT_ENTRY(Activated), DEFINE_EVENT_ENTRY(Timer),
803 DEFINE_EVENT_ENTRY(GraphicsReset), DEFINE_EVENT_ENTRY(UserNotification),
804 DEFINE_EVENT_ENTRY(ChannelInitialized), DEFINE_EVENT_ENTRY(ChannelTerminated),
805 DEFINE_EVENT_ENTRY(StateChanged)
806};
807
818BOOL freerdp_context_new(freerdp* instance)
819{
820 return freerdp_context_new_ex(instance, nullptr);
821}
822
823static BOOL freerdp_common_context(rdpContext* context, AccessTokenType tokenType, char** token,
824 size_t count, ...)
825{
826 BOOL rc = FALSE;
827
828 WINPR_ASSERT(context);
829 if (!context->instance || !context->instance->GetAccessToken)
830 return TRUE;
831
832 va_list ap = WINPR_C_ARRAY_INIT;
833 va_start(ap, count);
834 switch (tokenType)
835 {
836 case ACCESS_TOKEN_TYPE_AAD:
837 if (count != 2)
838 {
839 WLog_ERR(TAG,
840 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
841 ", aborting",
842 count);
843 }
844 else
845 {
846 const char* scope = va_arg(ap, const char*);
847 const char* req_cnf = va_arg(ap, const char*);
848 rc = context->instance->GetAccessToken(context->instance, tokenType, token, count,
849 scope, req_cnf);
850 }
851 break;
852 case ACCESS_TOKEN_TYPE_AVD:
853 if (count != 0)
854 {
855 WLog_WARN(TAG,
856 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
857 ", ignoring",
858 count);
859 }
860 else
861 {
862 rc = context->instance->GetAccessToken(context->instance, tokenType, token, count);
863 }
864 break;
865 default:
866 break;
867 }
868 va_end(ap);
869
870 if (!rc)
871 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
872
873 return rc;
874}
875
876BOOL freerdp_context_new_ex(freerdp* instance, rdpSettings* settings)
877{
878 rdpRdp* rdp = nullptr;
879 rdpContext* context = nullptr;
880 BOOL ret = TRUE;
881
882 WINPR_ASSERT(instance);
883
884 instance->context = context = (rdpContext*)calloc(1, instance->ContextSize);
885
886 if (!context)
887 return FALSE;
888
889 context->log = WLog_Get(TAG);
890 if (!context->log)
891 goto fail;
892
893 /* Set to external settings, prevents rdp_new from creating its own instance */
894 context->settings = settings;
895 context->instance = instance;
896 context->ServerMode = FALSE;
897 context->disconnectUltimatum = 0;
898
899 context->metrics = metrics_new(context);
900
901 if (!context->metrics)
902 goto fail;
903
904 rdp = rdp_new(context);
905
906 if (!rdp)
907 goto fail;
908
909 context->rdp = rdp;
910 context->pubSub = rdp->pubSub;
911
912 if (!context->pubSub)
913 goto fail;
914
915 PubSub_AddEventTypes(rdp->pubSub, FreeRDP_Events, ARRAYSIZE(FreeRDP_Events));
916
917#if defined(WITH_FREERDP_DEPRECATED)
918 instance->input = rdp->input;
919 instance->update = rdp->update;
920 instance->settings = rdp->settings;
921 instance->autodetect = rdp->autodetect;
922#endif
923
924 instance->heartbeat = rdp->heartbeat;
925 context->graphics = graphics_new(context);
926
927 if (!context->graphics)
928 goto fail;
929
930 context->input = rdp->input;
931 context->update = rdp->update;
932 context->settings = rdp->settings;
933 context->autodetect = rdp->autodetect;
934
935 if (!(context->errorDescription = calloc(1, 500)))
936 {
937 WLog_Print(context->log, WLOG_ERROR, "calloc failed!");
938 goto fail;
939 }
940
941 if (!(context->channelErrorEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
942 {
943 WLog_Print(context->log, WLOG_ERROR, "CreateEvent failed!");
944 goto fail;
945 }
946
947 update_register_client_callbacks(rdp->update);
948
949 if (!(context->channels = freerdp_channels_new(instance)))
950 goto fail;
951
952 context->dump = stream_dump_new();
953 if (!context->dump)
954 goto fail;
955
956 /* Fallback:
957 * Client common library might set a function pointer to handle this, but here we provide a
958 * default implementation that simply calls instance->GetAccessToken.
959 */
960 if (!freerdp_set_common_access_token(context, freerdp_common_context))
961 goto fail;
962
963 IFCALLRET(instance->ContextNew, ret, instance, context);
964
965 if (!ret)
966 goto fail;
967
968 return TRUE;
969
970fail:
971 freerdp_context_free(instance);
972 return FALSE;
973}
974
975BOOL freerdp_context_reset(freerdp* instance)
976{
977 if (!instance)
978 return FALSE;
979
980 WINPR_ASSERT(instance->context);
981 rdpRdp* rdp = instance->context->rdp;
982
983 return rdp_reset_runtime_settings(rdp);
984}
985
994void freerdp_context_free(freerdp* instance)
995{
996 rdpContext* ctx = nullptr;
997
998 if (!instance)
999 return;
1000
1001 if (!instance->context)
1002 return;
1003
1004 ctx = instance->context;
1005
1006 IFCALL(instance->ContextFree, instance, ctx);
1007 rdp_free(ctx->rdp);
1008 ctx->rdp = nullptr;
1009 ctx->settings = nullptr; /* owned by rdpRdp */
1010
1011 graphics_free(ctx->graphics);
1012 ctx->graphics = nullptr;
1013
1014 metrics_free(ctx->metrics);
1015 ctx->metrics = nullptr;
1016
1017 if (ctx->channelErrorEvent)
1018 (void)CloseHandle(ctx->channelErrorEvent);
1019 ctx->channelErrorEvent = nullptr;
1020
1021 free(ctx->errorDescription);
1022 ctx->errorDescription = nullptr;
1023
1024 freerdp_channels_free(ctx->channels);
1025 ctx->channels = nullptr;
1026
1027 freerdp_client_codecs_free(ctx->codecs);
1028 ctx->codecs = nullptr;
1029
1030 stream_dump_free(ctx->dump);
1031 ctx->dump = nullptr;
1032
1033 ctx->input = nullptr; /* owned by rdpRdp */
1034 ctx->update = nullptr; /* owned by rdpRdp */
1035 ctx->settings = nullptr; /* owned by rdpRdp */
1036 ctx->autodetect = nullptr; /* owned by rdpRdp */
1037
1038 free(ctx);
1039 instance->context = nullptr;
1040#if defined(WITH_FREERDP_DEPRECATED)
1041 instance->input = nullptr; /* owned by rdpRdp */
1042 instance->update = nullptr; /* owned by rdpRdp */
1043 instance->settings = nullptr; /* owned by rdpRdp */
1044 instance->autodetect = nullptr; /* owned by rdpRdp */
1045#endif
1046 instance->heartbeat = nullptr; /* owned by rdpRdp */
1047}
1048
1049int freerdp_get_disconnect_ultimatum(const rdpContext* context)
1050{
1051 WINPR_ASSERT(context);
1052 return context->disconnectUltimatum;
1053}
1054
1055UINT32 freerdp_error_info(const freerdp* instance)
1056{
1057 WINPR_ASSERT(instance);
1058 WINPR_ASSERT(instance->context);
1059 WINPR_ASSERT(instance->context->rdp);
1060 return instance->context->rdp->errorInfo;
1061}
1062
1063void freerdp_set_error_info(rdpRdp* rdp, UINT32 error)
1064{
1065 if (!rdp)
1066 return;
1067
1068 rdp_set_error_info(rdp, error);
1069}
1070
1071BOOL freerdp_send_error_info(rdpRdp* rdp)
1072{
1073 if (!rdp)
1074 return FALSE;
1075
1076 return rdp_send_error_info(rdp);
1077}
1078
1079UINT32 freerdp_get_last_error(const rdpContext* context)
1080{
1081 WINPR_ASSERT(context);
1082 return context->LastError;
1083}
1084
1085const char* freerdp_get_last_error_name(UINT32 code)
1086{
1087 const char* name = nullptr;
1088 const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1089 const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1090
1091 switch (cls)
1092 {
1093 case FREERDP_ERROR_ERRBASE_CLASS:
1094 name = freerdp_get_error_base_name(type);
1095 break;
1096
1097 case FREERDP_ERROR_ERRINFO_CLASS:
1098 name = freerdp_get_error_info_name(type);
1099 break;
1100
1101 case FREERDP_ERROR_CONNECT_CLASS:
1102 name = freerdp_get_error_connect_name(type);
1103 break;
1104
1105 default:
1106 name = rpc_error_to_string(code);
1107 break;
1108 }
1109
1110 return name;
1111}
1112
1113const char* freerdp_get_last_error_string(UINT32 code)
1114{
1115 const char* string = nullptr;
1116 const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1117 const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1118
1119 switch (cls)
1120 {
1121 case FREERDP_ERROR_ERRBASE_CLASS:
1122 string = freerdp_get_error_base_string(type);
1123 break;
1124
1125 case FREERDP_ERROR_ERRINFO_CLASS:
1126 string = freerdp_get_error_info_string(type);
1127 break;
1128
1129 case FREERDP_ERROR_CONNECT_CLASS:
1130 string = freerdp_get_error_connect_string(type);
1131 break;
1132
1133 default:
1134 string = rpc_error_to_string(code);
1135 break;
1136 }
1137
1138 return string;
1139}
1140
1141const char* freerdp_get_last_error_category(UINT32 code)
1142{
1143 const char* string = nullptr;
1144 const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1145 const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1146
1147 switch (cls)
1148 {
1149 case FREERDP_ERROR_ERRBASE_CLASS:
1150 string = freerdp_get_error_base_category(type);
1151 break;
1152
1153 case FREERDP_ERROR_ERRINFO_CLASS:
1154 string = freerdp_get_error_info_category(type);
1155 break;
1156
1157 case FREERDP_ERROR_CONNECT_CLASS:
1158 string = freerdp_get_error_connect_category(type);
1159 break;
1160
1161 default:
1162 string = rpc_error_to_category(code);
1163 break;
1164 }
1165
1166 return string;
1167}
1168
1169void freerdp_set_last_error_ex(rdpContext* context, UINT32 lastError, const char* fkt,
1170 const char* file, int line)
1171{
1172 WINPR_ASSERT(context);
1173 WINPR_ASSERT(line >= 0);
1174
1175 if (lastError)
1176 {
1177 if (WLog_IsLevelActive(context->log, WLOG_ERROR))
1178 {
1179 WLog_PrintTextMessage(context->log, WLOG_ERROR, (size_t)line, file, fkt,
1180 "%s [0x%08" PRIX32 "]", freerdp_get_last_error_name(lastError),
1181 lastError);
1182 }
1183 }
1184
1185 if (lastError == FREERDP_ERROR_SUCCESS)
1186 {
1187 if (WLog_IsLevelActive(context->log, WLOG_DEBUG))
1188 WLog_PrintTextMessage(context->log, WLOG_DEBUG, (size_t)line, file, fkt,
1189 "resetting error state");
1190 }
1191 else if (context->LastError != FREERDP_ERROR_SUCCESS)
1192 {
1193 if (WLog_IsLevelActive(context->log, WLOG_ERROR))
1194 {
1195 WLog_PrintTextMessage(context->log, WLOG_ERROR, (size_t)line, file, fkt,
1196 "TODO: Trying to set error code %s, but %s already set!",
1197 freerdp_get_last_error_name(lastError),
1198 freerdp_get_last_error_name(context->LastError));
1199 }
1200 }
1201 context->LastError = lastError;
1202}
1203
1204const char* freerdp_get_logon_error_info_type_ex(UINT32 type, char* buffer, size_t size)
1205{
1206 const char* str = freerdp_get_logon_error_info_type(type);
1207 (void)_snprintf(buffer, size, "%s(0x%04" PRIx32 ")", str, type);
1208 return buffer;
1209}
1210
1211const char* freerdp_get_logon_error_info_type(UINT32 type)
1212{
1213#define CASE_ENTRY(x) \
1214 case x: \
1215 return #x
1216 switch (type)
1217 {
1218 CASE_ENTRY(LOGON_MSG_SESSION_BUSY_OPTIONS);
1219 CASE_ENTRY(LOGON_MSG_DISCONNECT_REFUSED);
1220 CASE_ENTRY(LOGON_MSG_NO_PERMISSION);
1221 CASE_ENTRY(LOGON_MSG_BUMP_OPTIONS);
1222 CASE_ENTRY(LOGON_MSG_RECONNECT_OPTIONS);
1223 CASE_ENTRY(LOGON_MSG_SESSION_TERMINATE);
1224 CASE_ENTRY(LOGON_MSG_SESSION_CONTINUE);
1225 CASE_ENTRY(ERROR_CODE_ACCESS_DENIED);
1226
1227 default:
1228 return NtStatus2Tag((NTSTATUS)type);
1229 }
1230#undef CASE_ENTRY
1231}
1232
1233const char* freerdp_get_logon_error_info_data(UINT32 data)
1234{
1235#define CASE_ENTRY(x) \
1236 case x: \
1237 return #x
1238 switch (data)
1239 {
1240 CASE_ENTRY(LOGON_FAILED_BAD_PASSWORD);
1241 CASE_ENTRY(LOGON_FAILED_UPDATE_PASSWORD);
1242 CASE_ENTRY(LOGON_FAILED_OTHER);
1243 CASE_ENTRY(LOGON_WARNING);
1244
1245 default:
1246 return "SESSION_ID";
1247 }
1248#undef CASE_ENTRY
1249}
1250
1251const char* freerdp_get_logon_error_info_data_ex(UINT32 data, char* buffer, size_t size)
1252{
1253 const char* str = freerdp_get_logon_error_info_data(data);
1254 (void)_snprintf(buffer, size, "%s(0x%04" PRIx32 ")", str, data);
1255 return buffer;
1256}
1257
1261freerdp* freerdp_new(void)
1262{
1263 if (!utils_set_umask())
1264 return nullptr;
1265
1266 freerdp* instance = (freerdp*)calloc(1, sizeof(freerdp));
1267
1268 if (!instance)
1269 return nullptr;
1270
1271 instance->ContextSize = sizeof(rdpContext);
1272 instance->SendChannelData = freerdp_send_channel_data;
1273 instance->SendChannelPacket = freerdp_send_channel_packet;
1274 instance->ReceiveChannelData = freerdp_channels_data;
1275 return instance;
1276}
1277
1282void freerdp_free(freerdp* instance)
1283{
1284 free(instance);
1285}
1286
1287ULONG freerdp_get_transport_sent(const rdpContext* context, BOOL resetCount)
1288{
1289 WINPR_ASSERT(context);
1290 WINPR_ASSERT(context->rdp);
1291 UINT64 rc = transport_get_bytes_sent(context->rdp->transport, resetCount);
1292 return WINPR_CXX_COMPAT_CAST(ULONG, MIN(rc, UINT32_MAX));
1293}
1294
1295BOOL freerdp_nla_impersonate(rdpContext* context)
1296{
1297 rdpNla* nla = nullptr;
1298
1299 if (!context)
1300 return FALSE;
1301
1302 if (!context->rdp)
1303 return FALSE;
1304
1305 if (!context->rdp->transport)
1306 return FALSE;
1307
1308 nla = transport_get_nla(context->rdp->transport);
1309 return nla_impersonate(nla);
1310}
1311
1312BOOL freerdp_nla_revert_to_self(rdpContext* context)
1313{
1314 rdpNla* nla = nullptr;
1315
1316 if (!context)
1317 return FALSE;
1318
1319 if (!context->rdp)
1320 return FALSE;
1321
1322 if (!context->rdp->transport)
1323 return FALSE;
1324
1325 nla = transport_get_nla(context->rdp->transport);
1326 return nla_revert_to_self(nla);
1327}
1328
1329UINT32 freerdp_get_nla_sspi_error(const rdpContext* context)
1330{
1331 WINPR_ASSERT(context);
1332 WINPR_ASSERT(context->rdp);
1333 WINPR_ASSERT(context->rdp->transport);
1334
1335 rdpNla* nla = context->rdp->nla;
1336 if (!nla)
1337 nla = transport_get_nla(context->rdp->transport);
1338 return (UINT32)nla_get_sspi_error(nla);
1339}
1340
1341BOOL freerdp_nla_encrypt(rdpContext* context, const SecBuffer* inBuffer, SecBuffer* outBuffer)
1342{
1343 WINPR_ASSERT(context);
1344 WINPR_ASSERT(context->rdp);
1345
1346 rdpNla* nla = context->rdp->nla;
1347 return nla_encrypt(nla, inBuffer, outBuffer);
1348}
1349
1350BOOL freerdp_nla_decrypt(rdpContext* context, const SecBuffer* inBuffer, SecBuffer* outBuffer)
1351{
1352 WINPR_ASSERT(context);
1353 WINPR_ASSERT(context->rdp);
1354
1355 rdpNla* nla = context->rdp->nla;
1356 return nla_decrypt(nla, inBuffer, outBuffer);
1357}
1358
1359SECURITY_STATUS freerdp_nla_QueryContextAttributes(rdpContext* context, DWORD ulAttr, PVOID pBuffer)
1360{
1361 WINPR_ASSERT(context);
1362 WINPR_ASSERT(context->rdp);
1363
1364 rdpNla* nla = context->rdp->nla;
1365 if (!nla)
1366 nla = transport_get_nla(context->rdp->transport);
1367
1368 WINPR_ASSERT(nla);
1369
1370 return nla_QueryContextAttributes(nla, ulAttr, pBuffer);
1371}
1372
1373SECURITY_STATUS freerdp_nla_FreeContextBuffer(rdpContext* context, PVOID pBuffer)
1374{
1375 WINPR_ASSERT(context);
1376 WINPR_ASSERT(context->rdp);
1377
1378 rdpNla* nla = context->rdp->nla;
1379 if (!nla)
1380 nla = transport_get_nla(context->rdp->transport);
1381
1382 WINPR_ASSERT(nla);
1383
1384 return nla_FreeContextBuffer(nla, pBuffer);
1385}
1386
1387HANDLE getChannelErrorEventHandle(rdpContext* context)
1388{
1389 WINPR_ASSERT(context);
1390 return context->channelErrorEvent;
1391}
1392
1393BOOL checkChannelErrorEvent(rdpContext* context)
1394{
1395 WINPR_ASSERT(context);
1396
1397 if (WaitForSingleObject(context->channelErrorEvent, 0) == WAIT_OBJECT_0)
1398 {
1399 WLog_Print(context->log, WLOG_ERROR, "%s. Error was %" PRIu32 "", context->errorDescription,
1400 context->channelErrorNum);
1401 return FALSE;
1402 }
1403
1404 return TRUE;
1405}
1406
1412UINT getChannelError(const rdpContext* context)
1413{
1414 WINPR_ASSERT(context);
1415 return context->channelErrorNum;
1416}
1417
1418const char* getChannelErrorDescription(const rdpContext* context)
1419{
1420 WINPR_ASSERT(context);
1421 return context->errorDescription;
1422}
1423
1424void clearChannelError(rdpContext* context)
1425{
1426 WINPR_ASSERT(context);
1427 context->channelErrorNum = 0;
1428 memset(context->errorDescription, 0, 500);
1429 (void)ResetEvent(context->channelErrorEvent);
1430}
1431
1432WINPR_ATTR_FORMAT_ARG(3, 4)
1433void setChannelError(rdpContext* context, UINT errorNum, WINPR_FORMAT_ARG const char* format, ...)
1434{
1435 va_list ap = WINPR_C_ARRAY_INIT;
1436 va_start(ap, format);
1437
1438 WINPR_ASSERT(context);
1439
1440 context->channelErrorNum = errorNum;
1441 (void)vsnprintf(context->errorDescription, 499, format, ap);
1442 va_end(ap);
1443 (void)SetEvent(context->channelErrorEvent);
1444}
1445
1446const char* freerdp_nego_get_routing_token(const rdpContext* context, DWORD* length)
1447{
1448 if (!context || !context->rdp)
1449 return nullptr;
1450
1451 return (const char*)nego_get_routing_token(context->rdp->nego, length);
1452}
1453
1454BOOL freerdp_io_callback_set_event(rdpContext* context, BOOL set)
1455{
1456 WINPR_ASSERT(context);
1457 return rdp_io_callback_set_event(context->rdp, set);
1458}
1459
1460const rdpTransportIo* freerdp_get_io_callbacks(rdpContext* context)
1461{
1462 WINPR_ASSERT(context);
1463 return rdp_get_io_callbacks(context->rdp);
1464}
1465
1466BOOL freerdp_set_io_callbacks(rdpContext* context, const rdpTransportIo* io_callbacks)
1467{
1468 WINPR_ASSERT(context);
1469 return rdp_set_io_callbacks(context->rdp, io_callbacks);
1470}
1471
1472BOOL freerdp_set_io_callback_context(rdpContext* context, void* usercontext)
1473{
1474 WINPR_ASSERT(context);
1475 return rdp_set_io_callback_context(context->rdp, usercontext);
1476}
1477
1478void* freerdp_get_io_callback_context(rdpContext* context)
1479{
1480 WINPR_ASSERT(context);
1481 return rdp_get_io_callback_context(context->rdp);
1482}
1483
1484CONNECTION_STATE freerdp_get_state(const rdpContext* context)
1485{
1486 WINPR_ASSERT(context);
1487 return rdp_get_state(context->rdp);
1488}
1489
1490const char* freerdp_state_string(CONNECTION_STATE state)
1491{
1492 return rdp_state_string(state);
1493}
1494
1495BOOL freerdp_is_active_state(const rdpContext* context)
1496{
1497 WINPR_ASSERT(context);
1498 return rdp_is_active_state(context->rdp);
1499}
1500
1501BOOL freerdp_channels_from_mcs(rdpSettings* settings, const rdpContext* context)
1502{
1503 WINPR_ASSERT(context);
1504 return rdp_channels_from_mcs(settings, context->rdp);
1505}
1506
1507HANDLE freerdp_abort_event(rdpContext* context)
1508{
1509 WINPR_ASSERT(context);
1510 return utils_get_abort_event(context->rdp);
1511}
1512
1513static void test_mcs_free(rdpMcs* mcs)
1514{
1515 if (!mcs)
1516 return;
1517
1518 if (mcs->context)
1519 {
1520 rdpSettings* settings = mcs->context->settings;
1521 freerdp_settings_free(settings);
1522 }
1523 free(mcs->context);
1524
1525 mcs_free(mcs);
1526}
1527
1528static rdpMcs* test_mcs_new(void)
1529{
1530 rdpSettings* settings = freerdp_settings_new(0);
1531 rdpContext* context = calloc(1, sizeof(rdpContext));
1532
1533 if (!settings)
1534 goto fail;
1535 if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, TRUE))
1536 goto fail;
1537
1538 if (!context)
1539 goto fail;
1540 context->settings = settings;
1541 return mcs_new(context);
1542
1543fail:
1544 free(context);
1545 freerdp_settings_free(settings);
1546
1547 return nullptr;
1548}
1549
1550BOOL freerdp_is_valid_mcs_create_request(const BYTE* data, size_t size)
1551{
1552
1553 wStream sbuffer = WINPR_C_ARRAY_INIT;
1554 wStream* s = Stream_StaticConstInit(&sbuffer, data, size);
1555
1556 WINPR_ASSERT(data || (size == 0));
1557 WINPR_ASSERT(s);
1558
1559 rdpMcs* mcs = test_mcs_new();
1560 WINPR_ASSERT(mcs);
1561
1562 BOOL result = mcs_recv_connect_initial(mcs, s);
1563 test_mcs_free(mcs);
1564 return result;
1565}
1566
1567BOOL freerdp_is_valid_mcs_create_response(const BYTE* data, size_t size)
1568{
1569
1570 wStream sbuffer = WINPR_C_ARRAY_INIT;
1571 wStream* s = Stream_StaticConstInit(&sbuffer, data, size);
1572
1573 WINPR_ASSERT(data || (size == 0));
1574 WINPR_ASSERT(s);
1575
1576 rdpMcs* mcs = test_mcs_new();
1577 WINPR_ASSERT(mcs);
1578
1579 BOOL result = mcs_recv_connect_response(mcs, s);
1580 test_mcs_free(mcs);
1581 return result;
1582}
1583
1584BOOL freerdp_persist_credentials(rdpContext* context)
1585{
1586 if (!context)
1587 return FALSE;
1588 WINPR_ASSERT(context->rdp);
1589 return utils_persist_credentials(context->rdp->originalSettings, context->rdp->settings);
1590}
1591
1592const char* freerdp_disconnect_reason_string(int reason)
1593{
1594 switch (reason)
1595 {
1596 case Disconnect_Ultimatum_domain_disconnected:
1597 return "rn-domain-disconnected";
1598 case Disconnect_Ultimatum_provider_initiated:
1599 return "rn-provider-initiated";
1600 case Disconnect_Ultimatum_token_purged:
1601 return "rn-token-purged";
1602 case Disconnect_Ultimatum_user_requested:
1603 return "rn-user-requested";
1604 case Disconnect_Ultimatum_channel_purged:
1605 return "rn-channel-purged";
1606 default:
1607 return "rn-unknown";
1608 }
1609}
1610
1611BOOL freerdp_set_common_access_token(rdpContext* context,
1612 pGetCommonAccessToken GetCommonAccessToken)
1613{
1614 WINPR_ASSERT(context);
1615 WINPR_ASSERT(context->rdp);
1616 context->rdp->GetCommonAccessToken = GetCommonAccessToken;
1617 return TRUE;
1618}
1619
1620pGetCommonAccessToken freerdp_get_common_access_token(const rdpContext* context)
1621{
1622 WINPR_ASSERT(context);
1623 WINPR_ASSERT(context->rdp);
1624 return context->rdp->GetCommonAccessToken;
1625}
FREERDP_API rdpSettings * freerdp_settings_new(DWORD flags)
creates a new setting struct
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 BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
FREERDP_API void freerdp_settings_free(rdpSettings *settings)
Free a settings struct with all data in it.
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_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.