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