FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
pf_server.c
1
24#include <freerdp/config.h>
25
26#include <winpr/crt.h>
27#include <winpr/ssl.h>
28#include <winpr/path.h>
29#include <winpr/synch.h>
30#include <winpr/string.h>
31#include <winpr/winsock.h>
32#include <winpr/thread.h>
33#include <errno.h>
34
35#include <freerdp/freerdp.h>
36#include <freerdp/streamdump.h>
37#include <freerdp/channels/wtsvc.h>
38#include <freerdp/channels/channels.h>
39#include <freerdp/channels/drdynvc.h>
40#include <freerdp/build-config.h>
41
42#include <freerdp/channels/rdpdr.h>
43
44#include <freerdp/server/proxy/proxy_server.h>
45#include <freerdp/server/proxy/proxy_log.h>
46
47#include "pf_server.h"
48#include "pf_channel.h"
49#include <freerdp/server/proxy/proxy_config.h>
50#include "pf_client.h"
51#include <freerdp/server/proxy/proxy_context.h>
52#include "pf_update.h"
53#include "proxy_modules.h"
54#include "pf_utils.h"
55#include "channels/pf_channel_drdynvc.h"
56#include "channels/pf_channel_rdpdr.h"
57
58#define TAG PROXY_TAG("server")
59
60typedef struct
61{
62 HANDLE thread;
63 freerdp_peer* client;
64} peer_thread_args;
65
66static BOOL pf_server_parse_target_from_routing_token(rdpContext* context, rdpSettings* settings,
67 FreeRDP_Settings_Keys_String targetID,
68 FreeRDP_Settings_Keys_UInt32 portID)
69{
70#define TARGET_MAX (100)
71#define ROUTING_TOKEN_PREFIX "Cookie: msts="
72 char* colon = NULL;
73 size_t len = 0;
74 DWORD routing_token_length = 0;
75 const size_t prefix_len = strnlen(ROUTING_TOKEN_PREFIX, sizeof(ROUTING_TOKEN_PREFIX));
76 const char* routing_token = freerdp_nego_get_routing_token(context, &routing_token_length);
77 pServerContext* ps = (pServerContext*)context;
78
79 if (!routing_token)
80 return FALSE;
81
82 if ((routing_token_length <= prefix_len) || (routing_token_length >= TARGET_MAX))
83 {
84 PROXY_LOG_ERR(TAG, ps, "invalid routing token length: %" PRIu32 "", routing_token_length);
85 return FALSE;
86 }
87
88 len = routing_token_length - prefix_len;
89
90 if (!freerdp_settings_set_string_len(settings, targetID, routing_token + prefix_len, len))
91 return FALSE;
92
93 const char* target = freerdp_settings_get_string(settings, targetID);
94 colon = strchr(target, ':');
95
96 if (colon)
97 {
98 /* port is specified */
99 unsigned long p = strtoul(colon + 1, NULL, 10);
100
101 if (p > USHRT_MAX)
102 return FALSE;
103
104 if (!freerdp_settings_set_uint32(settings, portID, (USHORT)p))
105 return FALSE;
106 }
107
108 return TRUE;
109}
110
111static BOOL pf_server_get_target_info(rdpContext* context, rdpSettings* settings,
112 const proxyConfig* config)
113{
114 pServerContext* ps = (pServerContext*)context;
115 proxyFetchTargetEventInfo ev = { 0 };
116
117 WINPR_ASSERT(settings);
118 WINPR_ASSERT(ps);
119 WINPR_ASSERT(ps->pdata);
120
121 ev.fetch_method = config->FixedTarget ? PROXY_FETCH_TARGET_METHOD_CONFIG
122 : PROXY_FETCH_TARGET_METHOD_LOAD_BALANCE_INFO;
123
124 if (!pf_modules_run_filter(ps->pdata->module, FILTER_TYPE_SERVER_FETCH_TARGET_ADDR, ps->pdata,
125 &ev))
126 return FALSE;
127
128 switch (ev.fetch_method)
129 {
130 case PROXY_FETCH_TARGET_METHOD_DEFAULT:
131 case PROXY_FETCH_TARGET_METHOD_LOAD_BALANCE_INFO:
132 return pf_server_parse_target_from_routing_token(
133 context, settings, FreeRDP_ServerHostname, FreeRDP_ServerPort);
134
135 case PROXY_FETCH_TARGET_METHOD_CONFIG:
136 {
137 WINPR_ASSERT(config);
138
139 if (config->TargetPort > 0)
140 {
141 if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, config->TargetPort))
142 return FALSE;
143 }
144 else
145 {
146 if (!freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, 3389))
147 return FALSE;
148 }
149
150 if (!freerdp_settings_set_uint32(settings, FreeRDP_TlsSecLevel,
151 config->TargetTlsSecLevel))
152 return FALSE;
153
154 if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, config->TargetHost))
155 {
156 PROXY_LOG_ERR(TAG, ps, "strdup failed!");
157 return FALSE;
158 }
159
160 if (config->TargetUser)
161 {
162 if (!freerdp_settings_set_string(settings, FreeRDP_Username, config->TargetUser))
163 return FALSE;
164 }
165
166 if (config->TargetDomain)
167 {
168 if (!freerdp_settings_set_string(settings, FreeRDP_Domain, config->TargetDomain))
169 return FALSE;
170 }
171
172 if (config->TargetPassword)
173 {
174 if (!freerdp_settings_set_string(settings, FreeRDP_Password,
175 config->TargetPassword))
176 return FALSE;
177 }
178
179 return TRUE;
180 }
181 case PROXY_FETCH_TARGET_USE_CUSTOM_ADDR:
182 {
183 if (!ev.target_address)
184 {
185 PROXY_LOG_ERR(TAG, ps,
186 "router: using CUSTOM_ADDR fetch method, but target_address == NULL");
187 return FALSE;
188 }
189
190 if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, ev.target_address))
191 {
192 PROXY_LOG_ERR(TAG, ps, "strdup failed!");
193 return FALSE;
194 }
195
196 free(ev.target_address);
197 return freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, ev.target_port);
198 }
199 default:
200 PROXY_LOG_ERR(TAG, ps, "unknown target fetch method: %d", ev.fetch_method);
201 return FALSE;
202 }
203
204 return TRUE;
205}
206
207static BOOL pf_server_setup_channels(freerdp_peer* peer)
208{
209 BOOL rc = FALSE;
210 char** accepted_channels = NULL;
211 size_t accepted_channels_count = 0;
212 pServerContext* ps = (pServerContext*)peer->context;
213
214 accepted_channels = WTSGetAcceptedChannelNames(peer, &accepted_channels_count);
215 if (!accepted_channels)
216 return TRUE;
217
218 for (size_t i = 0; i < accepted_channels_count; i++)
219 {
220 pServerStaticChannelContext* channelContext = NULL;
221 const char* cname = accepted_channels[i];
222 UINT16 channelId = WTSChannelGetId(peer, cname);
223
224 PROXY_LOG_INFO(TAG, ps, "Accepted channel: %s (%" PRIu16 ")", cname, channelId);
225 channelContext = StaticChannelContext_new(ps, cname, channelId);
226 if (!channelContext)
227 {
228 PROXY_LOG_ERR(TAG, ps, "error setting up channelContext for '%s'", cname);
229 goto fail;
230 }
231
232 if ((strcmp(cname, DRDYNVC_SVC_CHANNEL_NAME) == 0) &&
233 (channelContext->channelMode == PF_UTILS_CHANNEL_INTERCEPT))
234 {
235 if (!pf_channel_setup_drdynvc(ps->pdata, channelContext))
236 {
237 PROXY_LOG_ERR(TAG, ps, "error while setting up dynamic channel");
238 StaticChannelContext_free(channelContext);
239 goto fail;
240 }
241 }
242 else if (strcmp(cname, RDPDR_SVC_CHANNEL_NAME) == 0 &&
243 (channelContext->channelMode == PF_UTILS_CHANNEL_INTERCEPT))
244 {
245 if (!pf_channel_setup_rdpdr(ps, channelContext))
246 {
247 PROXY_LOG_ERR(TAG, ps, "error while setting up redirection channel");
248 StaticChannelContext_free(channelContext);
249 goto fail;
250 }
251 }
252 else
253 {
254 if (!pf_channel_setup_generic(channelContext))
255 {
256 PROXY_LOG_ERR(TAG, ps, "error while setting up generic channel");
257 StaticChannelContext_free(channelContext);
258 goto fail;
259 }
260 }
261
262 if (!HashTable_Insert(ps->channelsByFrontId, &channelContext->front_channel_id,
263 channelContext))
264 {
265 StaticChannelContext_free(channelContext);
266 PROXY_LOG_ERR(TAG, ps, "error inserting channelContext in byId table for '%s'", cname);
267 goto fail;
268 }
269 }
270
271 rc = TRUE;
272fail:
273 free((void*)accepted_channels);
274 return rc;
275}
276
277/* Event callbacks */
278
286static BOOL pf_server_post_connect(freerdp_peer* peer)
287{
288 pServerContext* ps = NULL;
289 pClientContext* pc = NULL;
290 rdpSettings* client_settings = NULL;
291 proxyData* pdata = NULL;
292 rdpSettings* frontSettings = NULL;
293
294 WINPR_ASSERT(peer);
295
296 ps = (pServerContext*)peer->context;
297 WINPR_ASSERT(ps);
298
299 frontSettings = peer->context->settings;
300 WINPR_ASSERT(frontSettings);
301
302 pdata = ps->pdata;
303 WINPR_ASSERT(pdata);
304
305 const char* ClientHostname = freerdp_settings_get_string(frontSettings, FreeRDP_ClientHostname);
306 PROXY_LOG_INFO(TAG, ps, "Accepted client: %s", ClientHostname);
307 if (!pf_server_setup_channels(peer))
308 {
309 PROXY_LOG_ERR(TAG, ps, "error setting up channels");
310 return FALSE;
311 }
312
313 pc = pf_context_create_client_context(frontSettings);
314 if (pc == NULL)
315 {
316 PROXY_LOG_ERR(TAG, ps, "failed to create client context!");
317 return FALSE;
318 }
319
320 client_settings = pc->context.settings;
321
322 /* keep both sides of the connection in pdata */
323 proxy_data_set_client_context(pdata, pc);
324
325 if (!pf_server_get_target_info(peer->context, client_settings, pdata->config))
326 {
327 PROXY_LOG_INFO(TAG, ps, "pf_server_get_target_info failed!");
328 return FALSE;
329 }
330
331 PROXY_LOG_INFO(TAG, ps, "remote target is %s:%" PRIu32 "",
332 freerdp_settings_get_string(client_settings, FreeRDP_ServerHostname),
333 freerdp_settings_get_uint32(client_settings, FreeRDP_ServerPort));
334
335 if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_POST_CONNECT, pdata, peer))
336 return FALSE;
337
338 /* Start a proxy's client in it's own thread */
339 if (!(pdata->client_thread = CreateThread(NULL, 0, pf_client_start, pc, 0, NULL)))
340 {
341 PROXY_LOG_ERR(TAG, ps, "failed to create client thread");
342 return FALSE;
343 }
344
345 return TRUE;
346}
347
348static BOOL pf_server_activate(freerdp_peer* peer)
349{
350 pServerContext* ps = NULL;
351 proxyData* pdata = NULL;
352 rdpSettings* settings = NULL;
353
354 WINPR_ASSERT(peer);
355
356 ps = (pServerContext*)peer->context;
357 WINPR_ASSERT(ps);
358
359 pdata = ps->pdata;
360 WINPR_ASSERT(pdata);
361
362 settings = peer->context->settings;
363
364 if (!freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, PACKET_COMPR_TYPE_RDP8))
365 return FALSE;
366 if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_ACTIVATE, pdata, peer))
367 return FALSE;
368
369 return TRUE;
370}
371
372static BOOL pf_server_logon(freerdp_peer* peer, const SEC_WINNT_AUTH_IDENTITY* identity,
373 BOOL automatic)
374{
375 pServerContext* ps = NULL;
376 proxyData* pdata = NULL;
377 proxyServerPeerLogon info = { 0 };
378
379 WINPR_ASSERT(peer);
380
381 ps = (pServerContext*)peer->context;
382 WINPR_ASSERT(ps);
383
384 pdata = ps->pdata;
385 WINPR_ASSERT(pdata);
386 WINPR_ASSERT(identity);
387
388 info.identity = identity;
389 info.automatic = automatic;
390 if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_SERVER_PEER_LOGON, pdata, &info))
391 return FALSE;
392 return TRUE;
393}
394
395static BOOL pf_server_adjust_monitor_layout(WINPR_ATTR_UNUSED freerdp_peer* peer)
396{
397 WINPR_ASSERT(peer);
398 /* proxy as is, there's no need to do anything here */
399 return TRUE;
400}
401
402static BOOL pf_server_receive_channel_data_hook(freerdp_peer* peer, UINT16 channelId,
403 const BYTE* data, size_t size, UINT32 flags,
404 size_t totalSize)
405{
406 UINT64 channelId64 = channelId;
407
408 WINPR_ASSERT(peer);
409
410 pServerContext* ps = (pServerContext*)peer->context;
411 WINPR_ASSERT(ps);
412
413 proxyData* pdata = ps->pdata;
414 WINPR_ASSERT(pdata);
415
416 pClientContext* pc = pdata->pc;
417
418 /*
419 * client side is not initialized yet, call original callback.
420 * this is probably a drdynvc message between peer and proxy server,
421 * which doesn't need to be proxied.
422 */
423 if (!pc)
424 goto original_cb;
425
426 const pServerStaticChannelContext* channel =
427 HashTable_GetItemValue(ps->channelsByFrontId, &channelId64);
428 if (!channel)
429 {
430 PROXY_LOG_ERR(TAG, ps, "channel id=%" PRIu64 " not registered here, dropping", channelId64);
431 return TRUE;
432 }
433
434 WINPR_ASSERT(channel->onFrontData);
435 switch (channel->onFrontData(pdata, channel, data, size, flags, totalSize))
436 {
437 case PF_CHANNEL_RESULT_PASS:
438 {
439 proxyChannelDataEventInfo ev = { 0 };
440
441 ev.channel_id = channelId;
442 ev.channel_name = channel->channel_name;
443 ev.data = data;
444 ev.data_len = size;
445 ev.flags = flags;
446 ev.total_size = totalSize;
447 return IFCALLRESULT(TRUE, pc->sendChannelData, pc, &ev);
448 }
449 case PF_CHANNEL_RESULT_DROP:
450 return TRUE;
451 case PF_CHANNEL_RESULT_ERROR:
452 default:
453 return FALSE;
454 }
455
456original_cb:
457 WINPR_ASSERT(pdata->server_receive_channel_data_original);
458 return pdata->server_receive_channel_data_original(peer, channelId, data, size, flags,
459 totalSize);
460}
461
462static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
463{
464 WINPR_ASSERT(peer);
465
466 pServerContext* ps = (pServerContext*)peer->context;
467 if (!ps)
468 return FALSE;
469
470 rdpSettings* settings = peer->context->settings;
471 WINPR_ASSERT(settings);
472
473 proxyData* pdata = proxy_data_new();
474 if (!pdata)
475 return FALSE;
476 proxyServer* server = (proxyServer*)peer->ContextExtra;
477 WINPR_ASSERT(server);
478 proxy_data_set_server_context(pdata, ps);
479
480 pdata->module = server->module;
481 const proxyConfig* config = pdata->config = server->config;
482
483 rdpPrivateKey* key = freerdp_key_new_from_pem_enc(config->PrivateKeyPEM, NULL);
484 if (!key)
485 return FALSE;
486
487 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
488 return FALSE;
489
490 rdpCertificate* cert = freerdp_certificate_new_from_pem(config->CertificatePEM);
491 if (!cert)
492 return FALSE;
493
494 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1))
495 return FALSE;
496
497 /* currently not supporting GDI orders */
498 {
499 void* OrderSupport = freerdp_settings_get_pointer_writable(settings, FreeRDP_OrderSupport);
500 ZeroMemory(OrderSupport, 32);
501 }
502
503 WINPR_ASSERT(peer->context->update);
504 peer->context->update->autoCalculateBitmapData = FALSE;
505
506 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE))
507 return FALSE;
508 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, config->GFX))
509 return FALSE;
510
511 if (pf_utils_is_passthrough(config))
512 {
513 if (!freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, TRUE))
514 return FALSE;
515 }
516
517 if (config->RemoteApp)
518 {
519 const UINT32 mask =
520 RAIL_LEVEL_SUPPORTED | RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED |
521 RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED | RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED |
522 RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED |
523 RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED | RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED |
524 RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
525 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteApplicationSupportLevel, mask))
526 return FALSE;
527 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteAppLanguageBarSupported, TRUE))
528 return FALSE;
529 }
530
531 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, config->ServerRdpSecurity))
532 return FALSE;
533 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, config->ServerTlsSecurity))
534 return FALSE;
535 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, config->ServerNlaSecurity))
536 return FALSE;
537
538 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
539 ENCRYPTION_LEVEL_CLIENT_COMPATIBLE))
540 return FALSE;
541 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32))
542 return FALSE;
543 if (!freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, TRUE))
544 return FALSE;
545 if (!freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, TRUE))
546 return FALSE;
547 if (!freerdp_settings_set_bool(settings, FreeRDP_DesktopResize, TRUE))
548 return FALSE;
549
550 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
551 0xFFFFFF)) /* FIXME */
552 return FALSE;
553
554 peer->PostConnect = pf_server_post_connect;
555 peer->Activate = pf_server_activate;
556 peer->Logon = pf_server_logon;
557 peer->AdjustMonitorsLayout = pf_server_adjust_monitor_layout;
558
559 /* virtual channels receive data hook */
560 pdata->server_receive_channel_data_original = peer->ReceiveChannelData;
561 peer->ReceiveChannelData = pf_server_receive_channel_data_hook;
562
563 if (!stream_dump_register_handlers(peer->context, CONNECTION_STATE_NEGO, TRUE))
564 return FALSE;
565 return TRUE;
566}
567
573static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
574{
575 HANDLE eventHandles[MAXIMUM_WAIT_OBJECTS] = { 0 };
576 pServerContext* ps = NULL;
577 proxyData* pdata = NULL;
578 peer_thread_args* args = arg;
579
580 WINPR_ASSERT(args);
581
582 freerdp_peer* client = args->client;
583 WINPR_ASSERT(client);
584
585 proxyServer* server = (proxyServer*)client->ContextExtra;
586 WINPR_ASSERT(server);
587
588 size_t count = ArrayList_Count(server->peer_list);
589
590 if (!pf_context_init_server_context(client))
591 goto out_free_peer;
592
593 if (!pf_server_initialize_peer_connection(client))
594 goto out_free_peer;
595
596 ps = (pServerContext*)client->context;
597 WINPR_ASSERT(ps);
598 PROXY_LOG_DBG(TAG, ps, "Added peer, %" PRIuz " connected", count);
599
600 pdata = ps->pdata;
601 WINPR_ASSERT(pdata);
602
603 if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_INITIALIZE, pdata, client))
604 goto out_free_peer;
605
606 WINPR_ASSERT(client->Initialize);
607 client->Initialize(client);
608
609 PROXY_LOG_INFO(TAG, ps, "new connection: proxy address: %s, client address: %s",
610 pdata->config->Host, client->hostname);
611
612 if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_STARTED, pdata, client))
613 goto out_free_peer;
614
615 while (1)
616 {
617 HANDLE ChannelEvent = INVALID_HANDLE_VALUE;
618 DWORD eventCount = 0;
619 {
620 WINPR_ASSERT(client->GetEventHandles);
621 const DWORD tmp = client->GetEventHandles(client, &eventHandles[eventCount],
622 ARRAYSIZE(eventHandles) - eventCount);
623
624 if (tmp == 0)
625 {
626 PROXY_LOG_ERR(TAG, ps, "Failed to get FreeRDP transport event handles");
627 break;
628 }
629
630 eventCount += tmp;
631 }
632 /* Main client event handling loop */
633 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(ps->vcm);
634
635 WINPR_ASSERT(ChannelEvent && (ChannelEvent != INVALID_HANDLE_VALUE));
636 WINPR_ASSERT(pdata->abort_event && (pdata->abort_event != INVALID_HANDLE_VALUE));
637 eventHandles[eventCount++] = ChannelEvent;
638 eventHandles[eventCount++] = pdata->abort_event;
639 eventHandles[eventCount++] = server->stopEvent;
640
641 const DWORD status = WaitForMultipleObjects(
642 eventCount, eventHandles, FALSE, 1000); /* Do periodic polling to avoid client hang */
643
644 if (status == WAIT_FAILED)
645 {
646 PROXY_LOG_ERR(TAG, ps, "WaitForMultipleObjects failed (status: %" PRIu32 ")", status);
647 break;
648 }
649
650 WINPR_ASSERT(client->CheckFileDescriptor);
651 if (client->CheckFileDescriptor(client) != TRUE)
652 break;
653
654 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
655 {
656 if (!WTSVirtualChannelManagerCheckFileDescriptor(ps->vcm))
657 {
658 PROXY_LOG_ERR(TAG, ps, "WTSVirtualChannelManagerCheckFileDescriptor failure");
659 goto fail;
660 }
661 }
662
663 /* only disconnect after checking client's and vcm's file descriptors */
664 if (proxy_data_shall_disconnect(pdata))
665 {
666 PROXY_LOG_INFO(TAG, ps, "abort event is set, closing connection with peer %s",
667 client->hostname);
668 break;
669 }
670
671 if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
672 {
673 PROXY_LOG_INFO(TAG, ps, "Server shutting down, terminating peer");
674 break;
675 }
676
677 switch (WTSVirtualChannelManagerGetDrdynvcState(ps->vcm))
678 {
679 /* Dynamic channel status may have been changed after processing */
680 case DRDYNVC_STATE_NONE:
681
682 /* Initialize drdynvc channel */
683 if (!WTSVirtualChannelManagerCheckFileDescriptor(ps->vcm))
684 {
685 PROXY_LOG_ERR(TAG, ps, "Failed to initialize drdynvc channel");
686 goto fail;
687 }
688
689 break;
690
691 case DRDYNVC_STATE_READY:
692 if (WaitForSingleObject(ps->dynvcReady, 0) == WAIT_TIMEOUT)
693 {
694 (void)SetEvent(ps->dynvcReady);
695 }
696
697 break;
698
699 default:
700 break;
701 }
702 }
703
704fail:
705
706 PROXY_LOG_INFO(TAG, ps, "starting shutdown of connection");
707 PROXY_LOG_INFO(TAG, ps, "stopping proxy's client");
708
709 /* Abort the client. */
710 proxy_data_abort_connect(pdata);
711
712 pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_END, pdata, client);
713
714 PROXY_LOG_INFO(TAG, ps, "freeing server's channels");
715
716 WINPR_ASSERT(client->Close);
717 client->Close(client);
718
719 WINPR_ASSERT(client->Disconnect);
720 client->Disconnect(client);
721
722out_free_peer:
723 PROXY_LOG_INFO(TAG, ps, "freeing proxy data");
724
725 if (pdata && pdata->client_thread)
726 {
727 proxy_data_abort_connect(pdata);
728 (void)WaitForSingleObject(pdata->client_thread, INFINITE);
729 }
730
731 {
732 ArrayList_Lock(server->peer_list);
733 ArrayList_Remove(server->peer_list, args->thread);
734 count = ArrayList_Count(server->peer_list);
735 ArrayList_Unlock(server->peer_list);
736 }
737 PROXY_LOG_DBG(TAG, ps, "Removed peer, %" PRIuz " connected", count);
738 freerdp_peer_context_free(client);
739 freerdp_peer_free(client);
740 proxy_data_free(pdata);
741
742#if defined(WITH_DEBUG_EVENTS)
743 DumpEventHandles();
744#endif
745 free(args);
746 ExitThread(0);
747 return 0;
748}
749
750static BOOL pf_server_start_peer(freerdp_peer* client)
751{
752 HANDLE hThread = NULL;
753 proxyServer* server = NULL;
754 peer_thread_args* args = calloc(1, sizeof(peer_thread_args));
755 if (!args)
756 return FALSE;
757
758 WINPR_ASSERT(client);
759 args->client = client;
760
761 server = (proxyServer*)client->ContextExtra;
762 WINPR_ASSERT(server);
763
764 hThread = CreateThread(NULL, 0, pf_server_handle_peer, args, CREATE_SUSPENDED, NULL);
765 if (!hThread)
766 return FALSE;
767
768 args->thread = hThread;
769 if (!ArrayList_Append(server->peer_list, hThread))
770 {
771 (void)CloseHandle(hThread);
772 return FALSE;
773 }
774
775 return ResumeThread(hThread) != (DWORD)-1;
776}
777
778static BOOL pf_server_peer_accepted(freerdp_listener* listener, freerdp_peer* client)
779{
780 WINPR_ASSERT(listener);
781 WINPR_ASSERT(client);
782
783 client->ContextExtra = listener->info;
784
785 return pf_server_start_peer(client);
786}
787
788BOOL pf_server_start(proxyServer* server)
789{
790 WSADATA wsaData;
791
792 WINPR_ASSERT(server);
793
794 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
795 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
796
797 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
798 goto error;
799
800 WINPR_ASSERT(server->config);
801 WINPR_ASSERT(server->listener);
802 WINPR_ASSERT(server->listener->Open);
803 if (!server->listener->Open(server->listener, server->config->Host, server->config->Port))
804 {
805 switch (errno)
806 {
807 case EADDRINUSE:
808 WLog_ERR(TAG, "failed to start listener: address already in use!");
809 break;
810 case EACCES:
811 WLog_ERR(TAG, "failed to start listener: insufficient permissions!");
812 break;
813 default:
814 WLog_ERR(TAG, "failed to start listener: errno=%d", errno);
815 break;
816 }
817
818 goto error;
819 }
820
821 return TRUE;
822
823error:
824 WSACleanup();
825 return FALSE;
826}
827
828BOOL pf_server_start_from_socket(proxyServer* server, int socket)
829{
830 WSADATA wsaData;
831
832 WINPR_ASSERT(server);
833
834 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
835 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
836
837 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
838 goto error;
839
840 WINPR_ASSERT(server->listener);
841 WINPR_ASSERT(server->listener->OpenFromSocket);
842 if (!server->listener->OpenFromSocket(server->listener, socket))
843 {
844 switch (errno)
845 {
846 case EADDRINUSE:
847 WLog_ERR(TAG, "failed to start listener: address already in use!");
848 break;
849 case EACCES:
850 WLog_ERR(TAG, "failed to start listener: insufficient permissions!");
851 break;
852 default:
853 WLog_ERR(TAG, "failed to start listener: errno=%d", errno);
854 break;
855 }
856
857 goto error;
858 }
859
860 return TRUE;
861
862error:
863 WSACleanup();
864 return FALSE;
865}
866
867BOOL pf_server_start_with_peer_socket(proxyServer* server, int peer_fd)
868{
869 struct sockaddr_storage peer_addr;
870 socklen_t len = sizeof(peer_addr);
871 freerdp_peer* client = NULL;
872
873 WINPR_ASSERT(server);
874
875 if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
876 goto fail;
877
878 client = freerdp_peer_new(peer_fd);
879 if (!client)
880 goto fail;
881
882 if (getpeername(peer_fd, (struct sockaddr*)&peer_addr, &len) != 0)
883 goto fail;
884
885 if (!freerdp_peer_set_local_and_hostname(client, &peer_addr))
886 goto fail;
887
888 client->ContextExtra = server;
889
890 if (!pf_server_start_peer(client))
891 goto fail;
892
893 return TRUE;
894
895fail:
896 WLog_ERR(TAG, "PeerAccepted callback failed");
897 freerdp_peer_free(client);
898 return FALSE;
899}
900
901static BOOL are_all_required_modules_loaded(proxyModule* module, const proxyConfig* config)
902{
903 for (size_t i = 0; i < pf_config_required_plugins_count(config); i++)
904 {
905 const char* plugin_name = pf_config_required_plugin(config, i);
906
907 if (!pf_modules_is_plugin_loaded(module, plugin_name))
908 {
909 WLog_ERR(TAG, "Required plugin '%s' is not loaded. stopping.", plugin_name);
910 return FALSE;
911 }
912 }
913
914 return TRUE;
915}
916
917static void peer_free(void* obj)
918{
919 HANDLE hdl = (HANDLE)obj;
920 (void)CloseHandle(hdl);
921}
922
923proxyServer* pf_server_new(const proxyConfig* config)
924{
925 wObject* obj = NULL;
926 proxyServer* server = NULL;
927
928 WINPR_ASSERT(config);
929
930 server = calloc(1, sizeof(proxyServer));
931 if (!server)
932 return NULL;
933
934 if (!pf_config_clone(&server->config, config))
935 goto out;
936
937 server->module = pf_modules_new(FREERDP_PROXY_PLUGINDIR, pf_config_modules(server->config),
938 pf_config_modules_count(server->config));
939 if (!server->module)
940 {
941 WLog_ERR(TAG, "failed to initialize proxy modules!");
942 goto out;
943 }
944
945 pf_modules_list_loaded_plugins(server->module);
946 if (!are_all_required_modules_loaded(server->module, server->config))
947 goto out;
948
949 server->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
950 if (!server->stopEvent)
951 goto out;
952
953 server->listener = freerdp_listener_new();
954 if (!server->listener)
955 goto out;
956
957 server->peer_list = ArrayList_New(FALSE);
958 if (!server->peer_list)
959 goto out;
960
961 obj = ArrayList_Object(server->peer_list);
962 WINPR_ASSERT(obj);
963
964 obj->fnObjectFree = peer_free;
965
966 server->listener->info = server;
967 server->listener->PeerAccepted = pf_server_peer_accepted;
968
969 if (!pf_modules_add(server->module, pf_config_plugin, (void*)server->config))
970 goto out;
971
972 return server;
973
974out:
975 WINPR_PRAGMA_DIAG_PUSH
976 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
977 pf_server_free(server);
978 WINPR_PRAGMA_DIAG_POP
979 return NULL;
980}
981
982BOOL pf_server_run(proxyServer* server)
983{
984 BOOL rc = TRUE;
985 HANDLE eventHandles[MAXIMUM_WAIT_OBJECTS] = { 0 };
986 DWORD eventCount = 0;
987 DWORD status = 0;
988 freerdp_listener* listener = NULL;
989
990 WINPR_ASSERT(server);
991
992 listener = server->listener;
993 WINPR_ASSERT(listener);
994
995 while (1)
996 {
997 WINPR_ASSERT(listener->GetEventHandles);
998 eventCount = listener->GetEventHandles(listener, eventHandles, ARRAYSIZE(eventHandles));
999
1000 if ((0 == eventCount) || (eventCount >= ARRAYSIZE(eventHandles)))
1001 {
1002 WLog_ERR(TAG, "Failed to get FreeRDP event handles");
1003 break;
1004 }
1005
1006 WINPR_ASSERT(server->stopEvent);
1007 eventHandles[eventCount++] = server->stopEvent;
1008 status = WaitForMultipleObjects(eventCount, eventHandles, FALSE, 1000);
1009
1010 if (WAIT_FAILED == status)
1011 break;
1012
1013 if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
1014 break;
1015
1016 if (WAIT_FAILED == status)
1017 {
1018 WLog_ERR(TAG, "select failed");
1019 rc = FALSE;
1020 break;
1021 }
1022
1023 WINPR_ASSERT(listener->CheckFileDescriptor);
1024 if (listener->CheckFileDescriptor(listener) != TRUE)
1025 {
1026 WLog_ERR(TAG, "Failed to accept new peer");
1027 // TODO: Set out of resource error
1028 continue;
1029 }
1030 }
1031
1032 WINPR_ASSERT(listener->Close);
1033 listener->Close(listener);
1034 return rc;
1035}
1036
1037void pf_server_stop(proxyServer* server)
1038{
1039
1040 if (!server)
1041 return;
1042
1043 /* signal main thread to stop and wait for the thread to exit */
1044 (void)SetEvent(server->stopEvent);
1045}
1046
1047void pf_server_free(proxyServer* server)
1048{
1049 if (!server)
1050 return;
1051
1052 pf_server_stop(server);
1053
1054 if (server->peer_list)
1055 {
1056 while (ArrayList_Count(server->peer_list) > 0)
1057 {
1058 /* pf_server_stop triggers the threads to shut down.
1059 * loop here until all of them stopped.
1060 *
1061 * This must be done before ArrayList_Free otherwise the thread removal
1062 * in pf_server_handle_peer will deadlock due to both threads trying to
1063 * lock the list.
1064 */
1065 Sleep(100);
1066 }
1067 }
1068 ArrayList_Free(server->peer_list);
1069 freerdp_listener_free(server->listener);
1070
1071 if (server->stopEvent)
1072 (void)CloseHandle(server->stopEvent);
1073
1074 pf_server_config_free(server->config);
1075 pf_modules_free(server->module);
1076 free(server);
1077
1078#if defined(WITH_DEBUG_EVENTS)
1079 DumpEventHandles();
1080#endif
1081}
1082
1083BOOL pf_server_add_module(proxyServer* server, proxyModuleEntryPoint ep, void* userdata)
1084{
1085 WINPR_ASSERT(server);
1086 WINPR_ASSERT(ep);
1087
1088 return pf_modules_add(server->module, ep, userdata);
1089}
FREERDP_API void pf_server_config_free(proxyConfig *config)
pf_server_config_free Releases all resources associated with proxyConfig
Definition pf_config.c:842
FREERDP_API BOOL pf_config_clone(proxyConfig **dst, const proxyConfig *config)
pf_config_clone Create a copy of the configuration
Definition pf_config.c:947
FREERDP_API size_t pf_config_required_plugins_count(const proxyConfig *config)
pf_config_required_plugins_count
Definition pf_config.c:867
FREERDP_API const char ** pf_config_modules(const proxyConfig *config)
pf_config_modules
Definition pf_config.c:888
FREERDP_API BOOL pf_config_plugin(proxyPluginsManager *plugins_manager, void *userdata)
pf_config_plugin Register a proxy plugin handling event filtering defined in the configuration.
Definition pf_config.c:1273
FREERDP_API const char * pf_config_required_plugin(const proxyConfig *config, size_t index)
pf_config_required_plugin
Definition pf_config.c:873
FREERDP_API size_t pf_config_modules_count(const proxyConfig *config)
pf_config_modules_count
Definition pf_config.c:882
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
FREERDP_API void * freerdp_settings_get_pointer_writable(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a mutable pointer settings value.
FREERDP_API BOOL freerdp_settings_set_string_len(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param, size_t len)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 param)
Sets a UINT32 settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.
This struct contains function pointer to initialize/free objects.
Definition collections.h:57