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
41static UINT32 ChannelId_Hash(const void* key)
42{
43 const UINT32* v = (const UINT32*)key;
44 return *v;
45}
46
47static 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
56static 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
81pServerStaticChannelContext* 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
113void 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
124static void HashStaticChannelContext_free(void* ptr)
125{
126 pServerStaticChannelContext* ctx = (pServerStaticChannelContext*)ptr;
127 StaticChannelContext_free(ctx);
128}
129
130/* Proxy context initialization callback */
131static void client_to_proxy_context_free(freerdp_peer* client, rdpContext* ctx);
132static 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
183error:
184 client_to_proxy_context_free(client, ctx);
185
186 return FALSE;
187}
188
189/* Proxy context free callback */
190void 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
214BOOL 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
225static 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
243void 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
253BOOL 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 ourselves. */
294 rc = freerdp_settings_set_bool(dst, FreeRDP_ExternalCertificateManagement, TRUE);
295
296out_fail:
297 freerdp_settings_free(before_copy);
298 return rc;
299}
300
301pClientContext* 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;
321error:
322 freerdp_client_context_free(context);
323 return NULL;
324}
325
326proxyData* 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;
359error:
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 */
368void 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 */
377void 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
385void 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
408void 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
417BOOL 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 rdpSettings * freerdp_settings_clone(const rdpSettings *settings)
Creates a deep copy of settings.
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
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 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_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