FreeRDP
Loading...
Searching...
No Matches
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 {
427 const pServerStaticChannelContext* channel =
428 HashTable_GetItemValue(ps->channelsByFrontId, &channelId64);
429 if (!channel)
430 {
431 PROXY_LOG_ERR(TAG, ps, "channel id=%" PRIu64 " not registered here, dropping",
432 channelId64);
433 return TRUE;
434 }
435
436 WINPR_ASSERT(channel->onFrontData);
437 switch (channel->onFrontData(pdata, channel, data, size, flags, totalSize))
438 {
439 case PF_CHANNEL_RESULT_PASS:
440 {
441 proxyChannelDataEventInfo ev = { 0 };
442
443 ev.channel_id = channelId;
444 ev.channel_name = channel->channel_name;
445 ev.data = data;
446 ev.data_len = size;
447 ev.flags = flags;
448 ev.total_size = totalSize;
449 return IFCALLRESULT(TRUE, pc->sendChannelData, pc, &ev);
450 }
451 case PF_CHANNEL_RESULT_DROP:
452 return TRUE;
453 case PF_CHANNEL_RESULT_ERROR:
454 default:
455 return FALSE;
456 }
457 }
458original_cb:
459 WINPR_ASSERT(pdata->server_receive_channel_data_original);
460 return pdata->server_receive_channel_data_original(peer, channelId, data, size, flags,
461 totalSize);
462}
463
464static BOOL pf_server_initialize_peer_connection(freerdp_peer* peer)
465{
466 WINPR_ASSERT(peer);
467
468 pServerContext* ps = (pServerContext*)peer->context;
469 if (!ps)
470 return FALSE;
471
472 rdpSettings* settings = peer->context->settings;
473 WINPR_ASSERT(settings);
474
475 proxyData* pdata = proxy_data_new();
476 if (!pdata)
477 return FALSE;
478 proxyServer* server = (proxyServer*)peer->ContextExtra;
479 WINPR_ASSERT(server);
480 proxy_data_set_server_context(pdata, ps);
481
482 pdata->module = server->module;
483 const proxyConfig* config = pdata->config = server->config;
484
485 rdpPrivateKey* key = freerdp_key_new_from_pem_enc(config->PrivateKeyPEM, NULL);
486 if (!key)
487 return FALSE;
488
489 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerRsaKey, key, 1))
490 return FALSE;
491
492 rdpCertificate* cert = freerdp_certificate_new_from_pem(config->CertificatePEM);
493 if (!cert)
494 return FALSE;
495
496 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RdpServerCertificate, cert, 1))
497 return FALSE;
498
499 /* currently not supporting GDI orders */
500 {
501 void* OrderSupport = freerdp_settings_get_pointer_writable(settings, FreeRDP_OrderSupport);
502 ZeroMemory(OrderSupport, 32);
503 }
504
505 WINPR_ASSERT(peer->context->update);
506 peer->context->update->autoCalculateBitmapData = FALSE;
507
508 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE))
509 return FALSE;
510 if (!freerdp_settings_set_bool(settings, FreeRDP_SupportGraphicsPipeline, config->GFX))
511 return FALSE;
512
513 if (pf_utils_is_passthrough(config))
514 {
515 if (!freerdp_settings_set_bool(settings, FreeRDP_DeactivateClientDecoding, TRUE))
516 return FALSE;
517 }
518
519 if (config->RemoteApp)
520 {
521 const UINT32 mask =
522 RAIL_LEVEL_SUPPORTED | RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED |
523 RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED | RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED |
524 RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED |
525 RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED | RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED |
526 RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
527 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteApplicationSupportLevel, mask))
528 return FALSE;
529 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteAppLanguageBarSupported, TRUE))
530 return FALSE;
531 }
532
533 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, config->ServerRdpSecurity))
534 return FALSE;
535 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, config->ServerTlsSecurity))
536 return FALSE;
537 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, config->ServerNlaSecurity))
538 return FALSE;
539
540 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
541 ENCRYPTION_LEVEL_CLIENT_COMPATIBLE))
542 return FALSE;
543 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32))
544 return FALSE;
545 if (!freerdp_settings_set_bool(settings, FreeRDP_SuppressOutput, TRUE))
546 return FALSE;
547 if (!freerdp_settings_set_bool(settings, FreeRDP_RefreshRect, TRUE))
548 return FALSE;
549 if (!freerdp_settings_set_bool(settings, FreeRDP_DesktopResize, TRUE))
550 return FALSE;
551
552 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
553 0xFFFFFF)) /* FIXME */
554 return FALSE;
555
556 peer->PostConnect = pf_server_post_connect;
557 peer->Activate = pf_server_activate;
558 peer->Logon = pf_server_logon;
559 peer->AdjustMonitorsLayout = pf_server_adjust_monitor_layout;
560
561 /* virtual channels receive data hook */
562 pdata->server_receive_channel_data_original = peer->ReceiveChannelData;
563 peer->ReceiveChannelData = pf_server_receive_channel_data_hook;
564
565 if (!stream_dump_register_handlers(peer->context, CONNECTION_STATE_NEGO, TRUE))
566 return FALSE;
567 return TRUE;
568}
569
575static DWORD WINAPI pf_server_handle_peer(LPVOID arg)
576{
577 HANDLE eventHandles[MAXIMUM_WAIT_OBJECTS] = { 0 };
578 pServerContext* ps = NULL;
579 proxyData* pdata = NULL;
580 peer_thread_args* args = arg;
581
582 WINPR_ASSERT(args);
583
584 freerdp_peer* client = args->client;
585 WINPR_ASSERT(client);
586
587 proxyServer* server = (proxyServer*)client->ContextExtra;
588 WINPR_ASSERT(server);
589
590 ArrayList_Lock(server->peer_list);
591 size_t count = ArrayList_Count(server->peer_list);
592 ArrayList_Unlock(server->peer_list);
593
594 if (!pf_context_init_server_context(client))
595 goto out_free_peer;
596
597 if (!pf_server_initialize_peer_connection(client))
598 goto out_free_peer;
599
600 ps = (pServerContext*)client->context;
601 WINPR_ASSERT(ps);
602 PROXY_LOG_DBG(TAG, ps, "Added peer, %" PRIuz " connected", count);
603
604 pdata = ps->pdata;
605 WINPR_ASSERT(pdata);
606
607 if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_INITIALIZE, pdata, client))
608 goto out_free_peer;
609
610 WINPR_ASSERT(client->Initialize);
611 client->Initialize(client);
612
613 PROXY_LOG_INFO(TAG, ps, "new connection: proxy address: %s, client address: %s",
614 pdata->config->Host, client->hostname);
615
616 if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_STARTED, pdata, client))
617 goto out_free_peer;
618
619 while (1)
620 {
621 HANDLE ChannelEvent = INVALID_HANDLE_VALUE;
622 DWORD eventCount = 0;
623 {
624 WINPR_ASSERT(client->GetEventHandles);
625 const DWORD tmp = client->GetEventHandles(client, &eventHandles[eventCount],
626 ARRAYSIZE(eventHandles) - eventCount);
627
628 if (tmp == 0)
629 {
630 PROXY_LOG_ERR(TAG, ps, "Failed to get FreeRDP transport event handles");
631 break;
632 }
633
634 eventCount += tmp;
635 }
636 /* Main client event handling loop */
637 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(ps->vcm);
638
639 WINPR_ASSERT(ChannelEvent && (ChannelEvent != INVALID_HANDLE_VALUE));
640 WINPR_ASSERT(pdata->abort_event && (pdata->abort_event != INVALID_HANDLE_VALUE));
641 eventHandles[eventCount++] = ChannelEvent;
642 eventHandles[eventCount++] = pdata->abort_event;
643 eventHandles[eventCount++] = server->stopEvent;
644
645 const DWORD status = WaitForMultipleObjects(
646 eventCount, eventHandles, FALSE, 1000); /* Do periodic polling to avoid client hang */
647
648 if (status == WAIT_FAILED)
649 {
650 PROXY_LOG_ERR(TAG, ps, "WaitForMultipleObjects failed (status: %" PRIu32 ")", status);
651 break;
652 }
653
654 WINPR_ASSERT(client->CheckFileDescriptor);
655 if (client->CheckFileDescriptor(client) != TRUE)
656 break;
657
658 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
659 {
660 if (!WTSVirtualChannelManagerCheckFileDescriptor(ps->vcm))
661 {
662 PROXY_LOG_ERR(TAG, ps, "WTSVirtualChannelManagerCheckFileDescriptor failure");
663 goto fail;
664 }
665 }
666
667 /* only disconnect after checking client's and vcm's file descriptors */
668 if (proxy_data_shall_disconnect(pdata))
669 {
670 PROXY_LOG_INFO(TAG, ps, "abort event is set, closing connection with peer %s",
671 client->hostname);
672 break;
673 }
674
675 if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
676 {
677 PROXY_LOG_INFO(TAG, ps, "Server shutting down, terminating peer");
678 break;
679 }
680
681 switch (WTSVirtualChannelManagerGetDrdynvcState(ps->vcm))
682 {
683 /* Dynamic channel status may have been changed after processing */
684 case DRDYNVC_STATE_NONE:
685
686 /* Initialize drdynvc channel */
687 if (!WTSVirtualChannelManagerCheckFileDescriptor(ps->vcm))
688 {
689 PROXY_LOG_ERR(TAG, ps, "Failed to initialize drdynvc channel");
690 goto fail;
691 }
692
693 break;
694
695 case DRDYNVC_STATE_READY:
696 if (WaitForSingleObject(ps->dynvcReady, 0) == WAIT_TIMEOUT)
697 {
698 (void)SetEvent(ps->dynvcReady);
699 }
700
701 break;
702
703 default:
704 break;
705 }
706 }
707
708fail:
709
710 PROXY_LOG_INFO(TAG, ps, "starting shutdown of connection");
711 PROXY_LOG_INFO(TAG, ps, "stopping proxy's client");
712
713 /* Abort the client. */
714 proxy_data_abort_connect(pdata);
715
716 pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_END, pdata, client);
717
718 PROXY_LOG_INFO(TAG, ps, "freeing server's channels");
719
720 WINPR_ASSERT(client->Close);
721 client->Close(client);
722
723 WINPR_ASSERT(client->Disconnect);
724 client->Disconnect(client);
725
726out_free_peer:
727 PROXY_LOG_INFO(TAG, ps, "freeing proxy data");
728
729 if (pdata && pdata->client_thread)
730 {
731 proxy_data_abort_connect(pdata);
732 (void)WaitForSingleObject(pdata->client_thread, INFINITE);
733 }
734
735 {
736 ArrayList_Lock(server->peer_list);
737 ArrayList_Remove(server->peer_list, args->thread);
738 count = ArrayList_Count(server->peer_list);
739 ArrayList_Unlock(server->peer_list);
740 }
741 PROXY_LOG_DBG(TAG, ps, "Removed peer, %" PRIuz " connected", count);
742 freerdp_peer_context_free(client);
743 freerdp_peer_free(client);
744 proxy_data_free(pdata);
745
746#if defined(WITH_DEBUG_EVENTS)
747 DumpEventHandles();
748#endif
749 free(args);
750 ExitThread(0);
751 return 0;
752}
753
754static BOOL pf_server_start_peer(freerdp_peer* client)
755{
756 HANDLE hThread = NULL;
757 proxyServer* server = NULL;
758 peer_thread_args* args = calloc(1, sizeof(peer_thread_args));
759 if (!args)
760 return FALSE;
761
762 WINPR_ASSERT(client);
763 args->client = client;
764
765 server = (proxyServer*)client->ContextExtra;
766 WINPR_ASSERT(server);
767
768 hThread = CreateThread(NULL, 0, pf_server_handle_peer, args, CREATE_SUSPENDED, NULL);
769 if (!hThread)
770 {
771 free(args);
772 return FALSE;
773 }
774
775 args->thread = hThread;
776 ArrayList_Lock(server->peer_list);
777 const BOOL appended = ArrayList_Append(server->peer_list, hThread);
778 ArrayList_Unlock(server->peer_list);
779 if (!appended)
780 {
781 (void)CloseHandle(hThread);
782 free(args);
783 return FALSE;
784 }
785
786 return ResumeThread(hThread) != (DWORD)-1;
787}
788
789static BOOL pf_server_peer_accepted(freerdp_listener* listener, freerdp_peer* client)
790{
791 WINPR_ASSERT(listener);
792 WINPR_ASSERT(client);
793
794 client->ContextExtra = listener->info;
795
796 return pf_server_start_peer(client);
797}
798
799BOOL pf_server_start(proxyServer* server)
800{
801 WSADATA wsaData;
802
803 WINPR_ASSERT(server);
804
805 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
806 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
807
808 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
809 goto error;
810
811 WINPR_ASSERT(server->config);
812 WINPR_ASSERT(server->listener);
813 WINPR_ASSERT(server->listener->Open);
814 if (!server->listener->Open(server->listener, server->config->Host, server->config->Port))
815 {
816 switch (errno)
817 {
818 case EADDRINUSE:
819 WLog_ERR(TAG, "failed to start listener: address already in use!");
820 break;
821 case EACCES:
822 WLog_ERR(TAG, "failed to start listener: insufficient permissions!");
823 break;
824 default:
825 WLog_ERR(TAG, "failed to start listener: errno=%d", errno);
826 break;
827 }
828
829 goto error;
830 }
831
832 return TRUE;
833
834error:
835 WSACleanup();
836 return FALSE;
837}
838
839BOOL pf_server_start_from_socket(proxyServer* server, int socket)
840{
841 WSADATA wsaData;
842
843 WINPR_ASSERT(server);
844
845 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
846 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
847
848 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
849 goto error;
850
851 WINPR_ASSERT(server->listener);
852 WINPR_ASSERT(server->listener->OpenFromSocket);
853 if (!server->listener->OpenFromSocket(server->listener, socket))
854 {
855 switch (errno)
856 {
857 case EADDRINUSE:
858 WLog_ERR(TAG, "failed to start listener: address already in use!");
859 break;
860 case EACCES:
861 WLog_ERR(TAG, "failed to start listener: insufficient permissions!");
862 break;
863 default:
864 WLog_ERR(TAG, "failed to start listener: errno=%d", errno);
865 break;
866 }
867
868 goto error;
869 }
870
871 return TRUE;
872
873error:
874 WSACleanup();
875 return FALSE;
876}
877
878BOOL pf_server_start_with_peer_socket(proxyServer* server, int peer_fd)
879{
880 struct sockaddr_storage peer_addr;
881 socklen_t len = sizeof(peer_addr);
882 freerdp_peer* client = NULL;
883
884 WINPR_ASSERT(server);
885
886 if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
887 goto fail;
888
889 client = freerdp_peer_new(peer_fd);
890 if (!client)
891 goto fail;
892
893 if (getpeername(peer_fd, (struct sockaddr*)&peer_addr, &len) != 0)
894 goto fail;
895
896 if (!freerdp_peer_set_local_and_hostname(client, &peer_addr))
897 goto fail;
898
899 client->ContextExtra = server;
900
901 if (!pf_server_start_peer(client))
902 goto fail;
903
904 return TRUE;
905
906fail:
907 WLog_ERR(TAG, "PeerAccepted callback failed");
908 freerdp_peer_free(client);
909 return FALSE;
910}
911
912static BOOL are_all_required_modules_loaded(proxyModule* module, const proxyConfig* config)
913{
914 for (size_t i = 0; i < pf_config_required_plugins_count(config); i++)
915 {
916 const char* plugin_name = pf_config_required_plugin(config, i);
917
918 if (!pf_modules_is_plugin_loaded(module, plugin_name))
919 {
920 WLog_ERR(TAG, "Required plugin '%s' is not loaded. stopping.", plugin_name);
921 return FALSE;
922 }
923 }
924
925 return TRUE;
926}
927
928static void peer_free(void* obj)
929{
930 HANDLE hdl = (HANDLE)obj;
931 (void)CloseHandle(hdl);
932}
933
934proxyServer* pf_server_new(const proxyConfig* config)
935{
936 wObject* obj = NULL;
937 proxyServer* server = NULL;
938
939 WINPR_ASSERT(config);
940
941 server = calloc(1, sizeof(proxyServer));
942 if (!server)
943 return NULL;
944
945 if (!pf_config_clone(&server->config, config))
946 goto out;
947
948 server->module = pf_modules_new(FREERDP_PROXY_PLUGINDIR, pf_config_modules(server->config),
949 pf_config_modules_count(server->config));
950 if (!server->module)
951 {
952 WLog_ERR(TAG, "failed to initialize proxy modules!");
953 goto out;
954 }
955
956 pf_modules_list_loaded_plugins(server->module);
957 if (!are_all_required_modules_loaded(server->module, server->config))
958 goto out;
959
960 server->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
961 if (!server->stopEvent)
962 goto out;
963
964 server->listener = freerdp_listener_new();
965 if (!server->listener)
966 goto out;
967
968 server->peer_list = ArrayList_New(FALSE);
969 if (!server->peer_list)
970 goto out;
971
972 obj = ArrayList_Object(server->peer_list);
973 WINPR_ASSERT(obj);
974
975 obj->fnObjectFree = peer_free;
976
977 server->listener->info = server;
978 server->listener->PeerAccepted = pf_server_peer_accepted;
979
980 if (!pf_modules_add(server->module, pf_config_plugin, (void*)server->config))
981 goto out;
982
983 return server;
984
985out:
986 WINPR_PRAGMA_DIAG_PUSH
987 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
988 pf_server_free(server);
989 WINPR_PRAGMA_DIAG_POP
990 return NULL;
991}
992
993BOOL pf_server_run(proxyServer* server)
994{
995 BOOL rc = TRUE;
996 HANDLE eventHandles[MAXIMUM_WAIT_OBJECTS] = { 0 };
997 DWORD eventCount = 0;
998 DWORD status = 0;
999 freerdp_listener* listener = NULL;
1000
1001 WINPR_ASSERT(server);
1002
1003 listener = server->listener;
1004 WINPR_ASSERT(listener);
1005
1006 while (1)
1007 {
1008 WINPR_ASSERT(listener->GetEventHandles);
1009 eventCount = listener->GetEventHandles(listener, eventHandles, ARRAYSIZE(eventHandles));
1010
1011 if ((0 == eventCount) || (eventCount >= ARRAYSIZE(eventHandles)))
1012 {
1013 WLog_ERR(TAG, "Failed to get FreeRDP event handles");
1014 break;
1015 }
1016
1017 WINPR_ASSERT(server->stopEvent);
1018 eventHandles[eventCount++] = server->stopEvent;
1019 status = WaitForMultipleObjects(eventCount, eventHandles, FALSE, 1000);
1020
1021 if (WAIT_FAILED == status)
1022 break;
1023
1024 if (WaitForSingleObject(server->stopEvent, 0) == WAIT_OBJECT_0)
1025 break;
1026
1027 if (WAIT_FAILED == status)
1028 {
1029 WLog_ERR(TAG, "select failed");
1030 rc = FALSE;
1031 break;
1032 }
1033
1034 WINPR_ASSERT(listener->CheckFileDescriptor);
1035 if (listener->CheckFileDescriptor(listener) != TRUE)
1036 {
1037 WLog_ERR(TAG, "Failed to accept new peer");
1038 // TODO: Set out of resource error
1039 continue;
1040 }
1041 }
1042
1043 WINPR_ASSERT(listener->Close);
1044 listener->Close(listener);
1045 return rc;
1046}
1047
1048void pf_server_stop(proxyServer* server)
1049{
1050
1051 if (!server)
1052 return;
1053
1054 /* signal main thread to stop and wait for the thread to exit */
1055 (void)SetEvent(server->stopEvent);
1056}
1057
1058void pf_server_free(proxyServer* server)
1059{
1060 if (!server)
1061 return;
1062
1063 pf_server_stop(server);
1064
1065 if (server->peer_list)
1066 {
1067 while (ArrayList_Count(server->peer_list) > 0)
1068 {
1069 /* pf_server_stop triggers the threads to shut down.
1070 * loop here until all of them stopped.
1071 *
1072 * This must be done before ArrayList_Free otherwise the thread removal
1073 * in pf_server_handle_peer will deadlock due to both threads trying to
1074 * lock the list.
1075 */
1076 Sleep(100);
1077 }
1078 }
1079 ArrayList_Free(server->peer_list);
1080 freerdp_listener_free(server->listener);
1081
1082 if (server->stopEvent)
1083 (void)CloseHandle(server->stopEvent);
1084
1085 pf_server_config_free(server->config);
1086 pf_modules_free(server->module);
1087 free(server);
1088
1089#if defined(WITH_DEBUG_EVENTS)
1090 DumpEventHandles();
1091#endif
1092}
1093
1094BOOL pf_server_add_module(proxyServer* server, proxyModuleEntryPoint ep, void* userdata)
1095{
1096 WINPR_ASSERT(server);
1097 WINPR_ASSERT(ep);
1098
1099 return pf_modules_add(server->module, ep, userdata);
1100}
FREERDP_API void pf_server_config_free(proxyConfig *config)
pf_server_config_free Releases all resources associated with proxyConfig
Definition pf_config.c:862
FREERDP_API BOOL pf_config_clone(proxyConfig **dst, const proxyConfig *config)
pf_config_clone Create a copy of the configuration
Definition pf_config.c:968
FREERDP_API size_t pf_config_required_plugins_count(const proxyConfig *config)
pf_config_required_plugins_count
Definition pf_config.c:888
FREERDP_API const char ** pf_config_modules(const proxyConfig *config)
pf_config_modules
Definition pf_config.c:909
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:1294
FREERDP_API const char * pf_config_required_plugin(const proxyConfig *config, size_t index)
pf_config_required_plugin
Definition pf_config.c:894
FREERDP_API size_t pf_config_modules_count(const proxyConfig *config)
pf_config_modules_count
Definition pf_config.c:903
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