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