FreeRDP
pf_client.c
1 
24 #include <freerdp/config.h>
25 
26 #include <freerdp/freerdp.h>
27 #include <freerdp/gdi/gdi.h>
28 #include <freerdp/client/cmdline.h>
29 
30 #include <freerdp/server/proxy/proxy_log.h>
31 #include <freerdp/channels/drdynvc.h>
32 #include <freerdp/channels/encomsp.h>
33 #include <freerdp/channels/rdpdr.h>
34 #include <freerdp/channels/rdpsnd.h>
35 #include <freerdp/channels/cliprdr.h>
36 #include <freerdp/channels/channels.h>
37 
38 #include "pf_client.h"
39 #include "pf_channel.h"
40 #include <freerdp/server/proxy/proxy_context.h>
41 #include "pf_update.h"
42 #include "pf_input.h"
43 #include <freerdp/server/proxy/proxy_config.h>
44 #include "proxy_modules.h"
45 #include "pf_utils.h"
46 #include "channels/pf_channel_rdpdr.h"
47 #include "channels/pf_channel_smartcard.h"
48 
49 #define TAG PROXY_TAG("client")
50 
51 static void channel_data_free(void* obj);
52 static BOOL proxy_server_reactivate(rdpContext* ps, const rdpContext* pc)
53 {
54  WINPR_ASSERT(ps);
55  WINPR_ASSERT(pc);
56 
57  if (!pf_context_copy_settings(ps->settings, pc->settings))
58  return FALSE;
59 
60  /*
61  * DesktopResize causes internal function rdp_server_reactivate to be called,
62  * which causes the reactivation.
63  */
64  WINPR_ASSERT(ps->update);
65  if (!ps->update->DesktopResize(ps))
66  return FALSE;
67 
68  return TRUE;
69 }
70 
71 static void pf_client_on_error_info(void* ctx, const ErrorInfoEventArgs* e)
72 {
73  pClientContext* pc = (pClientContext*)ctx;
74  pServerContext* ps = NULL;
75 
76  WINPR_ASSERT(pc);
77  WINPR_ASSERT(pc->pdata);
78  WINPR_ASSERT(e);
79  ps = pc->pdata->ps;
80  WINPR_ASSERT(ps);
81 
82  if (e->code == ERRINFO_NONE)
83  return;
84 
85  PROXY_LOG_WARN(TAG, pc, "received ErrorInfo PDU. code=0x%08" PRIu32 ", message: %s", e->code,
86  freerdp_get_error_info_string(e->code));
87 
88  /* forward error back to client */
89  freerdp_set_error_info(ps->context.rdp, e->code);
90  freerdp_send_error_info(ps->context.rdp);
91 }
92 
93 static void pf_client_on_activated(void* ctx, const ActivatedEventArgs* e)
94 {
95  pClientContext* pc = (pClientContext*)ctx;
96  pServerContext* ps = NULL;
97  freerdp_peer* peer = NULL;
98 
99  WINPR_ASSERT(pc);
100  WINPR_ASSERT(pc->pdata);
101  WINPR_ASSERT(e);
102 
103  ps = pc->pdata->ps;
104  WINPR_ASSERT(ps);
105  peer = ps->context.peer;
106  WINPR_ASSERT(peer);
107  WINPR_ASSERT(peer->context);
108 
109  PROXY_LOG_INFO(TAG, pc, "client activated, registering server input callbacks");
110 
111  /* Register server input/update callbacks only after proxy client is fully activated */
112  pf_server_register_input_callbacks(peer->context->input);
113  pf_server_register_update_callbacks(peer->context->update);
114 }
115 
116 static BOOL pf_client_load_rdpsnd(pClientContext* pc)
117 {
118  rdpContext* context = (rdpContext*)pc;
119  pServerContext* ps = NULL;
120  const proxyConfig* config = NULL;
121 
122  WINPR_ASSERT(pc);
123  WINPR_ASSERT(pc->pdata);
124  ps = pc->pdata->ps;
125  WINPR_ASSERT(ps);
126  config = pc->pdata->config;
127  WINPR_ASSERT(config);
128 
129  /*
130  * if AudioOutput is enabled in proxy and client connected with rdpsnd, use proxy as rdpsnd
131  * backend. Otherwise, use sys:fake.
132  */
133  if (!freerdp_static_channel_collection_find(context->settings, RDPSND_CHANNEL_NAME))
134  {
135  const char* params[2] = { RDPSND_CHANNEL_NAME, "sys:fake" };
136 
137  if (!freerdp_client_add_static_channel(context->settings, ARRAYSIZE(params), params))
138  return FALSE;
139  }
140 
141  return TRUE;
142 }
143 
144 static BOOL pf_client_use_peer_load_balance_info(pClientContext* pc)
145 {
146  pServerContext* ps = NULL;
147  rdpSettings* settings = NULL;
148  DWORD lb_info_len = 0;
149  const char* lb_info = NULL;
150 
151  WINPR_ASSERT(pc);
152  WINPR_ASSERT(pc->pdata);
153  ps = pc->pdata->ps;
154  WINPR_ASSERT(ps);
155  settings = pc->context.settings;
156  WINPR_ASSERT(settings);
157 
158  lb_info = freerdp_nego_get_routing_token(&ps->context, &lb_info_len);
159  if (!lb_info)
160  return TRUE;
161 
162  return freerdp_settings_set_pointer_len(settings, FreeRDP_LoadBalanceInfo, lb_info,
163  lb_info_len);
164 }
165 
166 static BOOL str_is_empty(const char* str)
167 {
168  if (!str)
169  return TRUE;
170  if (strlen(str) == 0)
171  return TRUE;
172  return FALSE;
173 }
174 
175 static BOOL pf_client_use_proxy_smartcard_auth(const rdpSettings* settings)
176 {
177  BOOL enable = freerdp_settings_get_bool(settings, FreeRDP_SmartcardLogon);
178  const char* key = freerdp_settings_get_string(settings, FreeRDP_SmartcardPrivateKey);
179  const char* cert = freerdp_settings_get_string(settings, FreeRDP_SmartcardCertificate);
180 
181  if (!enable)
182  return FALSE;
183 
184  if (str_is_empty(key))
185  return FALSE;
186 
187  if (str_is_empty(cert))
188  return FALSE;
189 
190  return TRUE;
191 }
192 
193 static BOOL freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpSettings* settings,
194  const char* name, void* data)
195 {
196  PVIRTUALCHANNELENTRY entry = NULL;
197  PVIRTUALCHANNELENTRY lentry = freerdp_load_channel_addin_entry(
198  name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX);
199  PVIRTUALCHANNELENTRYEX entryEx = WINPR_FUNC_PTR_CAST(lentry, PVIRTUALCHANNELENTRYEX);
200  if (!entryEx)
201  entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC);
202 
203  if (entryEx)
204  {
205  if (freerdp_channels_client_load_ex(channels, settings, entryEx, data) == 0)
206  {
207  WLog_INFO(TAG, "loading channelEx %s", name);
208  return TRUE;
209  }
210  }
211  else if (entry)
212  {
213  if (freerdp_channels_client_load(channels, settings, entry, data) == 0)
214  {
215  WLog_INFO(TAG, "loading channel %s", name);
216  return TRUE;
217  }
218  }
219 
220  return FALSE;
221 }
222 
223 static BOOL pf_client_pre_connect(freerdp* instance)
224 {
225  pClientContext* pc = NULL;
226  pServerContext* ps = NULL;
227  const proxyConfig* config = NULL;
228  rdpSettings* settings = NULL;
229 
230  WINPR_ASSERT(instance);
231  pc = (pClientContext*)instance->context;
232  WINPR_ASSERT(pc);
233  WINPR_ASSERT(pc->pdata);
234  ps = pc->pdata->ps;
235  WINPR_ASSERT(ps);
236  WINPR_ASSERT(ps->pdata);
237  config = ps->pdata->config;
238  WINPR_ASSERT(config);
239  settings = instance->context->settings;
240  WINPR_ASSERT(settings);
241 
242  /*
243  * as the client's settings are copied from the server's, GlyphSupportLevel might not be
244  * GLYPH_SUPPORT_NONE. the proxy currently do not support GDI & GLYPH_SUPPORT_CACHE, so
245  * GlyphCacheSupport must be explicitly set to GLYPH_SUPPORT_NONE.
246  *
247  * Also, OrderSupport need to be zeroed, because it is currently not supported.
248  */
249  if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel, GLYPH_SUPPORT_NONE))
250  return FALSE;
251 
252  void* OrderSupport = freerdp_settings_get_pointer_writable(settings, FreeRDP_OrderSupport);
253  ZeroMemory(OrderSupport, 32);
254 
255  if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, DRDYNVC_SVC_CHANNEL_NAME))
256  {
257  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDynamicChannels, TRUE))
258  return FALSE;
259  }
260 
261  /* Multimon */
262  if (!freerdp_settings_set_bool(settings, FreeRDP_UseMultimon, TRUE))
263  return FALSE;
264 
265  /* Sound */
266  if (!freerdp_settings_set_bool(settings, FreeRDP_AudioCapture, config->AudioInput) ||
267  !freerdp_settings_set_bool(settings, FreeRDP_AudioPlayback, config->AudioOutput) ||
268  !freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection,
269  config->DeviceRedirection) ||
270  !freerdp_settings_set_bool(settings, FreeRDP_SupportDisplayControl,
271  config->DisplayControl) ||
272  !freerdp_settings_set_bool(settings, FreeRDP_MultiTouchInput, config->Multitouch))
273  return FALSE;
274 
275  if (config->RemoteApp)
276  {
277  if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, RAIL_SVC_CHANNEL_NAME))
278  {
279  if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteApplicationMode, TRUE))
280  return FALSE;
281  }
282  }
283 
284  if (config->DeviceRedirection)
285  {
286  if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, RDPDR_SVC_CHANNEL_NAME))
287  {
288  if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
289  return FALSE;
290  }
291  }
292 
293  /* Display control */
294  if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDisplayControl, config->DisplayControl))
295  return FALSE;
296  if (!freerdp_settings_set_bool(settings, FreeRDP_DynamicResolutionUpdate,
297  config->DisplayControl))
298  return FALSE;
299 
300  if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, ENCOMSP_SVC_CHANNEL_NAME))
301  {
302  if (!freerdp_settings_set_bool(settings, FreeRDP_EncomspVirtualChannel, TRUE))
303  return FALSE;
304  }
305 
306  if (config->Clipboard)
307  {
308  if (WTSVirtualChannelManagerIsChannelJoined(ps->vcm, CLIPRDR_SVC_CHANNEL_NAME))
309  {
310  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, config->Clipboard))
311  return FALSE;
312  }
313  }
314 
315  if (!freerdp_settings_set_bool(settings, FreeRDP_AutoReconnectionEnabled, TRUE))
316  return FALSE;
317 
318  PubSub_SubscribeErrorInfo(instance->context->pubSub, pf_client_on_error_info);
319  PubSub_SubscribeActivated(instance->context->pubSub, pf_client_on_activated);
320  if (!pf_client_use_peer_load_balance_info(pc))
321  return FALSE;
322 
323  return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_PRE_CONNECT, pc->pdata, pc);
324 }
325 
327 typedef struct
328 {
329  pServerContext* ps;
330  const char* name;
331  UINT32 backId;
332 } UpdateBackIdArgs;
333 
334 static BOOL updateBackIdFn(const void* key, void* value, void* arg)
335 {
336  pServerStaticChannelContext* current = (pServerStaticChannelContext*)value;
337  UpdateBackIdArgs* updateArgs = (UpdateBackIdArgs*)arg;
338 
339  if (strcmp(updateArgs->name, current->channel_name) != 0)
340  return TRUE;
341 
342  current->back_channel_id = updateArgs->backId;
343  if (!HashTable_Insert(updateArgs->ps->channelsByBackId, &current->back_channel_id, current))
344  {
345  WLog_ERR(TAG, "error inserting channel in channelsByBackId table");
346  }
347  return FALSE;
348 }
349 
350 static BOOL pf_client_update_back_id(pServerContext* ps, const char* name, UINT32 backId)
351 {
352  UpdateBackIdArgs res = { ps, name, backId };
353 
354  return HashTable_Foreach(ps->channelsByFrontId, updateBackIdFn, &res) == FALSE;
355 }
356 
357 static BOOL pf_client_load_channels(freerdp* instance)
358 {
359  pClientContext* pc = NULL;
360  pServerContext* ps = NULL;
361  const proxyConfig* config = NULL;
362  rdpSettings* settings = NULL;
363 
364  WINPR_ASSERT(instance);
365  pc = (pClientContext*)instance->context;
366  WINPR_ASSERT(pc);
367  WINPR_ASSERT(pc->pdata);
368  ps = pc->pdata->ps;
369  WINPR_ASSERT(ps);
370  WINPR_ASSERT(ps->pdata);
371  config = ps->pdata->config;
372  WINPR_ASSERT(config);
373  settings = instance->context->settings;
374  WINPR_ASSERT(settings);
379  PROXY_LOG_INFO(TAG, pc, "Loading addins");
380 
381  if (!pf_client_load_rdpsnd(pc))
382  {
383  PROXY_LOG_ERR(TAG, pc, "Failed to load rdpsnd client");
384  return FALSE;
385  }
386 
387  if (!pf_utils_is_passthrough(config))
388  {
389  if (!freerdp_client_load_addins(instance->context->channels, settings))
390  {
391  PROXY_LOG_ERR(TAG, pc, "Failed to load addins");
392  return FALSE;
393  }
394  }
395  else
396  {
397  if (!pf_channel_rdpdr_client_new(pc))
398  return FALSE;
399 #if defined(WITH_PROXY_EMULATE_SMARTCARD)
400  if (!pf_channel_smartcard_client_new(pc))
401  return FALSE;
402 #endif
403  /* Copy the current channel settings from the peer connection to the client. */
404  if (!freerdp_channels_from_mcs(settings, &ps->context))
405  return FALSE;
406 
407  /* Filter out channels we do not want */
408  {
409  CHANNEL_DEF* channels = (CHANNEL_DEF*)freerdp_settings_get_pointer_array_writable(
410  settings, FreeRDP_ChannelDefArray, 0);
411  UINT32 size = freerdp_settings_get_uint32(settings, FreeRDP_ChannelCount);
412  UINT32 id = MCS_GLOBAL_CHANNEL_ID + 1;
413 
414  WINPR_ASSERT(channels || (size == 0));
415 
416  UINT32 x = 0;
417  for (; x < size;)
418  {
419  CHANNEL_DEF* cur = &channels[x];
420  proxyChannelDataEventInfo dev = { 0 };
421 
422  dev.channel_name = cur->name;
423  dev.flags = cur->options;
424 
425  /* Filter out channels blocked by config */
426  if (!pf_modules_run_filter(pc->pdata->module,
427  FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_CREATE, pc->pdata,
428  &dev))
429  {
430  const size_t s = size - MIN(size, x + 1);
431  memmove(cur, &cur[1], sizeof(CHANNEL_DEF) * s);
432  size--;
433  }
434  else
435  {
436  if (!pf_client_update_back_id(ps, cur->name, id++))
437  {
438  WLog_ERR(TAG, "unable to update backid for channel %s", cur->name);
439  return FALSE;
440  }
441  x++;
442  }
443  }
444 
445  if (!freerdp_settings_set_uint32(settings, FreeRDP_ChannelCount, x))
446  return FALSE;
447  }
448  }
449  return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_LOAD_CHANNELS, pc->pdata, pc);
450 }
451 
452 static BOOL pf_client_receive_channel_data_hook(freerdp* instance, UINT16 channelId,
453  const BYTE* xdata, size_t xsize, UINT32 flags,
454  size_t totalSize)
455 {
456  pClientContext* pc = NULL;
457  pServerContext* ps = NULL;
458  proxyData* pdata = NULL;
459  pServerStaticChannelContext* channel = NULL;
460  UINT64 channelId64 = channelId;
461 
462  WINPR_ASSERT(instance);
463  WINPR_ASSERT(xdata || (xsize == 0));
464 
465  pc = (pClientContext*)instance->context;
466  WINPR_ASSERT(pc);
467  WINPR_ASSERT(pc->pdata);
468 
469  ps = pc->pdata->ps;
470  WINPR_ASSERT(ps);
471 
472  pdata = ps->pdata;
473  WINPR_ASSERT(pdata);
474 
475  channel = HashTable_GetItemValue(ps->channelsByBackId, &channelId64);
476  if (!channel)
477  return TRUE;
478 
479  WINPR_ASSERT(channel->onBackData);
480  switch (channel->onBackData(pdata, channel, xdata, xsize, flags, totalSize))
481  {
482  case PF_CHANNEL_RESULT_PASS:
483  /* Ignore messages for channels that can not be mapped.
484  * The client might not have enabled support for this specific channel,
485  * so just drop the message. */
486  if (channel->front_channel_id == 0)
487  return TRUE;
488 
489  return ps->context.peer->SendChannelPacket(ps->context.peer, channel->front_channel_id,
490  totalSize, flags, xdata, xsize);
491  case PF_CHANNEL_RESULT_DROP:
492  return TRUE;
493  case PF_CHANNEL_RESULT_ERROR:
494  default:
495  return FALSE;
496  }
497 }
498 
499 static BOOL pf_client_on_server_heartbeat(freerdp* instance, BYTE period, BYTE count1, BYTE count2)
500 {
501  pClientContext* pc = NULL;
502  pServerContext* ps = NULL;
503 
504  WINPR_ASSERT(instance);
505  pc = (pClientContext*)instance->context;
506  WINPR_ASSERT(pc);
507  WINPR_ASSERT(pc->pdata);
508  ps = pc->pdata->ps;
509  WINPR_ASSERT(ps);
510 
511  return freerdp_heartbeat_send_heartbeat_pdu(ps->context.peer, period, count1, count2);
512 }
513 
514 static BOOL pf_client_send_channel_data(pClientContext* pc, const proxyChannelDataEventInfo* ev)
515 {
516  WINPR_ASSERT(pc);
517  WINPR_ASSERT(ev);
518 
519  return Queue_Enqueue(pc->cached_server_channel_data, ev);
520 }
521 
522 static BOOL sendQueuedChannelData(pClientContext* pc)
523 {
524  BOOL rc = TRUE;
525 
526  WINPR_ASSERT(pc);
527 
528  if (pc->connected)
529  {
530  proxyChannelDataEventInfo* ev = NULL;
531 
532  Queue_Lock(pc->cached_server_channel_data);
533  while (rc && (ev = Queue_Dequeue(pc->cached_server_channel_data)))
534  {
535  UINT16 channelId = 0;
536  WINPR_ASSERT(pc->context.instance);
537 
538  channelId = freerdp_channels_get_id_by_name(pc->context.instance, ev->channel_name);
539  /* Ignore unmappable channels */
540  if ((channelId == 0) || (channelId == UINT16_MAX))
541  rc = TRUE;
542  else
543  {
544  WINPR_ASSERT(pc->context.instance->SendChannelPacket);
545  rc = pc->context.instance->SendChannelPacket(pc->context.instance, channelId,
546  ev->total_size, ev->flags, ev->data,
547  ev->data_len);
548  }
549  channel_data_free(ev);
550  }
551 
552  Queue_Unlock(pc->cached_server_channel_data);
553  }
554 
555  return rc;
556 }
557 
567 static BOOL pf_client_post_connect(freerdp* instance)
568 {
569  rdpContext* context = NULL;
570  rdpSettings* settings = NULL;
571  rdpUpdate* update = NULL;
572  rdpContext* ps = NULL;
573  pClientContext* pc = NULL;
574  const proxyConfig* config = NULL;
575 
576  WINPR_ASSERT(instance);
577  context = instance->context;
578  WINPR_ASSERT(context);
579  settings = context->settings;
580  WINPR_ASSERT(settings);
581  update = context->update;
582  WINPR_ASSERT(update);
583  pc = (pClientContext*)context;
584  WINPR_ASSERT(pc);
585  WINPR_ASSERT(pc->pdata);
586  ps = (rdpContext*)pc->pdata->ps;
587  WINPR_ASSERT(ps);
588  config = pc->pdata->config;
589  WINPR_ASSERT(config);
590 
591  if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_POST_CONNECT, pc->pdata, pc))
592  return FALSE;
593 
594  if (!gdi_init(instance, PIXEL_FORMAT_BGRA32))
595  return FALSE;
596 
597  WINPR_ASSERT(freerdp_settings_get_bool(settings, FreeRDP_SoftwareGdi));
598 
599  pf_client_register_update_callbacks(update);
600 
601  /* virtual channels receive data hook */
602  pc->client_receive_channel_data_original = instance->ReceiveChannelData;
603  instance->ReceiveChannelData = pf_client_receive_channel_data_hook;
604 
605  instance->heartbeat->ServerHeartbeat = pf_client_on_server_heartbeat;
606 
607  pc->connected = TRUE;
608 
609  /* Send cached channel data */
610  sendQueuedChannelData(pc);
611 
612  /*
613  * after the connection fully established and settings were negotiated with target server,
614  * send a reactivation sequence to the client with the negotiated settings. This way,
615  * settings are synchorinized between proxy's peer and and remote target.
616  */
617  return proxy_server_reactivate(ps, context);
618 }
619 
620 /* This function is called whether a session ends by failure or success.
621  * Clean up everything allocated by pre_connect and post_connect.
622  */
623 static void pf_client_post_disconnect(freerdp* instance)
624 {
625  pClientContext* pc = NULL;
626  proxyData* pdata = NULL;
627 
628  if (!instance)
629  return;
630 
631  if (!instance->context)
632  return;
633 
634  pc = (pClientContext*)instance->context;
635  WINPR_ASSERT(pc);
636  pdata = pc->pdata;
637  WINPR_ASSERT(pdata);
638 
639 #if defined(WITH_PROXY_EMULATE_SMARTCARD)
640  pf_channel_smartcard_client_free(pc);
641 #endif
642 
643  pf_channel_rdpdr_client_free(pc);
644 
645  pc->connected = FALSE;
646  pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_POST_DISCONNECT, pc->pdata, pc);
647 
648  PubSub_UnsubscribeErrorInfo(instance->context->pubSub, pf_client_on_error_info);
649  gdi_free(instance);
650 
651  /* Only close the connection if NLA fallback process is done */
652  if (!pc->allow_next_conn_failure)
653  proxy_data_abort_connect(pdata);
654 }
655 
656 static BOOL pf_client_redirect(freerdp* instance)
657 {
658  pClientContext* pc = NULL;
659  proxyData* pdata = NULL;
660 
661  if (!instance)
662  return FALSE;
663 
664  if (!instance->context)
665  return FALSE;
666 
667  pc = (pClientContext*)instance->context;
668  WINPR_ASSERT(pc);
669  pdata = pc->pdata;
670  WINPR_ASSERT(pdata);
671 
672 #if defined(WITH_PROXY_EMULATE_SMARTCARD)
673  pf_channel_smartcard_client_reset(pc);
674 #endif
675  pf_channel_rdpdr_client_reset(pc);
676 
677  return pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_REDIRECT, pc->pdata, pc);
678 }
679 
680 /*
681  * pf_client_should_retry_without_nla:
682  *
683  * returns TRUE if in case of connection failure, the client should try again without NLA.
684  * Otherwise, returns FALSE.
685  */
686 static BOOL pf_client_should_retry_without_nla(pClientContext* pc)
687 {
688  rdpSettings* settings = NULL;
689  const proxyConfig* config = NULL;
690 
691  WINPR_ASSERT(pc);
692  WINPR_ASSERT(pc->pdata);
693  settings = pc->context.settings;
694  WINPR_ASSERT(settings);
695  config = pc->pdata->config;
696  WINPR_ASSERT(config);
697 
698  if (!config->ClientAllowFallbackToTls ||
699  !freerdp_settings_get_bool(settings, FreeRDP_NlaSecurity))
700  return FALSE;
701 
702  return config->ClientTlsSecurity || config->ClientRdpSecurity;
703 }
704 
705 static BOOL pf_client_set_security_settings(pClientContext* pc)
706 {
707  WINPR_ASSERT(pc);
708  WINPR_ASSERT(pc->pdata);
709  rdpSettings* settings = pc->context.settings;
710  WINPR_ASSERT(settings);
711  const proxyConfig* config = pc->pdata->config;
712  WINPR_ASSERT(config);
713 
714  if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, config->ClientRdpSecurity))
715  return FALSE;
716  if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, config->ClientTlsSecurity))
717  return FALSE;
718  if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, config->ClientNlaSecurity))
719  return FALSE;
720 
721  if (pf_client_use_proxy_smartcard_auth(settings))
722  {
723  /* Smartcard authentication requires smartcard redirection to be enabled */
724  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSmartCards, TRUE))
725  return FALSE;
726 
727  /* Reset username/domain, we will get that info later from the sc cert */
728  if (!freerdp_settings_set_string(settings, FreeRDP_Username, NULL))
729  return FALSE;
730  if (!freerdp_settings_set_string(settings, FreeRDP_Domain, NULL))
731  return FALSE;
732  }
733 
734  return TRUE;
735 }
736 
737 static BOOL pf_client_connect_without_nla(pClientContext* pc)
738 {
739  freerdp* instance = NULL;
740  rdpSettings* settings = NULL;
741 
742  WINPR_ASSERT(pc);
743  instance = pc->context.instance;
744  WINPR_ASSERT(instance);
745 
746  if (!freerdp_context_reset(instance))
747  return FALSE;
748 
749  settings = pc->context.settings;
750  WINPR_ASSERT(settings);
751 
752  /* If already disabled abort early. */
753  if (!freerdp_settings_get_bool(settings, FreeRDP_NlaSecurity))
754  return FALSE;
755 
756  /* disable NLA */
757  if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
758  return FALSE;
759 
760  /* do not allow next connection failure */
761  pc->allow_next_conn_failure = FALSE;
762  return freerdp_connect(instance);
763 }
764 
765 static BOOL pf_client_connect(freerdp* instance)
766 {
767  pClientContext* pc = NULL;
768  rdpSettings* settings = NULL;
769  BOOL rc = FALSE;
770  BOOL retry = FALSE;
771 
772  WINPR_ASSERT(instance);
773  pc = (pClientContext*)instance->context;
774  WINPR_ASSERT(pc);
775  settings = instance->context->settings;
776  WINPR_ASSERT(settings);
777 
778  PROXY_LOG_INFO(TAG, pc, "connecting using client info: Username: %s, Domain: %s",
779  freerdp_settings_get_string(settings, FreeRDP_Username),
780  freerdp_settings_get_string(settings, FreeRDP_Domain));
781 
782  if (!pf_client_set_security_settings(pc))
783  return FALSE;
784 
785  if (pf_client_should_retry_without_nla(pc))
786  retry = pc->allow_next_conn_failure = TRUE;
787 
788  PROXY_LOG_INFO(TAG, pc, "connecting using security settings: rdp=%d, tls=%d, nla=%d",
789  freerdp_settings_get_bool(settings, FreeRDP_RdpSecurity),
790  freerdp_settings_get_bool(settings, FreeRDP_TlsSecurity),
791  freerdp_settings_get_bool(settings, FreeRDP_NlaSecurity));
792 
793  if (!freerdp_connect(instance))
794  {
795  if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_LOGIN_FAILURE, pc->pdata, pc))
796  goto out;
797 
798  if (!retry)
799  goto out;
800 
801  PROXY_LOG_ERR(TAG, pc, "failed to connect with NLA. retrying to connect without NLA");
802  if (!pf_client_connect_without_nla(pc))
803  {
804  PROXY_LOG_ERR(TAG, pc, "pf_client_connect_without_nla failed!");
805  goto out;
806  }
807  }
808 
809  rc = TRUE;
810 out:
811  pc->allow_next_conn_failure = FALSE;
812  return rc;
813 }
814 
820 static DWORD WINAPI pf_client_thread_proc(pClientContext* pc)
821 {
822  freerdp* instance = NULL;
823  proxyData* pdata = NULL;
824  DWORD nCount = 0;
825  DWORD status = 0;
826  HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
827 
828  WINPR_ASSERT(pc);
829 
830  instance = pc->context.instance;
831  WINPR_ASSERT(instance);
832 
833  pdata = pc->pdata;
834  WINPR_ASSERT(pdata);
835  /*
836  * during redirection, freerdp's abort event might be overriden (reset) by the library, after
837  * the server set it in order to shutdown the connection. it means that the server might signal
838  * the client to abort, but the library code will override the signal and the client will
839  * continue its work instead of exiting. That's why the client must wait on `pdata->abort_event`
840  * too, which will never be modified by the library.
841  */
842  handles[nCount++] = pdata->abort_event;
843 
844  if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_INIT_CONNECT, pdata, pc))
845  {
846  proxy_data_abort_connect(pdata);
847  goto end;
848  }
849 
850  if (!pf_client_connect(instance))
851  {
852  proxy_data_abort_connect(pdata);
853  goto end;
854  }
855  handles[nCount++] = Queue_Event(pc->cached_server_channel_data);
856 
857  while (!freerdp_shall_disconnect_context(instance->context))
858  {
859  UINT32 tmp = freerdp_get_event_handles(instance->context, &handles[nCount],
860  ARRAYSIZE(handles) - nCount);
861 
862  if (tmp == 0)
863  {
864  PROXY_LOG_ERR(TAG, pc, "freerdp_get_event_handles failed!");
865  break;
866  }
867 
868  status = WaitForMultipleObjects(nCount + tmp, handles, FALSE, INFINITE);
869 
870  if (status == WAIT_FAILED)
871  {
872  WLog_ERR(TAG, "WaitForMultipleObjects failed with %" PRIu32 "", status);
873  break;
874  }
875 
876  /* abort_event triggered */
877  if (status == WAIT_OBJECT_0)
878  break;
879 
880  if (freerdp_shall_disconnect_context(instance->context))
881  break;
882 
883  if (proxy_data_shall_disconnect(pdata))
884  break;
885 
886  if (!freerdp_check_event_handles(instance->context))
887  {
888  if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
889  WLog_ERR(TAG, "Failed to check FreeRDP event handles");
890 
891  break;
892  }
893  sendQueuedChannelData(pc);
894  }
895 
896  freerdp_disconnect(instance);
897 
898 end:
899  pf_modules_run_hook(pdata->module, HOOK_TYPE_CLIENT_UNINIT_CONNECT, pdata, pc);
900 
901  return 0;
902 }
903 
904 static int pf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
905 {
906  const char* str_data = freerdp_get_logon_error_info_data(data);
907  const char* str_type = freerdp_get_logon_error_info_type(type);
908 
909  if (!instance || !instance->context)
910  return -1;
911 
912  WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type);
913  return 1;
914 }
915 
916 static void pf_client_context_free(freerdp* instance, rdpContext* context)
917 {
918  pClientContext* pc = (pClientContext*)context;
919  WINPR_UNUSED(instance);
920 
921  if (!pc)
922  return;
923 
924  pc->sendChannelData = NULL;
925  Queue_Free(pc->cached_server_channel_data);
926  Stream_Free(pc->remote_pem, TRUE);
927  free(pc->remote_hostname);
928  free(pc->computerName.v);
929  HashTable_Free(pc->interceptContextMap);
930 }
931 
932 static int pf_client_verify_X509_certificate(freerdp* instance, const BYTE* data, size_t length,
933  const char* hostname, UINT16 port, DWORD flags)
934 {
935  pClientContext* pc = NULL;
936 
937  WINPR_ASSERT(instance);
938  WINPR_ASSERT(data);
939  WINPR_ASSERT(length > 0);
940  WINPR_ASSERT(hostname);
941 
942  pc = (pClientContext*)instance->context;
943  WINPR_ASSERT(pc);
944 
945  if (!Stream_EnsureCapacity(pc->remote_pem, length))
946  return 0;
947  Stream_SetPosition(pc->remote_pem, 0);
948 
949  free(pc->remote_hostname);
950  pc->remote_hostname = NULL;
951 
952  if (length > 0)
953  Stream_Write(pc->remote_pem, data, length);
954 
955  if (hostname)
956  pc->remote_hostname = _strdup(hostname);
957  pc->remote_port = port;
958  pc->remote_flags = flags;
959 
960  Stream_SealLength(pc->remote_pem);
961  if (!pf_modules_run_hook(pc->pdata->module, HOOK_TYPE_CLIENT_VERIFY_X509, pc->pdata, pc))
962  return 0;
963  return 1;
964 }
965 
966 void channel_data_free(void* obj)
967 {
968  union
969  {
970  const void* cpv;
971  void* pv;
972  } cnv;
973  proxyChannelDataEventInfo* dst = obj;
974  if (dst)
975  {
976  cnv.cpv = dst->data;
977  free(cnv.pv);
978 
979  cnv.cpv = dst->channel_name;
980  free(cnv.pv);
981  free(dst);
982  }
983 }
984 
985 static void* channel_data_copy(const void* obj)
986 {
987  union
988  {
989  const void* cpv;
990  void* pv;
991  } cnv;
992  const proxyChannelDataEventInfo* src = obj;
993  proxyChannelDataEventInfo* dst = NULL;
994 
995  WINPR_ASSERT(src);
996 
997  dst = calloc(1, sizeof(proxyChannelDataEventInfo));
998  if (!dst)
999  goto fail;
1000 
1001  *dst = *src;
1002  if (src->channel_name)
1003  {
1004  dst->channel_name = _strdup(src->channel_name);
1005  if (!dst->channel_name)
1006  goto fail;
1007  }
1008  dst->data = malloc(src->data_len);
1009  if (!dst->data)
1010  goto fail;
1011 
1012  cnv.cpv = dst->data;
1013  memcpy(cnv.pv, src->data, src->data_len);
1014  return dst;
1015 
1016 fail:
1017  channel_data_free(dst);
1018  return NULL;
1019 }
1020 
1021 static BOOL pf_client_client_new(freerdp* instance, rdpContext* context)
1022 {
1023  wObject* obj = NULL;
1024  pClientContext* pc = (pClientContext*)context;
1025 
1026  if (!instance || !context)
1027  return FALSE;
1028 
1029  instance->LoadChannels = pf_client_load_channels;
1030  instance->PreConnect = pf_client_pre_connect;
1031  instance->PostConnect = pf_client_post_connect;
1032  instance->PostDisconnect = pf_client_post_disconnect;
1033  instance->Redirect = pf_client_redirect;
1034  instance->LogonErrorInfo = pf_logon_error_info;
1035  instance->VerifyX509Certificate = pf_client_verify_X509_certificate;
1036 
1037  pc->remote_pem = Stream_New(NULL, 4096);
1038  if (!pc->remote_pem)
1039  return FALSE;
1040 
1041  pc->sendChannelData = pf_client_send_channel_data;
1042  pc->cached_server_channel_data = Queue_New(TRUE, -1, -1);
1043  if (!pc->cached_server_channel_data)
1044  return FALSE;
1045  obj = Queue_Object(pc->cached_server_channel_data);
1046  WINPR_ASSERT(obj);
1047  obj->fnObjectNew = channel_data_copy;
1048  obj->fnObjectFree = channel_data_free;
1049 
1050  pc->interceptContextMap = HashTable_New(FALSE);
1051  if (!pc->interceptContextMap)
1052  return FALSE;
1053 
1054  if (!HashTable_SetupForStringData(pc->interceptContextMap, FALSE))
1055  return FALSE;
1056 
1057  obj = HashTable_ValueObject(pc->interceptContextMap);
1058  WINPR_ASSERT(obj);
1059  obj->fnObjectFree = intercept_context_entry_free;
1060 
1061  return TRUE;
1062 }
1063 
1064 static int pf_client_client_stop(rdpContext* context)
1065 {
1066  pClientContext* pc = (pClientContext*)context;
1067  proxyData* pdata = NULL;
1068 
1069  WINPR_ASSERT(pc);
1070  pdata = pc->pdata;
1071  WINPR_ASSERT(pdata);
1072 
1073  PROXY_LOG_DBG(TAG, pc, "aborting client connection");
1074  proxy_data_abort_connect(pdata);
1075  freerdp_abort_connect_context(context);
1076 
1077  return 0;
1078 }
1079 
1080 int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
1081 {
1082  WINPR_ASSERT(pEntryPoints);
1083 
1084  ZeroMemory(pEntryPoints, sizeof(RDP_CLIENT_ENTRY_POINTS));
1085  pEntryPoints->Version = RDP_CLIENT_INTERFACE_VERSION;
1086  pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
1087  pEntryPoints->ContextSize = sizeof(pClientContext);
1088  /* Client init and finish */
1089  pEntryPoints->ClientNew = pf_client_client_new;
1090  pEntryPoints->ClientFree = pf_client_context_free;
1091  pEntryPoints->ClientStop = pf_client_client_stop;
1092  return 0;
1093 }
1094 
1098 DWORD WINAPI pf_client_start(LPVOID arg)
1099 {
1100  DWORD rc = 1;
1101  pClientContext* pc = (pClientContext*)arg;
1102 
1103  WINPR_ASSERT(pc);
1104  if (freerdp_client_start(&pc->context) == 0)
1105  rc = pf_client_thread_proc(pc);
1106  freerdp_client_stop(&pc->context);
1107  return rc;
1108 }
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_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean 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_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_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