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