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