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