FreeRDP
pf_context.c
1 
24 #include <winpr/crypto.h>
25 #include <winpr/print.h>
26 
27 #include <freerdp/server/proxy/proxy_log.h>
28 #include <freerdp/server/proxy/proxy_server.h>
29 #include <freerdp/channels/drdynvc.h>
30 
31 #include "pf_client.h"
32 #include "pf_utils.h"
33 #include "proxy_modules.h"
34 
35 #include <freerdp/server/proxy/proxy_context.h>
36 
37 #include "channels/pf_channel_rdpdr.h"
38 
39 #define TAG PROXY_TAG("server")
40 
41 static UINT32 ChannelId_Hash(const void* key)
42 {
43  const UINT32* v = (const UINT32*)key;
44  return *v;
45 }
46 
47 static BOOL ChannelId_Compare(const void* pv1, const void* pv2)
48 {
49  const UINT32* v1 = pv1;
50  const UINT32* v2 = pv2;
51  WINPR_ASSERT(v1);
52  WINPR_ASSERT(v2);
53  return (*v1 == *v2);
54 }
55 
56 static BOOL dyn_intercept(pServerContext* ps, const char* name)
57 {
58  if (strncmp(DRDYNVC_SVC_CHANNEL_NAME, name, sizeof(DRDYNVC_SVC_CHANNEL_NAME)) != 0)
59  return FALSE;
60 
61  WINPR_ASSERT(ps);
62  WINPR_ASSERT(ps->pdata);
63 
64  const proxyConfig* cfg = ps->pdata->config;
65  WINPR_ASSERT(cfg);
66  if (!cfg->GFX)
67  return TRUE;
68  if (!cfg->AudioOutput)
69  return TRUE;
70  if (!cfg->AudioInput)
71  return TRUE;
72  if (!cfg->Multitouch)
73  return TRUE;
74  if (!cfg->VideoRedirection)
75  return TRUE;
76  if (!cfg->CameraRedirection)
77  return TRUE;
78  return FALSE;
79 }
80 
81 pServerStaticChannelContext* StaticChannelContext_new(pServerContext* ps, const char* name,
82  UINT32 id)
83 {
84  pServerStaticChannelContext* ret = calloc(1, sizeof(*ret));
85  if (!ret)
86  {
87  PROXY_LOG_ERR(TAG, ps, "error allocating channel context for '%s'", name);
88  return NULL;
89  }
90 
91  ret->front_channel_id = id;
92  ret->channel_name = _strdup(name);
93  if (!ret->channel_name)
94  {
95  PROXY_LOG_ERR(TAG, ps, "error allocating name in channel context for '%s'", name);
96  free(ret);
97  return NULL;
98  }
99 
100  proxyChannelToInterceptData channel = { .name = name, .channelId = id, .intercept = FALSE };
101 
102  if (pf_modules_run_filter(ps->pdata->module, FILTER_TYPE_STATIC_INTERCEPT_LIST, ps->pdata,
103  &channel) &&
104  channel.intercept)
105  ret->channelMode = PF_UTILS_CHANNEL_INTERCEPT;
106  else if (dyn_intercept(ps, name))
107  ret->channelMode = PF_UTILS_CHANNEL_INTERCEPT;
108  else
109  ret->channelMode = pf_utils_get_channel_mode(ps->pdata->config, name);
110  return ret;
111 }
112 
113 void StaticChannelContext_free(pServerStaticChannelContext* ctx)
114 {
115  if (!ctx)
116  return;
117 
118  IFCALL(ctx->contextDtor, ctx->context);
119 
120  free(ctx->channel_name);
121  free(ctx);
122 }
123 
124 static void HashStaticChannelContext_free(void* ptr)
125 {
126  pServerStaticChannelContext* ctx = (pServerStaticChannelContext*)ptr;
127  StaticChannelContext_free(ctx);
128 }
129 
130 /* Proxy context initialization callback */
131 static void client_to_proxy_context_free(freerdp_peer* client, rdpContext* ctx);
132 static BOOL client_to_proxy_context_new(freerdp_peer* client, rdpContext* ctx)
133 {
134  wObject* obj = NULL;
135  pServerContext* context = (pServerContext*)ctx;
136 
137  WINPR_ASSERT(client);
138  WINPR_ASSERT(context);
139 
140  context->dynvcReady = NULL;
141 
142  context->vcm = WTSOpenServerA((LPSTR)client->context);
143 
144  if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
145  goto error;
146 
147  if (!(context->dynvcReady = CreateEvent(NULL, TRUE, FALSE, NULL)))
148  goto error;
149 
150  context->interceptContextMap = HashTable_New(FALSE);
151  if (!context->interceptContextMap)
152  goto error;
153  if (!HashTable_SetupForStringData(context->interceptContextMap, FALSE))
154  goto error;
155  obj = HashTable_ValueObject(context->interceptContextMap);
156  WINPR_ASSERT(obj);
157  obj->fnObjectFree = intercept_context_entry_free;
158 
159  /* channels by ids */
160  context->channelsByFrontId = HashTable_New(FALSE);
161  if (!context->channelsByFrontId)
162  goto error;
163  if (!HashTable_SetHashFunction(context->channelsByFrontId, ChannelId_Hash))
164  goto error;
165 
166  obj = HashTable_KeyObject(context->channelsByFrontId);
167  obj->fnObjectEquals = ChannelId_Compare;
168 
169  obj = HashTable_ValueObject(context->channelsByFrontId);
170  obj->fnObjectFree = HashStaticChannelContext_free;
171 
172  context->channelsByBackId = HashTable_New(FALSE);
173  if (!context->channelsByBackId)
174  goto error;
175  if (!HashTable_SetHashFunction(context->channelsByBackId, ChannelId_Hash))
176  goto error;
177 
178  obj = HashTable_KeyObject(context->channelsByBackId);
179  obj->fnObjectEquals = ChannelId_Compare;
180 
181  return TRUE;
182 
183 error:
184  client_to_proxy_context_free(client, ctx);
185 
186  return FALSE;
187 }
188 
189 /* Proxy context free callback */
190 void client_to_proxy_context_free(freerdp_peer* client, rdpContext* ctx)
191 {
192  pServerContext* context = (pServerContext*)ctx;
193 
194  WINPR_UNUSED(client);
195 
196  if (!context)
197  return;
198 
199  if (context->dynvcReady)
200  {
201  (void)CloseHandle(context->dynvcReady);
202  context->dynvcReady = NULL;
203  }
204 
205  HashTable_Free(context->interceptContextMap);
206  HashTable_Free(context->channelsByFrontId);
207  HashTable_Free(context->channelsByBackId);
208 
209  if (context->vcm && (context->vcm != INVALID_HANDLE_VALUE))
210  WTSCloseServer(context->vcm);
211  context->vcm = NULL;
212 }
213 
214 BOOL pf_context_init_server_context(freerdp_peer* client)
215 {
216  WINPR_ASSERT(client);
217 
218  client->ContextSize = sizeof(pServerContext);
219  client->ContextNew = client_to_proxy_context_new;
220  client->ContextFree = client_to_proxy_context_free;
221 
222  return freerdp_peer_context_new(client);
223 }
224 
225 static BOOL pf_context_revert_str_settings(rdpSettings* dst, const rdpSettings* before, size_t nr,
226  const FreeRDP_Settings_Keys_String* ids)
227 {
228  WINPR_ASSERT(dst);
229  WINPR_ASSERT(before);
230  WINPR_ASSERT(ids || (nr == 0));
231 
232  for (size_t x = 0; x < nr; x++)
233  {
234  FreeRDP_Settings_Keys_String id = ids[x];
235  const char* what = freerdp_settings_get_string(before, id);
236  if (!freerdp_settings_set_string(dst, id, what))
237  return FALSE;
238  }
239 
240  return TRUE;
241 }
242 
243 void intercept_context_entry_free(void* obj)
244 {
245  InterceptContextMapEntry* entry = obj;
246  if (!entry)
247  return;
248  if (!entry->free)
249  return;
250  entry->free(entry);
251 }
252 
253 BOOL pf_context_copy_settings(rdpSettings* dst, const rdpSettings* src)
254 {
255  BOOL rc = FALSE;
256  rdpSettings* before_copy = NULL;
257  const FreeRDP_Settings_Keys_String to_revert[] = { FreeRDP_ConfigPath,
258  FreeRDP_CertificateName };
259 
260  if (!dst || !src)
261  return FALSE;
262 
263  before_copy = freerdp_settings_clone(dst);
264  if (!before_copy)
265  return FALSE;
266 
267  if (!freerdp_settings_copy(dst, src))
268  goto out_fail;
269 
270  /* keep original ServerMode value */
271  if (!freerdp_settings_copy_item(dst, before_copy, FreeRDP_ServerMode))
272  goto out_fail;
273 
274  /* revert some values that must not be changed */
275  if (!pf_context_revert_str_settings(dst, before_copy, ARRAYSIZE(to_revert), to_revert))
276  goto out_fail;
277 
278  if (!freerdp_settings_get_bool(dst, FreeRDP_ServerMode))
279  {
280  /* adjust instance pointer */
281  if (!freerdp_settings_copy_item(dst, before_copy, FreeRDP_instance))
282  goto out_fail;
283 
284  /*
285  * RdpServerRsaKey must be set to NULL if `dst` is client's context
286  * it must be freed before setting it to NULL to avoid a memory leak!
287  */
288 
289  if (!freerdp_settings_set_pointer_len(dst, FreeRDP_RdpServerRsaKey, NULL, 1))
290  goto out_fail;
291  }
292 
293  /* We handle certificate management for this client ourselfes. */
294  rc = freerdp_settings_set_bool(dst, FreeRDP_ExternalCertificateManagement, TRUE);
295 
296 out_fail:
297  freerdp_settings_free(before_copy);
298  return rc;
299 }
300 
301 pClientContext* pf_context_create_client_context(const rdpSettings* clientSettings)
302 {
303  RDP_CLIENT_ENTRY_POINTS clientEntryPoints;
304  pClientContext* pc = NULL;
305  rdpContext* context = NULL;
306 
307  WINPR_ASSERT(clientSettings);
308 
309  RdpClientEntry(&clientEntryPoints);
310  context = freerdp_client_context_new(&clientEntryPoints);
311 
312  if (!context)
313  return NULL;
314 
315  pc = (pClientContext*)context;
316 
317  if (!pf_context_copy_settings(context->settings, clientSettings))
318  goto error;
319 
320  return pc;
321 error:
322  freerdp_client_context_free(context);
323  return NULL;
324 }
325 
326 proxyData* proxy_data_new(void)
327 {
328  BYTE temp[16];
329  char* hex = NULL;
330  proxyData* pdata = NULL;
331 
332  pdata = calloc(1, sizeof(proxyData));
333  if (!pdata)
334  return NULL;
335 
336  if (!(pdata->abort_event = CreateEvent(NULL, TRUE, FALSE, NULL)))
337  goto error;
338 
339  if (!(pdata->gfx_server_ready = CreateEvent(NULL, TRUE, FALSE, NULL)))
340  goto error;
341 
342  winpr_RAND(&temp, 16);
343  hex = winpr_BinToHexString(temp, 16, FALSE);
344  if (!hex)
345  goto error;
346 
347  CopyMemory(pdata->session_id, hex, PROXY_SESSION_ID_LENGTH);
348  pdata->session_id[PROXY_SESSION_ID_LENGTH] = '\0';
349  free(hex);
350 
351  if (!(pdata->modules_info = HashTable_New(FALSE)))
352  goto error;
353 
354  /* modules_info maps between plugin name to custom data */
355  if (!HashTable_SetupForStringData(pdata->modules_info, FALSE))
356  goto error;
357 
358  return pdata;
359 error:
360  WINPR_PRAGMA_DIAG_PUSH
361  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
362  proxy_data_free(pdata);
363  WINPR_PRAGMA_DIAG_POP
364  return NULL;
365 }
366 
367 /* updates circular pointers between proxyData and pClientContext instances */
368 void proxy_data_set_client_context(proxyData* pdata, pClientContext* context)
369 {
370  WINPR_ASSERT(pdata);
371  WINPR_ASSERT(context);
372  pdata->pc = context;
373  context->pdata = pdata;
374 }
375 
376 /* updates circular pointers between proxyData and pServerContext instances */
377 void proxy_data_set_server_context(proxyData* pdata, pServerContext* context)
378 {
379  WINPR_ASSERT(pdata);
380  WINPR_ASSERT(context);
381  pdata->ps = context;
382  context->pdata = pdata;
383 }
384 
385 void proxy_data_free(proxyData* pdata)
386 {
387  if (!pdata)
388  return;
389 
390  if (pdata->abort_event)
391  (void)CloseHandle(pdata->abort_event);
392 
393  if (pdata->client_thread)
394  (void)CloseHandle(pdata->client_thread);
395 
396  if (pdata->gfx_server_ready)
397  (void)CloseHandle(pdata->gfx_server_ready);
398 
399  if (pdata->modules_info)
400  HashTable_Free(pdata->modules_info);
401 
402  if (pdata->pc)
403  freerdp_client_context_free(&pdata->pc->context);
404 
405  free(pdata);
406 }
407 
408 void proxy_data_abort_connect(proxyData* pdata)
409 {
410  WINPR_ASSERT(pdata);
411  WINPR_ASSERT(pdata->abort_event);
412  (void)SetEvent(pdata->abort_event);
413  if (pdata->pc)
414  freerdp_abort_connect_context(&pdata->pc->context);
415 }
416 
417 BOOL proxy_data_shall_disconnect(proxyData* pdata)
418 {
419  WINPR_ASSERT(pdata);
420  WINPR_ASSERT(pdata->abort_event);
421  return WaitForSingleObject(pdata->abort_event, 0) == WAIT_OBJECT_0;
422 }
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_copy_item(rdpSettings *dst, const rdpSettings *src, SSIZE_T id)
copies one setting identified by id from src to dst
Definition: settings_str.c:429
FREERDP_API void freerdp_settings_free(rdpSettings *settings)
Free a settings struct with all data in it.
FREERDP_API BOOL freerdp_settings_copy(rdpSettings *dst, const rdpSettings *src)
Deep copies settings from src to dst.
FREERDP_API rdpSettings * freerdp_settings_clone(const rdpSettings *settings)
Creates a deep copy of settings.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57