FreeRDP
Loading...
Searching...
No Matches
pf_channel_rdpdr.c
1
21#include <freerdp/config.h>
22
23#include <winpr/assert.h>
24#include <winpr/cast.h>
25#include <winpr/string.h>
26#include <winpr/print.h>
27
28#include "../pf_client.h"
29#include "../pf_server.h"
30#include "pf_channel_rdpdr.h"
31#include "pf_channel_smartcard.h"
32
33#include <freerdp/server/proxy/proxy_log.h>
34#include <freerdp/channels/rdpdr.h>
35#include <freerdp/channels/channels.h>
36#include <freerdp/utils/rdpdr_utils.h>
37
38#define RTAG PROXY_TAG("channel.rdpdr")
39
40#define SCARD_DEVICE_ID UINT32_MAX
41
42typedef struct
43{
45 wStream* s;
46 wStream* buffer;
47 UINT16 versionMajor;
48 UINT16 versionMinor;
49 UINT32 clientID;
50 UINT32 computerNameLen;
51 BOOL computerNameUnicode;
52 union
53 {
54 WCHAR* wc;
55 char* c;
56 void* v;
57 } computerName;
58 UINT32 SpecialDeviceCount;
59 UINT32 capabilityVersions[6];
60 size_t totalLength;
61} pf_channel_common_context;
62
63typedef enum
64{
65 STATE_CLIENT_EXPECT_SERVER_ANNOUNCE_REQUEST = 0x01,
66 STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST = 0x02,
67 STATE_CLIENT_EXPECT_SERVER_CLIENT_ID_CONFIRM = 0x04,
68 STATE_CLIENT_CHANNEL_RUNNING = 0x10
69} pf_channel_client_state;
70
71typedef struct
72{
73 pf_channel_common_context common;
74 pf_channel_client_state state;
75 UINT32 flags;
76 UINT16 maxMajorVersion;
77 UINT16 maxMinorVersion;
78 wQueue* queue;
79 wLog* log;
80} pf_channel_client_context;
81
82typedef enum
83{
84 STATE_SERVER_INITIAL,
85 STATE_SERVER_EXPECT_CLIENT_ANNOUNCE_REPLY,
86 STATE_SERVER_EXPECT_CLIENT_NAME_REQUEST,
87 STATE_SERVER_EXPECT_EXPECT_CLIENT_CAPABILITY_RESPONE,
88 STATE_SERVER_CHANNEL_RUNNING
89} pf_channel_server_state;
90
91typedef struct
92{
93 pf_channel_common_context common;
94 pf_channel_server_state state;
95 DWORD SessionId;
96 HANDLE handle;
97 wArrayList* blockedDevices;
98 wLog* log;
99} pf_channel_server_context;
100
101#define proxy_client "[proxy<-->client]"
102#define proxy_server "[proxy<-->server]"
103
104#define proxy_client_rx proxy_client " receive"
105#define proxy_client_tx proxy_client " send"
106#define proxy_server_rx proxy_server " receive"
107#define proxy_server_tx proxy_server " send"
108
109#define SERVER_RX_LOG(log, lvl, fmt, ...) WLog_Print(log, lvl, proxy_client_rx fmt, ##__VA_ARGS__)
110#define CLIENT_RX_LOG(log, lvl, fmt, ...) WLog_Print(log, lvl, proxy_server_rx fmt, ##__VA_ARGS__)
111#define SERVER_TX_LOG(log, lvl, fmt, ...) WLog_Print(log, lvl, proxy_client_tx fmt, ##__VA_ARGS__)
112#define CLIENT_TX_LOG(log, lvl, fmt, ...) WLog_Print(log, lvl, proxy_server_tx fmt, ##__VA_ARGS__)
113#define RX_LOG(srv, lvl, fmt, ...) \
114 do \
115 { \
116 if (srv) \
117 { \
118 SERVER_RX_LOG(lvl, fmt, ##__VA_ARGS__); \
119 } \
120 else \
121 { \
122 CLIENT_RX_LOG(lvl, fmt, ##__VA_ARGS__); \
123 } \
124 } while (0)
125
126#define SERVER_RXTX_LOG(send, log, lvl, fmt, ...) \
127 do \
128 { \
129 if (send) \
130 { \
131 SERVER_TX_LOG(log, lvl, fmt, ##__VA_ARGS__); \
132 } \
133 else \
134 { \
135 SERVER_RX_LOG(log, lvl, fmt, ##__VA_ARGS__); \
136 } \
137 } while (0)
138
139#define Stream_CheckAndLogRequiredLengthSrv(log, s, len) \
140 Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, len, 1, \
141 proxy_client_rx " %s(%s:%" PRIuz ")", __func__, \
142 __FILE__, (size_t)__LINE__)
143#define Stream_CheckAndLogRequiredLengthClient(log, s, len) \
144 Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, len, 1, \
145 proxy_server_rx " %s(%s:%" PRIuz ")", __func__, \
146 __FILE__, (size_t)__LINE__)
147#define Stream_CheckAndLogRequiredLengthRx(srv, log, s, len) \
148 Stream_CheckAndLogRequiredLengthRx_(srv, log, s, len, 1, __func__, __FILE__, __LINE__)
149WINPR_ATTR_NODISCARD
150static BOOL Stream_CheckAndLogRequiredLengthRx_(BOOL srv, wLog* log, wStream* s, size_t nmemb,
151 size_t size, const char* fkt, const char* file,
152 size_t line)
153{
154 const char* fmt =
155 srv ? proxy_server_rx " %s(%s:%" PRIuz ")" : proxy_client_rx " %s(%s:%" PRIuz ")";
156
157 return Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, nmemb, size, fmt, fkt, file,
158 line);
159}
160
161WINPR_ATTR_NODISCARD
162static const char* rdpdr_server_state_to_string(pf_channel_server_state state)
163{
164 switch (state)
165 {
166 case STATE_SERVER_INITIAL:
167 return "STATE_SERVER_INITIAL";
168 case STATE_SERVER_EXPECT_CLIENT_ANNOUNCE_REPLY:
169 return "STATE_SERVER_EXPECT_CLIENT_ANNOUNCE_REPLY";
170 case STATE_SERVER_EXPECT_CLIENT_NAME_REQUEST:
171 return "STATE_SERVER_EXPECT_CLIENT_NAME_REQUEST";
172 case STATE_SERVER_EXPECT_EXPECT_CLIENT_CAPABILITY_RESPONE:
173 return "STATE_SERVER_EXPECT_EXPECT_CLIENT_CAPABILITY_RESPONE";
174 case STATE_SERVER_CHANNEL_RUNNING:
175 return "STATE_SERVER_CHANNEL_RUNNING";
176 default:
177 return "STATE_SERVER_UNKNOWN";
178 }
179}
180
181WINPR_ATTR_NODISCARD
182static const char* rdpdr_client_state_to_string(pf_channel_client_state state)
183{
184 switch (state)
185 {
186 case STATE_CLIENT_EXPECT_SERVER_ANNOUNCE_REQUEST:
187 return "STATE_CLIENT_EXPECT_SERVER_ANNOUNCE_REQUEST";
188 case STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST:
189 return "STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST";
190 case STATE_CLIENT_EXPECT_SERVER_CLIENT_ID_CONFIRM:
191 return "STATE_CLIENT_EXPECT_SERVER_CLIENT_ID_CONFIRM";
192 case STATE_CLIENT_CHANNEL_RUNNING:
193 return "STATE_CLIENT_CHANNEL_RUNNING";
194 default:
195 return "STATE_CLIENT_UNKNOWN";
196 }
197}
198
199WINPR_ATTR_NODISCARD
200static wStream* rdpdr_get_send_buffer(pf_channel_common_context* rdpdr, UINT16 component,
201 UINT16 PacketID, size_t capacity)
202{
203 WINPR_ASSERT(rdpdr);
204 WINPR_ASSERT(rdpdr->s);
205 Stream_ResetPosition(rdpdr->s);
206
207 if (!Stream_EnsureCapacity(rdpdr->s, capacity + 4))
208 return nullptr;
209 Stream_Write_UINT16(rdpdr->s, component);
210 Stream_Write_UINT16(rdpdr->s, PacketID);
211 return rdpdr->s;
212}
213
214WINPR_ATTR_NODISCARD
215static wStream* rdpdr_client_get_send_buffer(pf_channel_client_context* rdpdr, UINT16 component,
216 UINT16 PacketID, size_t capacity)
217{
218 WINPR_ASSERT(rdpdr);
219 return rdpdr_get_send_buffer(&rdpdr->common, component, PacketID, capacity);
220}
221
222WINPR_ATTR_NODISCARD
223static wStream* rdpdr_server_get_send_buffer(pf_channel_server_context* rdpdr, UINT16 component,
224 UINT16 PacketID, size_t capacity)
225{
226 WINPR_ASSERT(rdpdr);
227 return rdpdr_get_send_buffer(&rdpdr->common, component, PacketID, capacity);
228}
229
230WINPR_ATTR_NODISCARD
231static UINT rdpdr_client_send(wLog* log, pClientContext* pc, wStream* s)
232{
233 UINT16 channelId = 0;
234
235 WINPR_ASSERT(log);
236 WINPR_ASSERT(pc);
237 WINPR_ASSERT(s);
238 WINPR_ASSERT(pc->cctx.context.instance);
239
240 if (!pc->connected)
241 {
242 CLIENT_TX_LOG(log, WLOG_WARN, "Ignoring channel %s message, not connected!",
243 RDPDR_SVC_CHANNEL_NAME);
244 return CHANNEL_RC_OK;
245 }
246
247 channelId = freerdp_channels_get_id_by_name(pc->cctx.context.instance, RDPDR_SVC_CHANNEL_NAME);
248 /* Ignore unmappable channels. Might happen when the channel was already down and
249 * some delayed message is tried to be sent. */
250 if ((channelId == 0) || (channelId == UINT16_MAX))
251 return ERROR_INTERNAL_ERROR;
252
253 Stream_SealLength(s);
254 rdpdr_dump_send_packet(log, WLOG_TRACE, s, proxy_server_tx);
255 WINPR_ASSERT(pc->cctx.context.instance->SendChannelData);
256 if (!pc->cctx.context.instance->SendChannelData(pc->cctx.context.instance, channelId,
257 Stream_Buffer(s), Stream_Length(s)))
258 return ERROR_EVT_CHANNEL_NOT_FOUND;
259 return CHANNEL_RC_OK;
260}
261
262WINPR_ATTR_NODISCARD
263static UINT rdpdr_seal_send_free_request(pf_channel_server_context* context, wStream* s)
264{
265 BOOL status = 0;
266 size_t len = 0;
267
268 WINPR_ASSERT(context);
269 WINPR_ASSERT(context->handle);
270 WINPR_ASSERT(s);
271
272 Stream_SealLength(s);
273 len = Stream_Length(s);
274 WINPR_ASSERT(len <= UINT32_MAX);
275
276 rdpdr_dump_send_packet(context->log, WLOG_TRACE, s, proxy_client_tx);
277 status = WTSVirtualChannelWrite(context->handle, Stream_BufferAs(s, char), (ULONG)len, nullptr);
278 return (status) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
279}
280
281WINPR_ATTR_NODISCARD
282static BOOL rdpdr_process_server_header(BOOL server, wLog* log, wStream* s, UINT16 component,
283 UINT16 PacketId, size_t expect)
284{
285 UINT16 rpacketid = 0;
286 UINT16 rcomponent = 0;
287
288 WINPR_ASSERT(s);
289 if (!Stream_CheckAndLogRequiredLengthRx(server, log, s, 4))
290 {
291 RX_LOG(server, log, WLOG_WARN, "RDPDR_HEADER[%s | %s]: expected length 4, got %" PRIuz,
292 rdpdr_component_string(component), rdpdr_packetid_string(PacketId),
293 Stream_GetRemainingLength(s));
294 return FALSE;
295 }
296
297 Stream_Read_UINT16(s, rcomponent);
298 Stream_Read_UINT16(s, rpacketid);
299
300 if (rcomponent != component)
301 {
302 RX_LOG(server, log, WLOG_WARN, "RDPDR_HEADER[%s | %s]: got component %s",
303 rdpdr_component_string(component), rdpdr_packetid_string(PacketId),
304 rdpdr_component_string(rcomponent));
305 return FALSE;
306 }
307
308 if (rpacketid != PacketId)
309 {
310 RX_LOG(server, log, WLOG_WARN, "RDPDR_HEADER[%s | %s]: got PacketID %s",
311 rdpdr_component_string(component), rdpdr_packetid_string(PacketId),
312 rdpdr_packetid_string(rpacketid));
313 return FALSE;
314 }
315
316 if (!Stream_CheckAndLogRequiredLengthRx(server, log, s, expect))
317 {
318 RX_LOG(server, log, WLOG_WARN,
319 "RDPDR_HEADER[%s | %s] not enough data, expected %" PRIuz ", "
320 "got %" PRIuz,
321 rdpdr_component_string(component), rdpdr_packetid_string(PacketId), expect,
322 Stream_GetRemainingLength(s));
323 return ERROR_INVALID_DATA;
324 }
325
326 return TRUE;
327}
328
329WINPR_ATTR_NODISCARD
330static BOOL rdpdr_check_version(BOOL server, wLog* log, UINT16 versionMajor, UINT16 versionMinor,
331 UINT16 component, UINT16 PacketId)
332{
333 if (versionMajor != RDPDR_VERSION_MAJOR)
334 {
335 RX_LOG(server, log, WLOG_WARN, "[%s | %s] expected MajorVersion %d, got %" PRIu16,
336 rdpdr_component_string(component), rdpdr_packetid_string(PacketId),
337 RDPDR_VERSION_MAJOR, versionMajor);
338 return FALSE;
339 }
340 switch (versionMinor)
341 {
342 case RDPDR_VERSION_MINOR_RDP50:
343 case RDPDR_VERSION_MINOR_RDP51:
344 case RDPDR_VERSION_MINOR_RDP52:
345 case RDPDR_VERSION_MINOR_RDP6X:
346 case RDPDR_VERSION_MINOR_RDP10X:
347 break;
348 default:
349 {
350 RX_LOG(server, log, WLOG_WARN, "[%s | %s] unsupported MinorVersion %" PRIu16,
351 rdpdr_component_string(component), rdpdr_packetid_string(PacketId),
352 versionMinor);
353 return FALSE;
354 }
355 }
356 return TRUE;
357}
358
359WINPR_ATTR_NODISCARD
360static UINT rdpdr_process_server_announce_request(pf_channel_client_context* rdpdr, wStream* s)
361{
362 const UINT16 component = RDPDR_CTYP_CORE;
363 const UINT16 packetid = PAKID_CORE_SERVER_ANNOUNCE;
364 WINPR_ASSERT(rdpdr);
365 WINPR_ASSERT(s);
366
367 if (!rdpdr_process_server_header(FALSE, rdpdr->log, s, component, packetid, 8))
368 return ERROR_INVALID_DATA;
369
370 Stream_Read_UINT16(s, rdpdr->common.versionMajor);
371 Stream_Read_UINT16(s, rdpdr->common.versionMinor);
372
373 if (!rdpdr_check_version(FALSE, rdpdr->log, rdpdr->common.versionMajor,
374 rdpdr->common.versionMinor, component, packetid))
375 return ERROR_INVALID_DATA;
376
377 /* Limit maximum channel protocol version to the one set by proxy server */
378 if (rdpdr->common.versionMajor > rdpdr->maxMajorVersion)
379 {
380 rdpdr->common.versionMajor = rdpdr->maxMajorVersion;
381 rdpdr->common.versionMinor = rdpdr->maxMinorVersion;
382 }
383 else if (rdpdr->common.versionMinor > rdpdr->maxMinorVersion)
384 rdpdr->common.versionMinor = rdpdr->maxMinorVersion;
385
386 Stream_Read_UINT32(s, rdpdr->common.clientID);
387 return CHANNEL_RC_OK;
388}
389
390WINPR_ATTR_NODISCARD
391static UINT rdpdr_server_send_announce_request(pf_channel_server_context* context)
392{
393 wStream* s =
394 rdpdr_server_get_send_buffer(context, RDPDR_CTYP_CORE, PAKID_CORE_SERVER_ANNOUNCE, 8);
395 if (!s)
396 return CHANNEL_RC_NO_MEMORY;
397
398 Stream_Write_UINT16(s, context->common.versionMajor); /* VersionMajor (2 bytes) */
399 Stream_Write_UINT16(s, context->common.versionMinor); /* VersionMinor (2 bytes) */
400 Stream_Write_UINT32(s, context->common.clientID); /* ClientId (4 bytes) */
401 return rdpdr_seal_send_free_request(context, s);
402}
403
404WINPR_ATTR_NODISCARD
405static UINT rdpdr_process_client_announce_reply(pf_channel_server_context* rdpdr, wStream* s)
406{
407 const UINT16 component = RDPDR_CTYP_CORE;
408 const UINT16 packetid = PAKID_CORE_CLIENTID_CONFIRM;
409 UINT16 versionMajor = 0;
410 UINT16 versionMinor = 0;
411 UINT32 clientID = 0;
412
413 WINPR_ASSERT(rdpdr);
414 WINPR_ASSERT(s);
415
416 if (!rdpdr_process_server_header(TRUE, rdpdr->log, s, component, packetid, 8))
417 return ERROR_INVALID_DATA;
418
419 Stream_Read_UINT16(s, versionMajor);
420 Stream_Read_UINT16(s, versionMinor);
421
422 if (!rdpdr_check_version(TRUE, rdpdr->log, versionMajor, versionMinor, component, packetid))
423 return ERROR_INVALID_DATA;
424
425 if ((rdpdr->common.versionMajor != versionMajor) ||
426 (rdpdr->common.versionMinor != versionMinor))
427 {
428 SERVER_RX_LOG(
429 rdpdr->log, WLOG_WARN,
430 "[%s | %s] downgrading version from %" PRIu16 ".%" PRIu16 " to %" PRIu16 ".%" PRIu16,
431 rdpdr_component_string(component), rdpdr_packetid_string(packetid),
432 rdpdr->common.versionMajor, rdpdr->common.versionMinor, versionMajor, versionMinor);
433 rdpdr->common.versionMajor = versionMajor;
434 rdpdr->common.versionMinor = versionMinor;
435 }
436 Stream_Read_UINT32(s, clientID);
437 if (rdpdr->common.clientID != clientID)
438 {
439 SERVER_RX_LOG(rdpdr->log, WLOG_WARN,
440 "[%s | %s] changing clientID 0x%08" PRIu32 " to 0x%08" PRIu32,
441 rdpdr_component_string(component), rdpdr_packetid_string(packetid),
442 rdpdr->common.clientID, clientID);
443 rdpdr->common.clientID = clientID;
444 }
445
446 return CHANNEL_RC_OK;
447}
448
449WINPR_ATTR_NODISCARD
450static UINT rdpdr_send_client_announce_reply(pClientContext* pc, pf_channel_client_context* rdpdr)
451{
452 wStream* s =
453 rdpdr_client_get_send_buffer(rdpdr, RDPDR_CTYP_CORE, PAKID_CORE_CLIENTID_CONFIRM, 8);
454 if (!s)
455 return CHANNEL_RC_NO_MEMORY;
456
457 Stream_Write_UINT16(s, rdpdr->common.versionMajor);
458 Stream_Write_UINT16(s, rdpdr->common.versionMinor);
459 Stream_Write_UINT32(s, rdpdr->common.clientID);
460 return rdpdr_client_send(rdpdr->log, pc, s);
461}
462
463WINPR_ATTR_NODISCARD
464static UINT rdpdr_process_client_name_request(pf_channel_server_context* rdpdr, wStream* s,
465 pClientContext* pc)
466{
467 UINT32 unicodeFlag = 0;
468 UINT32 codePage = 0;
469
470 WINPR_ASSERT(rdpdr);
471 WINPR_ASSERT(s);
472 WINPR_ASSERT(pc);
473
474 if (!rdpdr_process_server_header(TRUE, rdpdr->log, s, RDPDR_CTYP_CORE, PAKID_CORE_CLIENT_NAME,
475 12))
476 return ERROR_INVALID_DATA;
477
478 Stream_Read_UINT32(s, unicodeFlag);
479 rdpdr->common.computerNameUnicode = ((unicodeFlag & 1) != 0);
480
481 Stream_Read_UINT32(s, codePage);
482 WINPR_UNUSED(codePage); /* Field is ignored */
483 Stream_Read_UINT32(s, rdpdr->common.computerNameLen);
484 if (!Stream_CheckAndLogRequiredLengthSrv(rdpdr->log, s, rdpdr->common.computerNameLen))
485 {
486 SERVER_RX_LOG(
487 rdpdr->log, WLOG_WARN, "[%s | %s]: missing data, got %" PRIuz ", expected %" PRIu32,
488 rdpdr_component_string(RDPDR_CTYP_CORE), rdpdr_packetid_string(PAKID_CORE_CLIENT_NAME),
489 Stream_GetRemainingLength(s), rdpdr->common.computerNameLen);
490 return ERROR_INVALID_DATA;
491 }
492 void* tmp = realloc(rdpdr->common.computerName.v, rdpdr->common.computerNameLen);
493 if (!tmp)
494 return CHANNEL_RC_NO_MEMORY;
495 rdpdr->common.computerName.v = tmp;
496
497 Stream_Read(s, rdpdr->common.computerName.v, rdpdr->common.computerNameLen);
498
499 pc->computerNameLen = rdpdr->common.computerNameLen;
500 pc->computerNameUnicode = rdpdr->common.computerNameUnicode;
501 tmp = realloc(pc->computerName.v, pc->computerNameLen);
502 if (!tmp)
503 return CHANNEL_RC_NO_MEMORY;
504 pc->computerName.v = tmp;
505 memcpy(pc->computerName.v, rdpdr->common.computerName.v, pc->computerNameLen);
506
507 return CHANNEL_RC_OK;
508}
509
510WINPR_ATTR_NODISCARD
511static UINT rdpdr_send_client_name_request(pClientContext* pc, pf_channel_client_context* rdpdr)
512{
513 wStream* s = nullptr;
514
515 WINPR_ASSERT(rdpdr);
516 WINPR_ASSERT(pc);
517
518 {
519 void* tmp = realloc(rdpdr->common.computerName.v, pc->computerNameLen);
520 if (!tmp)
521 return CHANNEL_RC_NO_MEMORY;
522 rdpdr->common.computerName.v = tmp;
523 rdpdr->common.computerNameLen = pc->computerNameLen;
524 rdpdr->common.computerNameUnicode = pc->computerNameUnicode;
525 memcpy(rdpdr->common.computerName.v, pc->computerName.v, pc->computerNameLen);
526 }
527 s = rdpdr_client_get_send_buffer(rdpdr, RDPDR_CTYP_CORE, PAKID_CORE_CLIENT_NAME,
528 12U + rdpdr->common.computerNameLen);
529 if (!s)
530 return CHANNEL_RC_NO_MEMORY;
531
532 Stream_Write_UINT32(s, rdpdr->common.computerNameUnicode
533 ? 1
534 : 0); /* unicodeFlag, 0 for ASCII and 1 for Unicode */
535 Stream_Write_UINT32(s, 0); /* codePage, must be set to zero */
536 Stream_Write_UINT32(s, rdpdr->common.computerNameLen);
537 Stream_Write(s, rdpdr->common.computerName.v, rdpdr->common.computerNameLen);
538 return rdpdr_client_send(rdpdr->log, pc, s);
539}
540
541#define rdpdr_ignore_capset(srv, log, s, header) \
542 rdpdr_ignore_capset_((srv), (log), (s), header, __func__)
543WINPR_ATTR_NODISCARD
544static UINT rdpdr_ignore_capset_(WINPR_ATTR_UNUSED BOOL srv, WINPR_ATTR_UNUSED wLog* log,
545 wStream* s, const RDPDR_CAPABILITY_HEADER* header,
546 WINPR_ATTR_UNUSED const char* fkt)
547{
548 WINPR_ASSERT(s);
549 WINPR_ASSERT(header);
550
551 Stream_Seek(s, header->CapabilityLength);
552 return CHANNEL_RC_OK;
553}
554
555WINPR_ATTR_NODISCARD
556static UINT rdpdr_client_process_general_capset(pf_channel_client_context* rdpdr, wStream* s,
557 const RDPDR_CAPABILITY_HEADER* header)
558{
559 WINPR_UNUSED(rdpdr);
560 return rdpdr_ignore_capset(FALSE, rdpdr->log, s, header);
561}
562
563WINPR_ATTR_NODISCARD
564static UINT rdpdr_process_printer_capset(pf_channel_client_context* rdpdr, wStream* s,
565 const RDPDR_CAPABILITY_HEADER* header)
566{
567 WINPR_UNUSED(rdpdr);
568 return rdpdr_ignore_capset(FALSE, rdpdr->log, s, header);
569}
570
571WINPR_ATTR_NODISCARD
572static UINT rdpdr_process_port_capset(pf_channel_client_context* rdpdr, wStream* s,
573 const RDPDR_CAPABILITY_HEADER* header)
574{
575 WINPR_UNUSED(rdpdr);
576 return rdpdr_ignore_capset(FALSE, rdpdr->log, s, header);
577}
578
579WINPR_ATTR_NODISCARD
580static UINT rdpdr_process_drive_capset(pf_channel_client_context* rdpdr, wStream* s,
581 const RDPDR_CAPABILITY_HEADER* header)
582{
583 WINPR_UNUSED(rdpdr);
584 return rdpdr_ignore_capset(FALSE, rdpdr->log, s, header);
585}
586
587WINPR_ATTR_NODISCARD
588static UINT rdpdr_process_smartcard_capset(pf_channel_client_context* rdpdr, wStream* s,
589 const RDPDR_CAPABILITY_HEADER* header)
590{
591 WINPR_UNUSED(rdpdr);
592 return rdpdr_ignore_capset(FALSE, rdpdr->log, s, header);
593}
594
595WINPR_ATTR_NODISCARD
596static UINT rdpdr_process_server_core_capability_request(pf_channel_client_context* rdpdr,
597 wStream* s)
598{
599 UINT status = CHANNEL_RC_OK;
600 UINT16 numCapabilities = 0;
601
602 WINPR_ASSERT(rdpdr);
603
604 if (!rdpdr_process_server_header(FALSE, rdpdr->log, s, RDPDR_CTYP_CORE,
605 PAKID_CORE_SERVER_CAPABILITY, 4))
606 return ERROR_INVALID_DATA;
607
608 Stream_Read_UINT16(s, numCapabilities);
609 Stream_Seek(s, 2); /* pad (2 bytes) */
610
611 for (UINT16 i = 0; i < numCapabilities; i++)
612 {
613 RDPDR_CAPABILITY_HEADER header = WINPR_C_ARRAY_INIT;
614 UINT error = rdpdr_read_capset_header(rdpdr->log, s, &header);
615 if (error != CHANNEL_RC_OK)
616 return error;
617
618 if (header.CapabilityType < ARRAYSIZE(rdpdr->common.capabilityVersions))
619 {
620 if (rdpdr->common.capabilityVersions[header.CapabilityType] > header.Version)
621 rdpdr->common.capabilityVersions[header.CapabilityType] = header.Version;
622
623 WLog_Print(rdpdr->log, WLOG_TRACE,
624 "capability %s got version %" PRIu32 ", will use version %" PRIu32,
625 rdpdr_cap_type_string(header.CapabilityType), header.Version,
626 rdpdr->common.capabilityVersions[header.CapabilityType]);
627 }
628
629 switch (header.CapabilityType)
630 {
631 case CAP_GENERAL_TYPE:
632 status = rdpdr_client_process_general_capset(rdpdr, s, &header);
633 break;
634
635 case CAP_PRINTER_TYPE:
636 status = rdpdr_process_printer_capset(rdpdr, s, &header);
637 break;
638
639 case CAP_PORT_TYPE:
640 status = rdpdr_process_port_capset(rdpdr, s, &header);
641 break;
642
643 case CAP_DRIVE_TYPE:
644 status = rdpdr_process_drive_capset(rdpdr, s, &header);
645 break;
646
647 case CAP_SMARTCARD_TYPE:
648 status = rdpdr_process_smartcard_capset(rdpdr, s, &header);
649 break;
650
651 default:
652 WLog_Print(rdpdr->log, WLOG_WARN,
653 "unknown capability 0x%04" PRIx16 ", length %" PRIu16
654 ", version %" PRIu32,
655 header.CapabilityType, header.CapabilityLength, header.Version);
656 Stream_Seek(s, header.CapabilityLength);
657 break;
658 }
659
660 if (status != CHANNEL_RC_OK)
661 return status;
662 }
663
664 return CHANNEL_RC_OK;
665}
666
667WINPR_ATTR_NODISCARD
668static BOOL rdpdr_write_general_capset(wLog* log, pf_channel_common_context* rdpdr, wStream* s)
669{
670 WINPR_ASSERT(rdpdr);
671 WINPR_ASSERT(s);
672
673 const RDPDR_CAPABILITY_HEADER header = { CAP_GENERAL_TYPE, 44,
674 rdpdr->capabilityVersions[CAP_GENERAL_TYPE] };
675 if (rdpdr_write_capset_header(log, s, &header) != CHANNEL_RC_OK)
676 return FALSE;
677 Stream_Write_UINT32(s, 0); /* osType, ignored on receipt */
678 Stream_Write_UINT32(s, 0); /* osVersion, should be ignored */
679 Stream_Write_UINT16(s, rdpdr->versionMajor); /* protocolMajorVersion, must be set to 1 */
680 Stream_Write_UINT16(s, rdpdr->versionMinor); /* protocolMinorVersion */
681 Stream_Write_UINT32(s, 0x0000FFFF); /* ioCode1 */
682 Stream_Write_UINT32(s, 0); /* ioCode2, must be set to zero, reserved for future use */
683 Stream_Write_UINT32(s, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU |
684 RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */
685 Stream_Write_UINT32(s, ENABLE_ASYNCIO); /* extraFlags1 */
686 Stream_Write_UINT32(s, 0); /* extraFlags2, must be set to zero, reserved for future use */
687 Stream_Write_UINT32(s, rdpdr->SpecialDeviceCount); /* SpecialTypeDeviceCap, number of special
688 devices to be redirected before logon */
689 return TRUE;
690}
691
692WINPR_ATTR_NODISCARD
693static BOOL rdpdr_write_printer_capset(wLog* log, pf_channel_common_context* rdpdr, wStream* s)
694{
695 WINPR_ASSERT(rdpdr);
696 WINPR_ASSERT(s);
697
698 const RDPDR_CAPABILITY_HEADER header = { CAP_PRINTER_TYPE, 8,
699 rdpdr->capabilityVersions[CAP_PRINTER_TYPE] };
700 return (rdpdr_write_capset_header(log, s, &header) == CHANNEL_RC_OK);
701}
702
703WINPR_ATTR_NODISCARD
704static BOOL rdpdr_write_port_capset(wLog* log, pf_channel_common_context* rdpdr, wStream* s)
705{
706 WINPR_ASSERT(rdpdr);
707 WINPR_ASSERT(s);
708
709 const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, 8,
710 rdpdr->capabilityVersions[CAP_PORT_TYPE] };
711 return (rdpdr_write_capset_header(log, s, &header) == CHANNEL_RC_OK);
712}
713
714WINPR_ATTR_NODISCARD
715static BOOL rdpdr_write_drive_capset(wLog* log, pf_channel_common_context* rdpdr, wStream* s)
716{
717 WINPR_ASSERT(rdpdr);
718 WINPR_ASSERT(s);
719
720 const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, 8,
721 rdpdr->capabilityVersions[CAP_DRIVE_TYPE] };
722 return (rdpdr_write_capset_header(log, s, &header) == CHANNEL_RC_OK);
723}
724
725WINPR_ATTR_NODISCARD
726static BOOL rdpdr_write_smartcard_capset(wLog* log, pf_channel_common_context* rdpdr, wStream* s)
727{
728 WINPR_ASSERT(rdpdr);
729 WINPR_ASSERT(s);
730
731 const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, 8,
732 rdpdr->capabilityVersions[CAP_SMARTCARD_TYPE] };
733 return (rdpdr_write_capset_header(log, s, &header) == CHANNEL_RC_OK);
734}
735
736WINPR_ATTR_NODISCARD
737static UINT rdpdr_send_server_capability_request(pf_channel_server_context* rdpdr)
738{
739 wStream* s =
740 rdpdr_server_get_send_buffer(rdpdr, RDPDR_CTYP_CORE, PAKID_CORE_SERVER_CAPABILITY, 8);
741 if (!s)
742 return CHANNEL_RC_NO_MEMORY;
743 Stream_Write_UINT16(s, 5); /* numCapabilities */
744 Stream_Write_UINT16(s, 0); /* pad */
745 if (!rdpdr_write_general_capset(rdpdr->log, &rdpdr->common, s))
746 return CHANNEL_RC_NO_MEMORY;
747 if (!rdpdr_write_printer_capset(rdpdr->log, &rdpdr->common, s))
748 return CHANNEL_RC_NO_MEMORY;
749 if (!rdpdr_write_port_capset(rdpdr->log, &rdpdr->common, s))
750 return CHANNEL_RC_NO_MEMORY;
751 if (!rdpdr_write_drive_capset(rdpdr->log, &rdpdr->common, s))
752 return CHANNEL_RC_NO_MEMORY;
753 if (!rdpdr_write_smartcard_capset(rdpdr->log, &rdpdr->common, s))
754 return CHANNEL_RC_NO_MEMORY;
755 return rdpdr_seal_send_free_request(rdpdr, s);
756}
757
758WINPR_ATTR_NODISCARD
759static UINT rdpdr_process_client_capability_response(pf_channel_server_context* rdpdr, wStream* s)
760{
761 const UINT16 component = RDPDR_CTYP_CORE;
762 const UINT16 packetid = PAKID_CORE_CLIENT_CAPABILITY;
763 UINT status = CHANNEL_RC_OK;
764 UINT16 numCapabilities = 0;
765 WINPR_ASSERT(rdpdr);
766
767 if (!rdpdr_process_server_header(TRUE, rdpdr->log, s, component, packetid, 4))
768 return ERROR_INVALID_DATA;
769
770 Stream_Read_UINT16(s, numCapabilities);
771 Stream_Seek_UINT16(s); /* padding */
772
773 for (UINT16 x = 0; x < numCapabilities; x++)
774 {
775 RDPDR_CAPABILITY_HEADER header = WINPR_C_ARRAY_INIT;
776 UINT error = rdpdr_read_capset_header(rdpdr->log, s, &header);
777 if (error != CHANNEL_RC_OK)
778 return error;
779 if (header.CapabilityType < ARRAYSIZE(rdpdr->common.capabilityVersions))
780 {
781 if (rdpdr->common.capabilityVersions[header.CapabilityType] > header.Version)
782 rdpdr->common.capabilityVersions[header.CapabilityType] = header.Version;
783
784 WLog_Print(rdpdr->log, WLOG_TRACE,
785 "capability %s got version %" PRIu32 ", will use version %" PRIu32,
786 rdpdr_cap_type_string(header.CapabilityType), header.Version,
787 rdpdr->common.capabilityVersions[header.CapabilityType]);
788 }
789
790 switch (header.CapabilityType)
791 {
792 case CAP_GENERAL_TYPE:
793 status = rdpdr_ignore_capset(TRUE, rdpdr->log, s, &header);
794 break;
795
796 case CAP_PRINTER_TYPE:
797 status = rdpdr_ignore_capset(TRUE, rdpdr->log, s, &header);
798 break;
799
800 case CAP_PORT_TYPE:
801 status = rdpdr_ignore_capset(TRUE, rdpdr->log, s, &header);
802 break;
803
804 case CAP_DRIVE_TYPE:
805 status = rdpdr_ignore_capset(TRUE, rdpdr->log, s, &header);
806 break;
807
808 case CAP_SMARTCARD_TYPE:
809 status = rdpdr_ignore_capset(TRUE, rdpdr->log, s, &header);
810 break;
811
812 default:
813 SERVER_RX_LOG(rdpdr->log, WLOG_WARN,
814 "[%s | %s] invalid capability type 0x%04" PRIx16,
815 rdpdr_component_string(component), rdpdr_packetid_string(packetid),
816 header.CapabilityType);
817 status = ERROR_INVALID_DATA;
818 break;
819 }
820
821 if (status != CHANNEL_RC_OK)
822 break;
823 }
824
825 return status;
826}
827
828WINPR_ATTR_NODISCARD
829static UINT rdpdr_send_client_capability_response(pClientContext* pc,
830 pf_channel_client_context* rdpdr)
831{
832 wStream* s = nullptr;
833
834 WINPR_ASSERT(rdpdr);
835 s = rdpdr_client_get_send_buffer(rdpdr, RDPDR_CTYP_CORE, PAKID_CORE_CLIENT_CAPABILITY, 4);
836 if (!s)
837 return CHANNEL_RC_NO_MEMORY;
838
839 Stream_Write_UINT16(s, 5); /* numCapabilities */
840 Stream_Write_UINT16(s, 0); /* pad */
841 if (!rdpdr_write_general_capset(rdpdr->log, &rdpdr->common, s))
842 return CHANNEL_RC_NO_MEMORY;
843 if (!rdpdr_write_printer_capset(rdpdr->log, &rdpdr->common, s))
844 return CHANNEL_RC_NO_MEMORY;
845 if (!rdpdr_write_port_capset(rdpdr->log, &rdpdr->common, s))
846 return CHANNEL_RC_NO_MEMORY;
847 if (!rdpdr_write_drive_capset(rdpdr->log, &rdpdr->common, s))
848 return CHANNEL_RC_NO_MEMORY;
849 if (!rdpdr_write_smartcard_capset(rdpdr->log, &rdpdr->common, s))
850 return CHANNEL_RC_NO_MEMORY;
851 return rdpdr_client_send(rdpdr->log, pc, s);
852}
853
854WINPR_ATTR_NODISCARD
855static UINT rdpdr_send_server_clientid_confirm(pf_channel_server_context* rdpdr)
856{
857 wStream* s = nullptr;
858
859 s = rdpdr_server_get_send_buffer(rdpdr, RDPDR_CTYP_CORE, PAKID_CORE_CLIENTID_CONFIRM, 8);
860 if (!s)
861 return CHANNEL_RC_NO_MEMORY;
862 Stream_Write_UINT16(s, rdpdr->common.versionMajor);
863 Stream_Write_UINT16(s, rdpdr->common.versionMinor);
864 Stream_Write_UINT32(s, rdpdr->common.clientID);
865 return rdpdr_seal_send_free_request(rdpdr, s);
866}
867
868WINPR_ATTR_NODISCARD
869static UINT rdpdr_process_server_clientid_confirm(pf_channel_client_context* rdpdr, wStream* s)
870{
871 UINT16 versionMajor = 0;
872 UINT16 versionMinor = 0;
873 UINT32 clientID = 0;
874
875 WINPR_ASSERT(rdpdr);
876 WINPR_ASSERT(s);
877
878 if (!rdpdr_process_server_header(FALSE, rdpdr->log, s, RDPDR_CTYP_CORE,
879 PAKID_CORE_CLIENTID_CONFIRM, 8))
880 return ERROR_INVALID_DATA;
881
882 Stream_Read_UINT16(s, versionMajor);
883 Stream_Read_UINT16(s, versionMinor);
884 if (!rdpdr_check_version(FALSE, rdpdr->log, versionMajor, versionMinor, RDPDR_CTYP_CORE,
885 PAKID_CORE_CLIENTID_CONFIRM))
886 return ERROR_INVALID_DATA;
887
888 Stream_Read_UINT32(s, clientID);
889
890 if ((versionMajor != rdpdr->common.versionMajor) ||
891 (versionMinor != rdpdr->common.versionMinor))
892 {
893 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN,
894 "[%s | %s] Version mismatch, sent %" PRIu16 ".%" PRIu16
895 ", downgraded to %" PRIu16 ".%" PRIu16,
896 rdpdr_component_string(RDPDR_CTYP_CORE),
897 rdpdr_packetid_string(PAKID_CORE_CLIENTID_CONFIRM),
898 rdpdr->common.versionMajor, rdpdr->common.versionMinor, versionMajor,
899 versionMinor);
900 rdpdr->common.versionMajor = versionMajor;
901 rdpdr->common.versionMinor = versionMinor;
902 }
903
904 if (clientID != rdpdr->common.clientID)
905 {
906 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN,
907 "[%s | %s] clientID mismatch, sent 0x%08" PRIx32 ", changed to 0x%08" PRIx32,
908 rdpdr_component_string(RDPDR_CTYP_CORE),
909 rdpdr_packetid_string(PAKID_CORE_CLIENTID_CONFIRM), rdpdr->common.clientID,
910 clientID);
911 rdpdr->common.clientID = clientID;
912 }
913
914 return CHANNEL_RC_OK;
915}
916
917WINPR_ATTR_NODISCARD
918static BOOL
919rdpdr_process_server_capability_request_or_clientid_confirm(pf_channel_client_context* rdpdr,
920 wStream* s)
921{
922 const UINT32 mask = STATE_CLIENT_EXPECT_SERVER_CLIENT_ID_CONFIRM |
923 STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST;
924 const UINT16 rcomponent = RDPDR_CTYP_CORE;
925 UINT16 component = 0;
926 UINT16 packetid = 0;
927
928 WINPR_ASSERT(rdpdr);
929 WINPR_ASSERT(s);
930
931 if ((rdpdr->flags & mask) == mask)
932 {
933 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN, "already past this state, abort!");
934 return FALSE;
935 }
936
937 if (!Stream_CheckAndLogRequiredLengthClient(rdpdr->log, s, 4))
938 return FALSE;
939
940 Stream_Read_UINT16(s, component);
941 if (rcomponent != component)
942 {
943 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN, "got component %s, expected %s",
944 rdpdr_component_string(component), rdpdr_component_string(rcomponent));
945 return FALSE;
946 }
947 Stream_Read_UINT16(s, packetid);
948 Stream_Rewind(s, 4);
949
950 switch (packetid)
951 {
952 case PAKID_CORE_SERVER_CAPABILITY:
953 if (rdpdr->flags & STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST)
954 {
955 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN, "got duplicate packetid %s",
956 rdpdr_packetid_string(packetid));
957 return FALSE;
958 }
959 rdpdr->flags |= STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST;
960 return rdpdr_process_server_core_capability_request(rdpdr, s) == CHANNEL_RC_OK;
961 case PAKID_CORE_CLIENTID_CONFIRM:
962 default:
963 if (rdpdr->flags & STATE_CLIENT_EXPECT_SERVER_CLIENT_ID_CONFIRM)
964 {
965 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN, "got duplicate packetid %s",
966 rdpdr_packetid_string(packetid));
967 return FALSE;
968 }
969 rdpdr->flags |= STATE_CLIENT_EXPECT_SERVER_CLIENT_ID_CONFIRM;
970 return rdpdr_process_server_clientid_confirm(rdpdr, s) == CHANNEL_RC_OK;
971 }
972}
973
974#if defined(WITH_PROXY_EMULATE_SMARTCARD)
975WINPR_ATTR_NODISCARD
976static UINT rdpdr_send_emulated_scard_device_list_announce_request(pClientContext* pc,
977 pf_channel_client_context* rdpdr)
978{
979 wStream* s = nullptr;
980
981 s = rdpdr_client_get_send_buffer(rdpdr, RDPDR_CTYP_CORE, PAKID_CORE_DEVICELIST_ANNOUNCE, 24);
982 if (!s)
983 return CHANNEL_RC_NO_MEMORY;
984
985 Stream_Write_UINT32(s, 1); /* deviceCount -> our emulated smartcard only */
986 Stream_Write_UINT32(s, RDPDR_DTYP_SMARTCARD); /* deviceType */
987 Stream_Write_UINT32(
988 s, SCARD_DEVICE_ID); /* deviceID -> reserve highest value for the emulated smartcard */
989 Stream_Write(s, "SCARD\0\0\0", 8);
990 Stream_Write_UINT32(s, 6);
991 Stream_Write(s, "SCARD\0", 6);
992
993 return rdpdr_client_send(rdpdr->log, pc, s);
994}
995
996WINPR_ATTR_NODISCARD
997static UINT rdpdr_send_emulated_scard_device_remove(pClientContext* pc,
998 pf_channel_client_context* rdpdr)
999{
1000 wStream* s = nullptr;
1001
1002 s = rdpdr_client_get_send_buffer(rdpdr, RDPDR_CTYP_CORE, PAKID_CORE_DEVICELIST_REMOVE, 24);
1003 if (!s)
1004 return CHANNEL_RC_NO_MEMORY;
1005
1006 Stream_Write_UINT32(s, 1); /* deviceCount -> our emulated smartcard only */
1007 Stream_Write_UINT32(
1008 s, SCARD_DEVICE_ID); /* deviceID -> reserve highest value for the emulated smartcard */
1009
1010 return rdpdr_client_send(rdpdr->log, pc, s);
1011}
1012
1013WINPR_ATTR_NODISCARD
1014static UINT rdpdr_process_server_device_announce_response(pf_channel_client_context* rdpdr,
1015 wStream* s)
1016{
1017 const UINT16 component = RDPDR_CTYP_CORE;
1018 const UINT16 packetid = PAKID_CORE_DEVICE_REPLY;
1019 UINT32 deviceID = 0;
1020 UINT32 resultCode = 0;
1021
1022 WINPR_ASSERT(rdpdr);
1023 WINPR_ASSERT(s);
1024
1025 if (!rdpdr_process_server_header(TRUE, rdpdr->log, s, component, packetid, 8))
1026 return ERROR_INVALID_DATA;
1027
1028 Stream_Read_UINT32(s, deviceID);
1029 Stream_Read_UINT32(s, resultCode);
1030
1031 if (deviceID != SCARD_DEVICE_ID)
1032 {
1033 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN,
1034 "[%s | %s] deviceID mismatch, sent 0x%08" PRIx32 ", changed to 0x%08" PRIx32,
1035 rdpdr_component_string(component), rdpdr_packetid_string(packetid),
1036 SCARD_DEVICE_ID, deviceID);
1037 }
1038 else if (resultCode != 0)
1039 {
1040 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN,
1041 "[%s | %s] deviceID 0x%08" PRIx32 " resultCode=0x%08" PRIx32,
1042 rdpdr_component_string(component), rdpdr_packetid_string(packetid), deviceID,
1043 resultCode);
1044 }
1045 else
1046 CLIENT_RX_LOG(rdpdr->log, WLOG_DEBUG,
1047 "[%s | %s] deviceID 0x%08" PRIx32 " resultCode=0x%08" PRIx32
1048 " -> emulated smartcard redirected!",
1049 rdpdr_component_string(component), rdpdr_packetid_string(packetid), deviceID,
1050 resultCode);
1051
1052 return CHANNEL_RC_OK;
1053}
1054#endif
1055
1056WINPR_ATTR_NODISCARD
1057static BOOL pf_channel_rdpdr_rewrite_device_list_to(wStream* s, UINT32 fromVersion,
1058 UINT32 toVersion)
1059{
1060 BOOL rc = FALSE;
1061 if (fromVersion == toVersion)
1062 return TRUE;
1063
1064 const size_t cap = Stream_GetRemainingLength(s);
1065 wStream* clone = Stream_New(nullptr, cap);
1066 if (!clone)
1067 goto fail;
1068
1069 {
1070 const size_t pos = Stream_GetPosition(s);
1071 Stream_Copy(s, clone, cap);
1072 Stream_SealLength(clone);
1073
1074 Stream_ResetPosition(clone);
1075 if (!Stream_SetPosition(s, pos))
1076 goto fail;
1077 }
1078
1079 /* Skip device count */
1080 if (!Stream_SafeSeek(s, 4))
1081 goto fail;
1082
1083 {
1084 UINT32 count = 0;
1085 if (Stream_GetRemainingLength(clone) < 4)
1086 goto fail;
1087 Stream_Read_UINT32(clone, count);
1088
1089 for (UINT32 x = 0; x < count; x++)
1090 {
1091 RdpdrDevice device = WINPR_C_ARRAY_INIT;
1092 const size_t charCount = ARRAYSIZE(device.PreferredDosName);
1093 if (Stream_GetRemainingLength(clone) < 20)
1094 goto fail;
1095
1096 Stream_Read_UINT32(clone, device.DeviceType); /* DeviceType (4 bytes) */
1097 Stream_Read_UINT32(clone, device.DeviceId); /* DeviceId (4 bytes) */
1098 Stream_Read(clone, device.PreferredDosName, charCount); /* PreferredDosName (8 bytes) */
1099 Stream_Read_UINT32(clone, device.DeviceDataLength); /* DeviceDataLength (4 bytes) */
1100 device.DeviceData = Stream_Pointer(clone);
1101 if (!Stream_SafeSeek(clone, device.DeviceDataLength))
1102 goto fail;
1103
1104 if (!Stream_EnsureRemainingCapacity(s, 20))
1105 goto fail;
1106 Stream_Write_UINT32(s, device.DeviceType);
1107 Stream_Write_UINT32(s, device.DeviceId);
1108 Stream_Write(s, device.PreferredDosName, charCount);
1109
1110 if (device.DeviceType == RDPDR_DTYP_FILESYSTEM)
1111 {
1112 if (toVersion == DRIVE_CAPABILITY_VERSION_01)
1113 Stream_Write_UINT32(s, 0); /* No unicode name */
1114 else
1115 {
1116 const SSIZE_T devNameWLen = ConvertUtf8NToWChar(
1117 device.PreferredDosName, ARRAYSIZE(device.PreferredDosName), nullptr, 0);
1118 if (devNameWLen < 0)
1119 goto fail;
1120 const size_t datalen =
1121 WINPR_ASSERTING_INT_CAST(size_t, devNameWLen) * sizeof(WCHAR);
1122 if (!Stream_EnsureRemainingCapacity(s, datalen + sizeof(UINT32)))
1123 goto fail;
1124 Stream_Write_UINT32(s, WINPR_ASSERTING_INT_CAST(uint32_t, datalen));
1125
1126 const SSIZE_T rcw = Stream_Write_UTF16_String_From_UTF8(
1127 s, charCount, device.PreferredDosName, charCount - 1, TRUE);
1128 if (rcw < 0)
1129 goto fail;
1130 }
1131 }
1132 else
1133 {
1134 Stream_Write_UINT32(s, device.DeviceDataLength);
1135 if (!Stream_EnsureRemainingCapacity(s, device.DeviceDataLength))
1136 goto fail;
1137 Stream_Write(s, device.DeviceData, device.DeviceDataLength);
1138 }
1139 }
1140 }
1141
1142 Stream_SealLength(s);
1143 rc = TRUE;
1144
1145fail:
1146 Stream_Free(clone, TRUE);
1147 return rc;
1148}
1149
1150WINPR_ATTR_NODISCARD
1151static BOOL pf_channel_rdpdr_rewrite_device_list(pf_channel_client_context* rdpdr,
1152 pServerContext* ps, wStream* s, BOOL toServer)
1153{
1154 WINPR_ASSERT(rdpdr);
1155 WINPR_ASSERT(ps);
1156
1157 const size_t pos = Stream_GetPosition(s);
1158 UINT16 component = 0;
1159 UINT16 packetid = 0;
1160 Stream_ResetPosition(s);
1161
1162 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4))
1163 return FALSE;
1164
1165 Stream_Read_UINT16(s, component);
1166 Stream_Read_UINT16(s, packetid);
1167 if ((component != RDPDR_CTYP_CORE) || (packetid != PAKID_CORE_DEVICELIST_ANNOUNCE))
1168 return Stream_SetPosition(s, pos);
1169
1170 const pf_channel_server_context* srv =
1171 HashTable_GetItemValue(ps->interceptContextMap, RDPDR_SVC_CHANNEL_NAME);
1172 if (!srv)
1173 {
1174 WLog_Print(rdpdr->log, WLOG_ERROR, "No channel %s in intercep map", RDPDR_SVC_CHANNEL_NAME);
1175 return FALSE;
1176 }
1177
1178 UINT32 from = srv->common.capabilityVersions[CAP_DRIVE_TYPE];
1179 UINT32 to = rdpdr->common.capabilityVersions[CAP_DRIVE_TYPE];
1180 if (toServer)
1181 {
1182 from = rdpdr->common.capabilityVersions[CAP_DRIVE_TYPE];
1183 to = srv->common.capabilityVersions[CAP_DRIVE_TYPE];
1184 }
1185 if (!pf_channel_rdpdr_rewrite_device_list_to(s, from, to))
1186 return FALSE;
1187
1188 return Stream_SetPosition(s, pos);
1189}
1190
1191WINPR_ATTR_NODISCARD
1192static BOOL pf_channel_rdpdr_client_send_to_server(pf_channel_client_context* rdpdr,
1193 pServerContext* ps, wStream* s)
1194{
1195 WINPR_ASSERT(rdpdr);
1196 if (ps)
1197 {
1198 UINT16 server_channel_id = WTSChannelGetId(ps->context.peer, RDPDR_SVC_CHANNEL_NAME);
1199
1200 /* Ignore messages for channels that can not be mapped.
1201 * The client might not have enabled support for this specific channel,
1202 * so just drop the message. */
1203 if (server_channel_id == 0)
1204 return TRUE;
1205
1206 if (!pf_channel_rdpdr_rewrite_device_list(rdpdr, ps, s, TRUE))
1207 return FALSE;
1208 size_t len = Stream_Length(s);
1209 if (!Stream_SetPosition(s, len))
1210 return ERROR_INVALID_DATA;
1211 rdpdr_dump_send_packet(rdpdr->log, WLOG_TRACE, s, proxy_client_tx);
1212 WINPR_ASSERT(ps->context.peer);
1213 WINPR_ASSERT(ps->context.peer->SendChannelData);
1214 return ps->context.peer->SendChannelData(ps->context.peer, server_channel_id,
1215 Stream_Buffer(s), len);
1216 }
1217 return TRUE;
1218}
1219
1220WINPR_ATTR_NODISCARD
1221static BOOL pf_channel_send_client_queue(pClientContext* pc, pf_channel_client_context* rdpdr);
1222
1223#if defined(WITH_PROXY_EMULATE_SMARTCARD)
1224WINPR_ATTR_NODISCARD
1225static BOOL rdpdr_process_server_loggedon_request(pServerContext* ps, pClientContext* pc,
1226 pf_channel_client_context* rdpdr, wStream* s,
1227 UINT16 component, UINT16 packetid)
1228{
1229 WINPR_ASSERT(rdpdr);
1230 WLog_Print(rdpdr->log, WLOG_DEBUG, "[%s | %s]", rdpdr_component_string(component),
1231 rdpdr_packetid_string(packetid));
1232 if (rdpdr_send_emulated_scard_device_remove(pc, rdpdr) != CHANNEL_RC_OK)
1233 return FALSE;
1234 if (rdpdr_send_emulated_scard_device_list_announce_request(pc, rdpdr) != CHANNEL_RC_OK)
1235 return FALSE;
1236 return pf_channel_rdpdr_client_send_to_server(rdpdr, ps, s);
1237}
1238
1239WINPR_ATTR_NODISCARD
1240static BOOL filter_smartcard_io_requests(pf_channel_client_context* rdpdr, wStream* s,
1241 UINT16* pPacketid)
1242{
1243 BOOL rc = FALSE;
1244 UINT16 component = 0;
1245 UINT16 packetid = 0;
1246 UINT32 deviceID = 0;
1247 size_t pos = 0;
1248
1249 WINPR_ASSERT(rdpdr);
1250 WINPR_ASSERT(pPacketid);
1251
1252 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4))
1253 return FALSE;
1254
1255 pos = Stream_GetPosition(s);
1256 Stream_Read_UINT16(s, component);
1257 Stream_Read_UINT16(s, packetid);
1258
1259 if (Stream_GetRemainingLength(s) >= 4)
1260 Stream_Read_UINT32(s, deviceID);
1261
1262 WLog_Print(rdpdr->log, WLOG_DEBUG, "got: [%s | %s]: [0x%08" PRIx32 "]",
1263 rdpdr_component_string(component), rdpdr_packetid_string(packetid), deviceID);
1264
1265 if (component != RDPDR_CTYP_CORE)
1266 goto fail;
1267
1268 switch (packetid)
1269 {
1270 case PAKID_CORE_SERVER_ANNOUNCE:
1271 case PAKID_CORE_CLIENTID_CONFIRM:
1272 case PAKID_CORE_CLIENT_NAME:
1273 case PAKID_CORE_DEVICELIST_ANNOUNCE:
1274 case PAKID_CORE_DEVICELIST_REMOVE:
1275 case PAKID_CORE_SERVER_CAPABILITY:
1276 case PAKID_CORE_CLIENT_CAPABILITY:
1277 WLog_Print(rdpdr->log, WLOG_WARN, "Filtering client -> server message [%s | %s]",
1278 rdpdr_component_string(component), rdpdr_packetid_string(packetid));
1279 *pPacketid = packetid;
1280 break;
1281 case PAKID_CORE_USER_LOGGEDON:
1282 *pPacketid = packetid;
1283 break;
1284 case PAKID_CORE_DEVICE_REPLY:
1285 case PAKID_CORE_DEVICE_IOREQUEST:
1286 if (deviceID != SCARD_DEVICE_ID)
1287 goto fail;
1288 *pPacketid = packetid;
1289 break;
1290 default:
1291 if (deviceID != SCARD_DEVICE_ID)
1292 goto fail;
1293 WLog_Print(rdpdr->log, WLOG_WARN,
1294 "Got [%s | %s] for deviceID 0x%08" PRIx32 ", TODO: Not handled!",
1295 rdpdr_component_string(component), rdpdr_packetid_string(packetid),
1296 deviceID);
1297 goto fail;
1298 }
1299
1300 rc = TRUE;
1301
1302fail:
1303 if (!Stream_SetPosition(s, pos))
1304 return FALSE;
1305 return rc;
1306}
1307#endif
1308
1309BOOL pf_channel_send_client_queue(pClientContext* pc, pf_channel_client_context* rdpdr)
1310{
1311 WINPR_ASSERT(pc);
1312 WINPR_ASSERT(rdpdr);
1313
1314 if (rdpdr->state != STATE_CLIENT_CHANNEL_RUNNING)
1315 {
1316 CLIENT_TX_LOG(rdpdr->log, WLOG_WARN, "Client RDPDR channel not ready, dropping packet!");
1317 return TRUE;
1318 }
1319
1320 const UINT16 channelId =
1321 freerdp_channels_get_id_by_name(pc->cctx.context.instance, RDPDR_SVC_CHANNEL_NAME);
1322 if ((channelId == 0) || (channelId == UINT16_MAX))
1323 {
1324 CLIENT_TX_LOG(rdpdr->log, WLOG_WARN,
1325 "Client RDPDR channel not available, dropping packet!");
1326 return TRUE;
1327 }
1328
1329 Queue_Lock(rdpdr->queue);
1330 while (Queue_Count(rdpdr->queue) > 0)
1331 {
1332 wStream* s = Queue_Dequeue(rdpdr->queue);
1333 if (!s)
1334 continue;
1335
1336 size_t len = Stream_Length(s);
1337 if (!Stream_SetPosition(s, len))
1338 {
1339 Stream_Free(s, TRUE);
1340 continue;
1341 }
1342
1343 rdpdr_dump_send_packet(rdpdr->log, WLOG_TRACE, s, proxy_server_tx " (queue) ");
1344 WINPR_ASSERT(pc->cctx.context.instance->SendChannelData);
1345 if (!pc->cctx.context.instance->SendChannelData(pc->cctx.context.instance, channelId,
1346 Stream_Buffer(s), len))
1347 {
1348 CLIENT_TX_LOG(rdpdr->log, WLOG_ERROR, "xxxxxx TODO: Failed to send data!");
1349 }
1350 Stream_Free(s, TRUE);
1351 }
1352 Queue_Unlock(rdpdr->queue);
1353 return TRUE;
1354}
1355
1356WINPR_ATTR_NODISCARD
1357static BOOL rdpdr_handle_server_announce_request(pClientContext* pc,
1358 pf_channel_client_context* rdpdr, wStream* s)
1359{
1360 WINPR_ASSERT(pc);
1361 WINPR_ASSERT(rdpdr);
1362 WINPR_ASSERT(s);
1363
1364 if (rdpdr_process_server_announce_request(rdpdr, s) != CHANNEL_RC_OK)
1365 return FALSE;
1366 if (rdpdr_send_client_announce_reply(pc, rdpdr) != CHANNEL_RC_OK)
1367 return FALSE;
1368 if (rdpdr_send_client_name_request(pc, rdpdr) != CHANNEL_RC_OK)
1369 return FALSE;
1370 rdpdr->state = STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST;
1371 return TRUE;
1372}
1373
1374BOOL pf_channel_rdpdr_client_handle(pClientContext* pc, UINT16 channelId, const char* channel_name,
1375 const BYTE* xdata, size_t xsize, UINT32 flags, size_t totalSize)
1376{
1377#if defined(WITH_PROXY_EMULATE_SMARTCARD)
1378 UINT16 packetid = 0;
1379#endif
1380
1381 WINPR_ASSERT(pc);
1382 WINPR_ASSERT(pc->pdata);
1383 WINPR_ASSERT(pc->interceptContextMap);
1384 WINPR_ASSERT(channel_name);
1385 WINPR_ASSERT(xdata);
1386
1387 pServerContext* ps = proxy_data_get_server_context(pc->pdata);
1388
1389 pf_channel_client_context* rdpdr =
1390 HashTable_GetItemValue(pc->interceptContextMap, channel_name);
1391 if (!rdpdr)
1392 {
1393 CLIENT_RX_LOG(WLog_Get(RTAG), WLOG_ERROR,
1394 "Channel %s [0x%04" PRIx16 "] missing context in interceptContextMap",
1395 channel_name, channelId);
1396 return FALSE;
1397 }
1398
1399 wStream* s = rdpdr->common.buffer;
1400 if (flags & CHANNEL_FLAG_FIRST)
1401 {
1402 Stream_ResetPosition(s);
1403 rdpdr->common.totalLength = totalSize;
1404 }
1405
1406 if (!Stream_EnsureRemainingCapacity(s, xsize))
1407 {
1408 CLIENT_RX_LOG(rdpdr->log, WLOG_ERROR,
1409 "Channel %s [0x%04" PRIx16 "] not enough memory [need %" PRIuz "]",
1410 channel_name, channelId, xsize);
1411 return FALSE;
1412 }
1413 Stream_Write(s, xdata, xsize);
1414
1415 if ((Stream_GetPosition(s) > totalSize) || (totalSize != rdpdr->common.totalLength))
1416 {
1417 CLIENT_RX_LOG(rdpdr->log, WLOG_ERROR,
1418 "Channel %s [0x%04" PRIx16 "] total size mismatch [got %" PRIuz
1419 ", expected %" PRIuz "]",
1420 channel_name, channelId, totalSize, rdpdr->common.totalLength);
1421 return FALSE;
1422 }
1423
1424 if ((flags & CHANNEL_FLAG_LAST) == 0)
1425 return TRUE;
1426
1427 Stream_SealLength(s);
1428 Stream_ResetPosition(s);
1429 rdpdr->common.totalLength = 0;
1430 if (Stream_Length(s) != totalSize)
1431 {
1432 CLIENT_RX_LOG(rdpdr->log, WLOG_WARN,
1433 "Received invalid %s channel data (server -> proxy), expected %" PRIuz
1434 "bytes, got %" PRIuz,
1435 channel_name, totalSize, Stream_Length(s));
1436 return FALSE;
1437 }
1438
1439 rdpdr_dump_received_packet(rdpdr->log, WLOG_TRACE, s, proxy_server_rx);
1440 switch (rdpdr->state)
1441 {
1442 case STATE_CLIENT_EXPECT_SERVER_ANNOUNCE_REQUEST:
1443 if (!rdpdr_handle_server_announce_request(pc, rdpdr, s))
1444 return FALSE;
1445 break;
1446 case STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST:
1447 if (!rdpdr_process_server_capability_request_or_clientid_confirm(rdpdr, s))
1448 return FALSE;
1449 rdpdr->state = STATE_CLIENT_EXPECT_SERVER_CLIENT_ID_CONFIRM;
1450 break;
1451 case STATE_CLIENT_EXPECT_SERVER_CLIENT_ID_CONFIRM:
1452 if (!rdpdr_process_server_capability_request_or_clientid_confirm(rdpdr, s))
1453 return FALSE;
1454 if (rdpdr_send_client_capability_response(pc, rdpdr) != CHANNEL_RC_OK)
1455 return FALSE;
1456#if defined(WITH_PROXY_EMULATE_SMARTCARD)
1457 if (pf_channel_smartcard_client_emulate(pc))
1458 {
1459 if (rdpdr_send_emulated_scard_device_list_announce_request(pc, rdpdr) !=
1460 CHANNEL_RC_OK)
1461 return FALSE;
1462 rdpdr->state = STATE_CLIENT_CHANNEL_RUNNING;
1463 }
1464 else
1465#endif
1466 {
1467 rdpdr->state = STATE_CLIENT_CHANNEL_RUNNING;
1468 if (!pf_channel_send_client_queue(pc, rdpdr))
1469 return FALSE;
1470 }
1471
1472 break;
1473 case STATE_CLIENT_CHANNEL_RUNNING:
1474#if defined(WITH_PROXY_EMULATE_SMARTCARD)
1475 if (!pf_channel_smartcard_client_emulate(pc) ||
1476 !filter_smartcard_io_requests(rdpdr, s, &packetid))
1477 return pf_channel_rdpdr_client_send_to_server(rdpdr, ps, s);
1478 else
1479 {
1480 switch (packetid)
1481 {
1482 case PAKID_CORE_USER_LOGGEDON:
1483 return rdpdr_process_server_loggedon_request(ps, pc, rdpdr, s,
1484 RDPDR_CTYP_CORE, packetid);
1485 case PAKID_CORE_DEVICE_IOREQUEST:
1486 {
1487 wStream* out = rdpdr_client_get_send_buffer(
1488 rdpdr, RDPDR_CTYP_CORE, PAKID_CORE_DEVICE_IOCOMPLETION, 0);
1489 WINPR_ASSERT(out);
1490
1491 if (!rdpdr_process_server_header(FALSE, rdpdr->log, s, RDPDR_CTYP_CORE,
1492 PAKID_CORE_DEVICE_IOREQUEST, 20))
1493 return FALSE;
1494
1495 if (!pf_channel_smartcard_client_handle(rdpdr->log, pc, s, out,
1496 rdpdr_client_send))
1497 return FALSE;
1498 }
1499 break;
1500 case PAKID_CORE_SERVER_ANNOUNCE:
1501 pf_channel_rdpdr_client_reset(pc);
1502 if (!rdpdr_handle_server_announce_request(pc, rdpdr, s))
1503 return FALSE;
1504 break;
1505 case PAKID_CORE_SERVER_CAPABILITY:
1506 rdpdr->state = STATE_CLIENT_EXPECT_SERVER_CORE_CAPABILITY_REQUEST;
1507 rdpdr->flags = 0;
1508 return pf_channel_rdpdr_client_handle(pc, channelId, channel_name, xdata,
1509 xsize, flags, totalSize);
1510 case PAKID_CORE_DEVICE_REPLY:
1511 break;
1512 default:
1513 CLIENT_RX_LOG(
1514 rdpdr->log, WLOG_ERROR,
1515 "Channel %s [0x%04" PRIx16
1516 "] we´ve reached an impossible state %s! [%s] aliens invaded!",
1517 channel_name, channelId, rdpdr_client_state_to_string(rdpdr->state),
1518 rdpdr_packetid_string(packetid));
1519 return FALSE;
1520 }
1521 }
1522 break;
1523#else
1524 return pf_channel_rdpdr_client_send_to_server(rdpdr, ps, s);
1525#endif
1526 default:
1527 CLIENT_RX_LOG(rdpdr->log, WLOG_ERROR,
1528 "Channel %s [0x%04" PRIx16
1529 "] we´ve reached an impossible state %s! aliens invaded!",
1530 channel_name, channelId, rdpdr_client_state_to_string(rdpdr->state));
1531 return FALSE;
1532 }
1533
1534 return TRUE;
1535}
1536
1537static void pf_channel_rdpdr_common_context_free(pf_channel_common_context* common)
1538{
1539 if (!common)
1540 return;
1541 free(common->computerName.v);
1542 Stream_Free(common->s, TRUE);
1543 Stream_Free(common->buffer, TRUE);
1544}
1545
1546static void pf_channel_rdpdr_client_context_free(InterceptContextMapEntry* base)
1547{
1548 pf_channel_client_context* entry = (pf_channel_client_context*)base;
1549 if (!entry)
1550 return;
1551
1552 pf_channel_rdpdr_common_context_free(&entry->common);
1553 Queue_Free(entry->queue);
1554 WLog_Discard(entry->log);
1555 free(entry);
1556}
1557
1558WINPR_ATTR_NODISCARD
1559static BOOL pf_channel_rdpdr_common_context_new(pf_channel_common_context* common,
1560 void (*fkt)(InterceptContextMapEntry*))
1561{
1562 if (!common)
1563 return FALSE;
1564 common->base.free = fkt;
1565 common->s = Stream_New(nullptr, 1024);
1566 if (!common->s)
1567 return FALSE;
1568 common->buffer = Stream_New(nullptr, 1024);
1569 if (!common->buffer)
1570 return FALSE;
1571 common->computerNameUnicode = 1;
1572 common->computerName.v = nullptr;
1573 common->versionMajor = RDPDR_VERSION_MAJOR;
1574 common->versionMinor = RDPDR_VERSION_MINOR_RDP10X;
1575 common->clientID = SCARD_DEVICE_ID;
1576
1577 const UINT32 versions[] = { 0,
1578 GENERAL_CAPABILITY_VERSION_02,
1579 PRINT_CAPABILITY_VERSION_01,
1580 PORT_CAPABILITY_VERSION_01,
1581 DRIVE_CAPABILITY_VERSION_02,
1582 SMARTCARD_CAPABILITY_VERSION_01 };
1583
1584 memcpy(common->capabilityVersions, versions, sizeof(common->capabilityVersions));
1585 return TRUE;
1586}
1587
1588WINPR_ATTR_NODISCARD
1589static BOOL pf_channel_rdpdr_client_pass_message(pServerContext* ps, pClientContext* pc,
1590 WINPR_ATTR_UNUSED UINT16 channelId,
1591 const char* channel_name, wStream* s)
1592{
1593 pf_channel_client_context* rdpdr = nullptr;
1594
1595 WINPR_ASSERT(ps);
1596 WINPR_ASSERT(pc);
1597
1598 rdpdr = HashTable_GetItemValue(pc->interceptContextMap, channel_name);
1599 if (!rdpdr)
1600 return TRUE; /* Ignore data for channels not available on proxy -> server connection */
1601 WINPR_ASSERT(rdpdr->queue);
1602
1603 if (!pf_channel_rdpdr_rewrite_device_list(rdpdr, ps, s, FALSE))
1604 return FALSE;
1605 if (!Queue_Enqueue(rdpdr->queue, s))
1606 return FALSE;
1607 return pf_channel_send_client_queue(pc, rdpdr);
1608}
1609
1610#if defined(WITH_PROXY_EMULATE_SMARTCARD)
1611WINPR_ATTR_NODISCARD
1612static BOOL filter_smartcard_device_list_remove(pf_channel_server_context* rdpdr, wStream* s)
1613{
1614 size_t pos = 0;
1615 UINT32 count = 0;
1616
1617 WINPR_ASSERT(rdpdr);
1618 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, sizeof(UINT32)))
1619 return TRUE;
1620 pos = Stream_GetPosition(s);
1621 Stream_Read_UINT32(s, count);
1622
1623 if (count == 0)
1624 return TRUE;
1625
1626 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(rdpdr->log, s, count, sizeof(UINT32)))
1627 return TRUE;
1628
1629 for (UINT32 x = 0; x < count; x++)
1630 {
1631 UINT32 deviceID = 0;
1632 BYTE* dst = Stream_Pointer(s);
1633 Stream_Read_UINT32(s, deviceID);
1634 if (deviceID == SCARD_DEVICE_ID)
1635 {
1636 ArrayList_Remove(rdpdr->blockedDevices, (void*)(size_t)deviceID);
1637
1638 /* This is the only device, filter it! */
1639 if (count == 1)
1640 return TRUE;
1641
1642 /* Remove this device from the list */
1643 memmove(dst, Stream_ConstPointer(s), (count - x - 1) * sizeof(UINT32));
1644
1645 count--;
1646 if (Stream_SetPosition(s, pos))
1647 Stream_Write_UINT32(s, count);
1648 return FALSE;
1649 }
1650 }
1651
1652 return FALSE;
1653}
1654
1655WINPR_ATTR_NODISCARD
1656static BOOL filter_smartcard_device_io_request(pf_channel_server_context* rdpdr, wStream* s)
1657{
1658 UINT32 DeviceID = 0;
1659 WINPR_ASSERT(rdpdr);
1660 WINPR_ASSERT(s);
1661 Stream_Read_UINT32(s, DeviceID);
1662 return ArrayList_Contains(rdpdr->blockedDevices, (void*)(size_t)DeviceID);
1663}
1664
1665WINPR_ATTR_NODISCARD
1666static BOOL filter_smartcard_device_list_announce(pf_channel_server_context* rdpdr, wStream* s)
1667{
1668 UINT32 count = 0;
1669
1670 WINPR_ASSERT(rdpdr);
1671 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, sizeof(UINT32)))
1672 return TRUE;
1673 const size_t pos = Stream_GetPosition(s);
1674 Stream_Read_UINT32(s, count);
1675
1676 if (count == 0)
1677 return TRUE;
1678
1679 for (UINT32 x = 0; x < count; x++)
1680 {
1681 UINT32 DeviceType = 0;
1682 UINT32 DeviceId = 0;
1683 char PreferredDosName[8];
1684 UINT32 DeviceDataLength = 0;
1685 BYTE* dst = Stream_Pointer(s);
1686 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 20))
1687 return TRUE;
1688 Stream_Read_UINT32(s, DeviceType);
1689 Stream_Read_UINT32(s, DeviceId);
1690 Stream_Read(s, PreferredDosName, ARRAYSIZE(PreferredDosName));
1691 Stream_Read_UINT32(s, DeviceDataLength);
1692 if (!Stream_SafeSeek(s, DeviceDataLength))
1693 return TRUE;
1694 if (DeviceType == RDPDR_DTYP_SMARTCARD)
1695 {
1696 if (!ArrayList_Append(rdpdr->blockedDevices, (void*)(size_t)DeviceId))
1697 return FALSE;
1698 if (count == 1)
1699 return TRUE;
1700
1701 WLog_Print(rdpdr->log, WLOG_INFO, "Filtering smartcard device 0x%08" PRIx32 "",
1702 DeviceId);
1703
1704 memmove(dst, Stream_ConstPointer(s), Stream_GetRemainingLength(s));
1705 if (Stream_SetPosition(s, pos))
1706 Stream_Write_UINT32(s, count - 1);
1707 return FALSE;
1708 }
1709 }
1710
1711 return FALSE;
1712}
1713
1714WINPR_ATTR_NODISCARD
1715static BOOL filter_smartcard_device_list_announce_request(pf_channel_server_context* rdpdr,
1716 wStream* s)
1717{
1718 BOOL rc = TRUE;
1719 size_t pos = 0;
1720 UINT16 component = 0;
1721 UINT16 packetid = 0;
1722
1723 WINPR_ASSERT(rdpdr);
1724 if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 8))
1725 return FALSE;
1726
1727 pos = Stream_GetPosition(s);
1728
1729 Stream_Read_UINT16(s, component);
1730 Stream_Read_UINT16(s, packetid);
1731
1732 if (component != RDPDR_CTYP_CORE)
1733 goto fail;
1734
1735 switch (packetid)
1736 {
1737 case PAKID_CORE_DEVICELIST_ANNOUNCE:
1738 if (filter_smartcard_device_list_announce(rdpdr, s))
1739 goto fail;
1740 break;
1741 case PAKID_CORE_DEVICELIST_REMOVE:
1742 if (filter_smartcard_device_list_remove(rdpdr, s))
1743 goto fail;
1744 break;
1745 case PAKID_CORE_DEVICE_IOREQUEST:
1746 if (filter_smartcard_device_io_request(rdpdr, s))
1747 goto fail;
1748 break;
1749
1750 case PAKID_CORE_SERVER_ANNOUNCE:
1751 case PAKID_CORE_CLIENTID_CONFIRM:
1752 case PAKID_CORE_CLIENT_NAME:
1753 case PAKID_CORE_DEVICE_REPLY:
1754 case PAKID_CORE_SERVER_CAPABILITY:
1755 case PAKID_CORE_CLIENT_CAPABILITY:
1756 case PAKID_CORE_USER_LOGGEDON:
1757 WLog_Print(rdpdr->log, WLOG_WARN, "Filtering client -> server message [%s | %s]",
1758 rdpdr_component_string(component), rdpdr_packetid_string(packetid));
1759 goto fail;
1760 default:
1761 break;
1762 }
1763
1764 rc = FALSE;
1765fail:
1766 if (!Stream_SetPosition(s, pos))
1767 return FALSE;
1768 return rc;
1769}
1770#endif
1771
1772WINPR_ATTR_MALLOC(Stream_Free, 1)
1773WINPR_ATTR_NODISCARD
1774static void* stream_copy(const void* obj)
1775{
1776 const wStream* src = obj;
1777 wStream* dst = Stream_New(nullptr, Stream_Capacity(src));
1778 if (!dst)
1779 return nullptr;
1780 memcpy(Stream_Buffer(dst), Stream_ConstBuffer(src), Stream_Capacity(dst));
1781 if (!Stream_SetLength(dst, Stream_Length(src)))
1782 goto fail;
1783 if (!Stream_SetPosition(dst, Stream_GetPosition(src)))
1784 goto fail;
1785 return dst;
1786fail:
1787 Stream_Free(dst, TRUE);
1788 return nullptr;
1789}
1790
1791static void stream_free(void* obj)
1792{
1793 wStream* s = obj;
1794 Stream_Free(s, TRUE);
1795}
1796
1797WINPR_ATTR_NODISCARD
1798static const char* pf_channel_rdpdr_client_context(void* arg)
1799{
1800 pClientContext* pc = arg;
1801 if (!pc)
1802 return "pc=null";
1803 if (!pc->pdata)
1804 return "pc->pdata=null";
1805 return pc->pdata->session_id;
1806}
1807
1808BOOL pf_channel_rdpdr_client_new(pClientContext* pc)
1809{
1810 wObject* obj = nullptr;
1811 pf_channel_client_context* rdpdr = nullptr;
1812
1813 WINPR_ASSERT(pc);
1814 WINPR_ASSERT(pc->interceptContextMap);
1815
1816 rdpdr = calloc(1, sizeof(pf_channel_client_context));
1817 if (!rdpdr)
1818 return FALSE;
1819 rdpdr->log = WLog_Create(RTAG, WLog_GetRoot());
1820 if (!rdpdr->log)
1821 goto fail;
1822
1823 if (!WLog_SetContext(rdpdr->log, pf_channel_rdpdr_client_context, pc))
1824 goto fail;
1825
1826 if (!pf_channel_rdpdr_common_context_new(&rdpdr->common, pf_channel_rdpdr_client_context_free))
1827 goto fail;
1828
1829 rdpdr->maxMajorVersion = RDPDR_VERSION_MAJOR;
1830 rdpdr->maxMinorVersion = RDPDR_VERSION_MINOR_RDP10X;
1831 rdpdr->state = STATE_CLIENT_EXPECT_SERVER_ANNOUNCE_REQUEST;
1832
1833 rdpdr->queue = Queue_New(TRUE, 0, 0);
1834 if (!rdpdr->queue)
1835 goto fail;
1836 obj = Queue_Object(rdpdr->queue);
1837 WINPR_ASSERT(obj);
1838 obj->fnObjectNew = stream_copy;
1839 obj->fnObjectFree = stream_free;
1840 if (!HashTable_Insert(pc->interceptContextMap, RDPDR_SVC_CHANNEL_NAME, rdpdr))
1841 goto fail;
1842 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert takes ownership of rdpdr
1843 return TRUE;
1844fail:
1845 pf_channel_rdpdr_client_context_free(&rdpdr->common.base);
1846 return FALSE;
1847}
1848
1849void pf_channel_rdpdr_client_free(pClientContext* pc)
1850{
1851 WINPR_ASSERT(pc);
1852 WINPR_ASSERT(pc->interceptContextMap);
1853 HashTable_Remove(pc->interceptContextMap, RDPDR_SVC_CHANNEL_NAME);
1854}
1855
1856static void pf_channel_rdpdr_server_context_free(InterceptContextMapEntry* base)
1857{
1858 pf_channel_server_context* entry = (pf_channel_server_context*)base;
1859 if (!entry)
1860 return;
1861
1862 (void)WTSVirtualChannelClose(entry->handle);
1863 pf_channel_rdpdr_common_context_free(&entry->common);
1864 ArrayList_Free(entry->blockedDevices);
1865 WLog_Discard(entry->log);
1866 free(entry);
1867}
1868
1869WINPR_ATTR_NODISCARD
1870static const char* pf_channel_rdpdr_server_context(void* arg)
1871{
1872 pServerContext* ps = arg;
1873 if (!ps)
1874 return "ps=null";
1875 if (!ps->pdata)
1876 return "ps->pdata=null";
1877 return ps->pdata->session_id;
1878}
1879
1880BOOL pf_channel_rdpdr_server_new(pServerContext* ps)
1881{
1882 pf_channel_server_context* rdpdr = nullptr;
1883 PULONG pSessionId = nullptr;
1884 DWORD BytesReturned = 0;
1885
1886 WINPR_ASSERT(ps);
1887 WINPR_ASSERT(ps->interceptContextMap);
1888
1889 rdpdr = calloc(1, sizeof(pf_channel_server_context));
1890 if (!rdpdr)
1891 return FALSE;
1892 rdpdr->log = WLog_Create(RTAG, WLog_GetRoot());
1893 if (!rdpdr->log)
1894 goto fail;
1895
1896 if (!WLog_SetContext(rdpdr->log, pf_channel_rdpdr_server_context, ps))
1897 goto fail;
1898
1899 if (!pf_channel_rdpdr_common_context_new(&rdpdr->common, pf_channel_rdpdr_server_context_free))
1900 goto fail;
1901 rdpdr->state = STATE_SERVER_INITIAL;
1902
1903 rdpdr->blockedDevices = ArrayList_New(FALSE);
1904 if (!rdpdr->blockedDevices)
1905 goto fail;
1906
1907 rdpdr->SessionId = WTS_CURRENT_SESSION;
1908 if (WTSQuerySessionInformationA(ps->vcm, WTS_CURRENT_SESSION, WTSSessionId, (LPSTR*)&pSessionId,
1909 &BytesReturned))
1910 {
1911 rdpdr->SessionId = (DWORD)*pSessionId;
1912 WTSFreeMemory(pSessionId);
1913 }
1914
1915 rdpdr->handle = WTSVirtualChannelOpenEx(rdpdr->SessionId, RDPDR_SVC_CHANNEL_NAME, 0);
1916 if (rdpdr->handle == nullptr)
1917 goto fail;
1918 if (!HashTable_Insert(ps->interceptContextMap, RDPDR_SVC_CHANNEL_NAME, rdpdr))
1919 goto fail;
1920
1921 // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert takes ownership of rdpdr
1922 return TRUE;
1923fail:
1924 pf_channel_rdpdr_server_context_free(&rdpdr->common.base);
1925 return FALSE;
1926}
1927
1928void pf_channel_rdpdr_server_free(pServerContext* ps)
1929{
1930 WINPR_ASSERT(ps);
1931 WINPR_ASSERT(ps->interceptContextMap);
1932 HashTable_Remove(ps->interceptContextMap, RDPDR_SVC_CHANNEL_NAME);
1933}
1934
1935WINPR_ATTR_NODISCARD
1936static pf_channel_server_context* get_channel(pServerContext* ps, BOOL send)
1937{
1938 pf_channel_server_context* rdpdr = nullptr;
1939 WINPR_ASSERT(ps);
1940 WINPR_ASSERT(ps->interceptContextMap);
1941
1942 rdpdr = HashTable_GetItemValue(ps->interceptContextMap, RDPDR_SVC_CHANNEL_NAME);
1943 if (!rdpdr)
1944 {
1945 SERVER_RXTX_LOG(send, WLog_Get(RTAG), WLOG_ERROR,
1946 "Channel %s missing context in interceptContextMap",
1947 RDPDR_SVC_CHANNEL_NAME);
1948 return nullptr;
1949 }
1950
1951 return rdpdr;
1952}
1953
1954BOOL pf_channel_rdpdr_server_handle(pServerContext* ps, UINT16 channelId, const char* channel_name,
1955 const BYTE* xdata, size_t xsize, UINT32 flags, size_t totalSize)
1956{
1957 pf_channel_server_context* rdpdr = get_channel(ps, FALSE);
1958 if (!rdpdr)
1959 return FALSE;
1960
1961 WINPR_ASSERT(ps->pdata);
1962 pClientContext* pc = proxy_data_get_client_context(ps->pdata);
1963
1964 wStream* s = rdpdr->common.buffer;
1965
1966 if (flags & CHANNEL_FLAG_FIRST)
1967 {
1968 rdpdr->common.totalLength = totalSize;
1969 Stream_ResetPosition(s);
1970 }
1971
1972 if (!Stream_EnsureRemainingCapacity(s, xsize))
1973 return FALSE;
1974 Stream_Write(s, xdata, xsize);
1975
1976 if ((Stream_GetPosition(s) > totalSize) || (totalSize != rdpdr->common.totalLength))
1977 return FALSE;
1978
1979 if ((flags & CHANNEL_FLAG_LAST) == 0)
1980 return TRUE;
1981
1982 Stream_SealLength(s);
1983 Stream_ResetPosition(s);
1984 rdpdr->common.totalLength = 0;
1985
1986 if (Stream_Length(s) != totalSize)
1987 {
1988 SERVER_RX_LOG(rdpdr->log, WLOG_WARN,
1989 "Received invalid %s channel data (client -> proxy), expected %" PRIuz
1990 "bytes, got %" PRIuz,
1991 channel_name, totalSize, Stream_Length(s));
1992 return FALSE;
1993 }
1994
1995 rdpdr_dump_received_packet(rdpdr->log, WLOG_TRACE, s, proxy_client_rx);
1996 switch (rdpdr->state)
1997 {
1998 case STATE_SERVER_EXPECT_CLIENT_ANNOUNCE_REPLY:
1999 if (rdpdr_process_client_announce_reply(rdpdr, s) != CHANNEL_RC_OK)
2000 return FALSE;
2001 rdpdr->state = STATE_SERVER_EXPECT_CLIENT_NAME_REQUEST;
2002 break;
2003 case STATE_SERVER_EXPECT_CLIENT_NAME_REQUEST:
2004 if (rdpdr_process_client_name_request(rdpdr, s, pc) != CHANNEL_RC_OK)
2005 return FALSE;
2006 if (rdpdr_send_server_capability_request(rdpdr) != CHANNEL_RC_OK)
2007 return FALSE;
2008 if (rdpdr_send_server_clientid_confirm(rdpdr) != CHANNEL_RC_OK)
2009 return FALSE;
2010 rdpdr->state = STATE_SERVER_EXPECT_EXPECT_CLIENT_CAPABILITY_RESPONE;
2011 break;
2012 case STATE_SERVER_EXPECT_EXPECT_CLIENT_CAPABILITY_RESPONE:
2013 if (rdpdr_process_client_capability_response(rdpdr, s) != CHANNEL_RC_OK)
2014 return FALSE;
2015 rdpdr->state = STATE_SERVER_CHANNEL_RUNNING;
2016 break;
2017 case STATE_SERVER_CHANNEL_RUNNING:
2018#if defined(WITH_PROXY_EMULATE_SMARTCARD)
2019 if (!pf_channel_smartcard_client_emulate(pc) ||
2020 !filter_smartcard_device_list_announce_request(rdpdr, s))
2021 {
2022 if (!pf_channel_rdpdr_client_pass_message(ps, pc, channelId, channel_name, s))
2023 return FALSE;
2024 }
2025 else
2026 return pf_channel_smartcard_server_handle(ps, s);
2027#else
2028 if (!pf_channel_rdpdr_client_pass_message(ps, pc, channelId, channel_name, s))
2029 return FALSE;
2030#endif
2031 break;
2032 default:
2033 case STATE_SERVER_INITIAL:
2034 SERVER_RX_LOG(rdpdr->log, WLOG_WARN, "Invalid state %s",
2035 rdpdr_server_state_to_string(rdpdr->state));
2036 return FALSE;
2037 }
2038
2039 return TRUE;
2040}
2041
2042BOOL pf_channel_rdpdr_server_announce(pServerContext* ps)
2043{
2044 pf_channel_server_context* rdpdr = get_channel(ps, TRUE);
2045 if (!rdpdr)
2046 return FALSE;
2047
2048 WINPR_ASSERT(rdpdr->state == STATE_SERVER_INITIAL);
2049 if (rdpdr_server_send_announce_request(rdpdr) != CHANNEL_RC_OK)
2050 return FALSE;
2051 rdpdr->state = STATE_SERVER_EXPECT_CLIENT_ANNOUNCE_REPLY;
2052 return TRUE;
2053}
2054
2055BOOL pf_channel_rdpdr_client_reset(pClientContext* pc)
2056{
2057 pf_channel_client_context* rdpdr = nullptr;
2058
2059 WINPR_ASSERT(pc);
2060 WINPR_ASSERT(pc->pdata);
2061 WINPR_ASSERT(pc->interceptContextMap);
2062
2063 rdpdr = HashTable_GetItemValue(pc->interceptContextMap, RDPDR_SVC_CHANNEL_NAME);
2064 if (!rdpdr)
2065 return TRUE;
2066
2067 Queue_Clear(rdpdr->queue);
2068 rdpdr->flags = 0;
2069 rdpdr->state = STATE_CLIENT_EXPECT_SERVER_ANNOUNCE_REQUEST;
2070
2071 return TRUE;
2072}
2073
2074WINPR_ATTR_NODISCARD
2075static PfChannelResult pf_rdpdr_back_data(proxyData* pdata,
2076 const pServerStaticChannelContext* channel,
2077 const BYTE* xdata, size_t xsize, UINT32 flags,
2078 size_t totalSize)
2079{
2080 WINPR_ASSERT(pdata);
2081 WINPR_ASSERT(channel);
2082
2083 pClientContext* pc = proxy_data_get_client_context(pdata);
2084 if (!pf_channel_rdpdr_client_handle(pc,
2085 WINPR_ASSERTING_INT_CAST(UINT16, channel->back_channel_id),
2086 channel->channel_name, xdata, xsize, flags, totalSize))
2087 return PF_CHANNEL_RESULT_ERROR;
2088
2089#if defined(WITH_PROXY_EMULATE_SMARTCARD)
2090 if (pf_channel_smartcard_client_emulate((pClientContext*)pdata->pc))
2091 return PF_CHANNEL_RESULT_DROP;
2092#endif
2093 return PF_CHANNEL_RESULT_DROP;
2094}
2095
2096WINPR_ATTR_NODISCARD
2097static PfChannelResult pf_rdpdr_front_data(proxyData* pdata,
2098 const pServerStaticChannelContext* channel,
2099 const BYTE* xdata, size_t xsize, UINT32 flags,
2100 size_t totalSize)
2101{
2102 WINPR_ASSERT(pdata);
2103 WINPR_ASSERT(channel);
2104
2105 pServerContext* ps = proxy_data_get_server_context(pdata);
2106 if (!pf_channel_rdpdr_server_handle(ps,
2107 WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id),
2108 channel->channel_name, xdata, xsize, flags, totalSize))
2109 return PF_CHANNEL_RESULT_ERROR;
2110
2111#if defined(WITH_PROXY_EMULATE_SMARTCARD)
2112 if (pf_channel_smartcard_client_emulate((pClientContext*)pdata->pc))
2113 return PF_CHANNEL_RESULT_DROP;
2114#endif
2115 return PF_CHANNEL_RESULT_DROP;
2116}
2117
2118BOOL pf_channel_setup_rdpdr(pServerContext* ps, pServerStaticChannelContext* channel)
2119{
2120 channel->onBackData = pf_rdpdr_back_data;
2121 channel->onFrontData = pf_rdpdr_front_data;
2122
2123 if (!pf_channel_rdpdr_server_new(ps))
2124 return FALSE;
2125 if (!pf_channel_rdpdr_server_announce(ps))
2126 return FALSE;
2127
2128 return TRUE;
2129}
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_NEW_FN fnObjectNew
Definition collections.h:54