FreeRDP
Loading...
Searching...
No Matches
activation.c
1
20#include <freerdp/config.h>
21
22#include "settings.h"
23
24#include <winpr/assert.h>
25#include <winpr/cast.h>
26
27#include "activation.h"
28#include "display.h"
29
30#define TAG FREERDP_TAG("core.activation")
31
32WINPR_ATTR_NODISCARD
33static BOOL rdp_recv_client_font_list_pdu(wStream* s);
34
35WINPR_ATTR_NODISCARD
36static BOOL rdp_recv_client_persistent_key_list_pdu(wStream* s);
37
38WINPR_ATTR_NODISCARD
39static BOOL rdp_send_server_font_map_pdu(rdpRdp* rdp);
40
41WINPR_ATTR_NODISCARD
42static BOOL rdp_write_synchronize_pdu(wStream* s, const rdpSettings* settings)
43{
44 const UINT32 PduSource = freerdp_settings_get_uint32(settings, FreeRDP_PduSource);
45
46 if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 4))
47 return FALSE;
48 Stream_Write_UINT16(s, SYNCMSGTYPE_SYNC); /* messageType (2 bytes) */
49 Stream_Write_UINT16(s,
50 WINPR_ASSERTING_INT_CAST(uint16_t, PduSource)); /* targetUser (2 bytes) */
51 return TRUE;
52}
53
54WINPR_ATTR_NODISCARD
55static BOOL rdp_recv_sync_pdu(rdpRdp* rdp, wStream* s, const char* what)
56{
57 UINT16 msgType = 0;
58 UINT16 targetUser = 0;
59
60 WINPR_UNUSED(rdp);
61 if (!Stream_CheckAndLogRequiredLengthEx(TAG, WLOG_WARN, s, 4, 1, "%s(%s:%" PRIuz ") %s",
62 __func__, __FILE__, (size_t)__LINE__, what))
63 return FALSE;
64 Stream_Read_UINT16(s, msgType);
65 if (msgType != SYNCMSGTYPE_SYNC)
66 {
67 WLog_WARN(TAG, "%s: Invalid messageType=0x%04" PRIx16 ", expected 0x%04" PRIx16, what,
68 msgType, WINPR_CXX_COMPAT_CAST(uint16_t, SYNCMSGTYPE_SYNC));
69 return FALSE;
70 }
71 Stream_Read_UINT16(s, targetUser);
72 WLog_VRB(TAG, "%s: targetUser=0x%04" PRIx16, what, targetUser);
73 return TRUE;
74}
75
76BOOL rdp_recv_server_synchronize_pdu(rdpRdp* rdp, wStream* s)
77{
78 if (!rdp_recv_sync_pdu(rdp, s, "[MS-RDPBCGR] 2.2.1.19 Server Synchronize PDU"))
79 return FALSE;
80 return rdp_finalize_set_flag(rdp, FINALIZE_SC_SYNCHRONIZE_PDU);
81}
82
83BOOL rdp_send_server_synchronize_pdu(rdpRdp* rdp)
84{
85 UINT16 sec_flags = 0;
86 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
87 if (!s)
88 return FALSE;
89
90 WINPR_ASSERT(rdp);
91 if (!rdp_write_synchronize_pdu(s, rdp->settings))
92 {
93 Stream_Free(s, TRUE);
94 return FALSE;
95 }
96
97 WINPR_ASSERT(rdp->mcs);
98 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SYNCHRONIZE, rdp->mcs->userId, sec_flags);
99}
100
101BOOL rdp_recv_client_synchronize_pdu(rdpRdp* rdp, wStream* s)
102{
103 if (!rdp_recv_sync_pdu(rdp, s, "[MS-RDPBCGR] 2.2.1.14 Client Synchronize PDU"))
104 return FALSE;
105 return rdp_finalize_set_flag(rdp, FINALIZE_CS_SYNCHRONIZE_PDU);
106}
107
108BOOL rdp_send_client_synchronize_pdu(rdpRdp* rdp)
109{
110 UINT16 sec_flags = 0;
111 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
112 if (!s)
113 return FALSE;
114
115 WINPR_ASSERT(rdp);
116 if (!rdp_write_synchronize_pdu(s, rdp->settings))
117 {
118 Stream_Free(s, TRUE);
119 return FALSE;
120 }
121
122 WINPR_ASSERT(rdp->mcs);
123 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SYNCHRONIZE, rdp->mcs->userId, sec_flags);
124}
125
126WINPR_ATTR_NODISCARD
127static BOOL rdp_recv_control_pdu(wStream* s, UINT16* action, UINT16* grantId, UINT32* controlId)
128{
129 WINPR_ASSERT(s);
130 WINPR_ASSERT(action);
131 WINPR_ASSERT(grantId);
132 WINPR_ASSERT(controlId);
133
134 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
135 return FALSE;
136
137 Stream_Read_UINT16(s, *action); /* action (2 bytes) */
138 Stream_Read_UINT16(s, *grantId); /* grantId (2 bytes) */
139 Stream_Read_UINT32(s, *controlId); /* controlId (4 bytes) */
140 return TRUE;
141}
142
143WINPR_ATTR_NODISCARD
144static BOOL rdp_write_client_control_pdu(wStream* s, UINT16 action, UINT16 grantId,
145 UINT32 controlId)
146{
147 WINPR_ASSERT(s);
148 if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
149 return FALSE;
150 Stream_Write_UINT16(s, action); /* action (2 bytes) */
151 Stream_Write_UINT16(s, grantId); /* grantId (2 bytes) */
152 Stream_Write_UINT32(s, controlId); /* controlId (4 bytes) */
153 return TRUE;
154}
155
156BOOL rdp_recv_server_control_pdu(rdpRdp* rdp, wStream* s)
157{
158 UINT16 action = 0;
159 UINT16 grantId = 0;
160 UINT32 controlId = 0;
161
162 WINPR_ASSERT(rdp);
163 WINPR_ASSERT(s);
164
165 if (!rdp_recv_control_pdu(s, &action, &grantId, &controlId))
166 return FALSE;
167
168 switch (action)
169 {
170 case CTRLACTION_COOPERATE:
171 return rdp_finalize_set_flag(rdp, FINALIZE_SC_CONTROL_COOPERATE_PDU);
172
173 case CTRLACTION_GRANTED_CONTROL:
174 rdp->resendFocus = TRUE;
175 return rdp_finalize_set_flag(rdp, FINALIZE_SC_CONTROL_GRANTED_PDU);
176 default:
177 {
178 char buffer[128] = WINPR_C_ARRAY_INIT;
179 WLog_WARN(TAG, "Unexpected control PDU %s",
180 rdp_ctrlaction_string(action, buffer, sizeof(buffer)));
181
182 return FALSE;
183 }
184 }
185}
186
187BOOL rdp_send_server_control_cooperate_pdu(rdpRdp* rdp)
188{
189 UINT16 sec_flags = 0;
190 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
191 if (!s)
192 return FALSE;
193 if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
194 {
195 Stream_Free(s, TRUE);
196 return FALSE;
197 }
198 Stream_Write_UINT16(s, CTRLACTION_COOPERATE); /* action (2 bytes) */
199 Stream_Write_UINT16(s, 0); /* grantId (2 bytes) */
200 Stream_Write_UINT32(s, 0); /* controlId (4 bytes) */
201
202 WINPR_ASSERT(rdp->mcs);
203 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->userId, sec_flags);
204}
205
206BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp)
207{
208 UINT16 sec_flags = 0;
209 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
210 if (!s)
211 return FALSE;
212 if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
213 {
214 Stream_Free(s, TRUE);
215 return FALSE;
216 }
217
218 WINPR_ASSERT(rdp->mcs);
219 Stream_Write_UINT16(s, CTRLACTION_GRANTED_CONTROL); /* action (2 bytes) */
220 Stream_Write_UINT16(s, rdp->mcs->userId); /* grantId (2 bytes) */
221 Stream_Write_UINT32(s, 0x03EA); /* controlId (4 bytes) */
222 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->userId, sec_flags);
223}
224
225BOOL rdp_send_client_control_pdu(rdpRdp* rdp, UINT16 action)
226{
227 UINT16 GrantId = 0;
228 UINT16 ControlId = 0;
229
230 switch (action)
231 {
232 case CTRLACTION_COOPERATE:
233 case CTRLACTION_REQUEST_CONTROL:
234 break;
235 default:
236 WLog_WARN(TAG,
237 "Invalid client control PDU::action 0x%04" PRIx16 ", not allowed by client",
238 action);
239 return FALSE;
240 }
241
242 UINT16 sec_flags = 0;
243 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
244 if (!s)
245 return FALSE;
246 if (!rdp_write_client_control_pdu(s, action, GrantId, ControlId))
247 {
248 Stream_Free(s, TRUE);
249 return FALSE;
250 }
251
252 WINPR_ASSERT(rdp->mcs);
253 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->userId, sec_flags);
254}
255
256WINPR_ATTR_NODISCARD
257static BOOL rdp_write_client_persistent_key_list_pdu(wStream* s, UINT8 flags,
258 const RDP_BITMAP_PERSISTENT_INFO* info)
259{
260 WINPR_ASSERT(s);
261 WINPR_ASSERT(info);
262
263 if (!Stream_EnsureRemainingCapacity(s, 24))
264 return FALSE;
265
266 Stream_Write_UINT16(s, info->numEntriesCache0); /* numEntriesCache0 (2 bytes) */
267 Stream_Write_UINT16(s, info->numEntriesCache1); /* numEntriesCache1 (2 bytes) */
268 Stream_Write_UINT16(s, info->numEntriesCache2); /* numEntriesCache2 (2 bytes) */
269 Stream_Write_UINT16(s, info->numEntriesCache3); /* numEntriesCache3 (2 bytes) */
270 Stream_Write_UINT16(s, info->numEntriesCache4); /* numEntriesCache4 (2 bytes) */
271 Stream_Write_UINT16(s, info->totalEntriesCache0); /* totalEntriesCache0 (2 bytes) */
272 Stream_Write_UINT16(s, info->totalEntriesCache1); /* totalEntriesCache1 (2 bytes) */
273 Stream_Write_UINT16(s, info->totalEntriesCache2); /* totalEntriesCache2 (2 bytes) */
274 Stream_Write_UINT16(s, info->totalEntriesCache3); /* totalEntriesCache3 (2 bytes) */
275 Stream_Write_UINT16(s, info->totalEntriesCache4); /* totalEntriesCache4 (2 bytes) */
276 Stream_Write_UINT8(s, flags); /* bBitMask (1 byte) */
277 Stream_Write_UINT8(s, 0); /* pad1 (1 byte) */
278 Stream_Write_UINT16(s, 0); /* pad3 (2 bytes) */
279 /* entries */
280
281 if (!Stream_CheckAndLogRequiredCapacityOfSize(TAG, s, info->keyCount, sizeof(UINT64)))
282 return FALSE;
283
284 for (UINT32 index = 0; index < info->keyCount; index++)
285 {
286 const UINT64 val = info->keyList[index];
287 Stream_Write_UINT64(s, val);
288 }
289
290 return TRUE;
291}
292
293WINPR_ATTR_NODISCARD
294static BOOL rdp_send_persistent_key_list_pdu(rdpRdp* rdp, UINT8 flags,
295 const RDP_BITMAP_PERSISTENT_INFO* info)
296{
297 WINPR_ASSERT(rdp);
298 WINPR_ASSERT(info);
299
300 UINT16 sec_flags = 0;
301 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
302
303 if (!s)
304 return FALSE;
305
306 if (!rdp_write_client_persistent_key_list_pdu(s, flags, info))
307 {
308 Stream_Free(s, TRUE);
309 return FALSE;
310 }
311
312 WINPR_ASSERT(rdp->mcs);
313
314 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST, rdp->mcs->userId,
315 sec_flags);
316}
317
318WINPR_ATTR_NODISCARD
319static UINT16 rdp_load_persistent_key_list(rdpRdp* rdp, UINT64** pKeyList)
320{
321 UINT16 keyCount = 0;
322 UINT64* keyList = nullptr;
323
324 WINPR_ASSERT(rdp);
325 WINPR_ASSERT(pKeyList);
326 rdpSettings* settings = rdp->settings;
327
328 *pKeyList = nullptr;
329
330 if (!freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
331 return 0;
332
333 if (!settings->BitmapCachePersistFile)
334 return 0;
335
336 rdpPersistentCache* persistent = persistent_cache_new();
337
338 if (!persistent)
339 return 0;
340
341 const int status =
342 persistent_cache_open(persistent, settings->BitmapCachePersistFile, FALSE, 0);
343
344 if (status < 1)
345 goto error;
346
347 {
348 const int count = persistent_cache_get_count(persistent);
349 if ((count < 0) || (count > UINT16_MAX))
350 goto error;
351
352 keyCount = (UINT16)count;
353 keyList = (UINT64*)calloc(keyCount, sizeof(UINT64));
354
355 if (!keyList)
356 goto error;
357
358 for (int index = 0; index < count; index++)
359 {
360 PERSISTENT_CACHE_ENTRY cacheEntry = WINPR_C_ARRAY_INIT;
361
362 if (persistent_cache_read_entry(persistent, &cacheEntry) < 1)
363 continue;
364
365 keyList[index] = cacheEntry.key64;
366 }
367 }
368
369 *pKeyList = keyList;
370
371 persistent_cache_free(persistent);
372 return keyCount;
373error:
374 persistent_cache_free(persistent);
375 free(keyList);
376 return 0;
377}
378
379WINPR_ATTR_NODISCARD
380static RDP_BITMAP_PERSISTENT_INFO rdp_persist_update(UINT32 offset, UINT16 step,
381 const RDP_BITMAP_PERSISTENT_INFO* info)
382{
383 WINPR_ASSERT(info);
384
385 const UINT16 maxSlots = step;
386 RDP_BITMAP_PERSISTENT_INFO copy = *info;
387 copy.keyList = &info->keyList[offset];
388
389 if (offset < info->totalEntriesCache0)
390 {
391 copy.numEntriesCache0 =
392 MIN(step, WINPR_ASSERTING_INT_CAST(UINT16, (info->totalEntriesCache0 - offset)));
393 step -= copy.numEntriesCache0;
394 offset += copy.numEntriesCache0;
395 }
396
397 if (offset < 1ull * info->totalEntriesCache0 + info->totalEntriesCache1)
398 {
399 copy.numEntriesCache1 =
400 MIN(step, WINPR_ASSERTING_INT_CAST(UINT16, (info->totalEntriesCache1 - offset)));
401 step -= copy.numEntriesCache1;
402 offset += copy.numEntriesCache1;
403 }
404 if (offset <
405 1ull * info->totalEntriesCache0 + info->totalEntriesCache1 + info->totalEntriesCache2)
406 {
407 copy.numEntriesCache2 =
408 MIN(step, WINPR_ASSERTING_INT_CAST(UINT16, (info->totalEntriesCache2 - offset)));
409 step -= copy.numEntriesCache3;
410 }
411 if (offset < 1ull * info->totalEntriesCache0 + info->totalEntriesCache1 +
412 info->totalEntriesCache2 + info->totalEntriesCache3)
413 {
414 copy.numEntriesCache3 =
415 MIN(step, WINPR_ASSERTING_INT_CAST(UINT16, (info->totalEntriesCache3 - offset)));
416 step -= copy.numEntriesCache3;
417 }
418 if (offset < 1ull * info->totalEntriesCache0 + info->totalEntriesCache1 +
419 info->totalEntriesCache2 + info->totalEntriesCache3 + info->totalEntriesCache4)
420 {
421 copy.numEntriesCache4 =
422 MIN(step, WINPR_ASSERTING_INT_CAST(UINT16, (info->totalEntriesCache4 - offset)));
423 step -= copy.numEntriesCache4;
424 }
425 copy.keyCount = maxSlots - step;
426 return copy;
427}
428
429BOOL rdp_send_client_persistent_key_list_pdu(rdpRdp* rdp)
430{
431 WINPR_ASSERT(rdp);
432
433 rdpSettings* settings = rdp->settings;
434 const UINT32 cellInfoCount =
435 freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheV2NumCells);
436 if (cellInfoCount != 5)
437 {
438 WLog_ERR(TAG, "BitmapCacheV2NumCells %" PRIu32 ", but must be 5. Aborting.", cellInfoCount);
439 return FALSE;
440 }
441
442 UINT64* keyList = nullptr;
443 RDP_BITMAP_PERSISTENT_INFO info = WINPR_C_ARRAY_INIT;
444 const UINT16 keyCount = rdp_load_persistent_key_list(rdp, &keyList);
445
446 WLog_DBG(TAG, "Persistent Key List: TotalKeyCount: %" PRIu16, keyCount);
447
448 info.totalEntriesCache0 =
449 (UINT16)MIN(UINT16_MAX, settings->BitmapCacheV2CellInfo[0].numEntries);
450 info.totalEntriesCache1 =
451 (UINT16)MIN(UINT16_MAX, settings->BitmapCacheV2CellInfo[1].numEntries);
452 info.totalEntriesCache2 =
453 (UINT16)MIN(UINT16_MAX, settings->BitmapCacheV2CellInfo[2].numEntries);
454 info.totalEntriesCache3 =
455 (UINT16)MIN(UINT16_MAX, settings->BitmapCacheV2CellInfo[3].numEntries);
456 info.totalEntriesCache4 =
457 (UINT16)MIN(UINT16_MAX, settings->BitmapCacheV2CellInfo[4].numEntries);
458
459 info.keyCount = keyCount;
460 info.keyList = keyList;
461
462 WLog_DBG(TAG, "persistentKeyList count: %" PRIu32, info.keyCount);
463
464 WLog_DBG(TAG,
465 "numEntriesCache: [0]: %" PRIu16 " [1]: %" PRIu16 " [2]: %" PRIu16 " [3]: %" PRIu16
466 " [4]: %" PRIu16,
467 info.numEntriesCache0, info.numEntriesCache1, info.numEntriesCache2,
468 info.numEntriesCache3, info.numEntriesCache4);
469
470 WLog_DBG(TAG,
471 "totalEntriesCache: [0]: %" PRIu16 " [1]: %" PRIu16 " [2]: %" PRIu16 " [3]: %" PRIu16
472 " [4]: %" PRIu16,
473 info.totalEntriesCache0, info.totalEntriesCache1, info.totalEntriesCache2,
474 info.totalEntriesCache3, info.totalEntriesCache4);
475
476 BOOL res = TRUE;
477 const UINT16 maxKeysPerPDU = 169;
478 for (UINT32 offset = 0; offset < info.keyCount; offset += maxKeysPerPDU)
479 {
480 const UINT16 curKeysPerPDU = (offset + maxKeysPerPDU) > info.keyCount
481 ? (UINT16)(info.keyCount - offset)
482 : maxKeysPerPDU;
483 RDP_BITMAP_PERSISTENT_INFO cur = rdp_persist_update(offset, curKeysPerPDU, &info);
484
485 UINT8 flags = 0;
486 if (offset == 0)
487 flags |= PERSIST_FIRST_PDU;
488 if (offset + curKeysPerPDU >= info.keyCount)
489 flags |= PERSIST_LAST_PDU;
490 res = rdp_send_persistent_key_list_pdu(rdp, flags, &cur);
491 if (!res)
492 break;
493 }
494 free(keyList);
495 return res;
496}
497
498BOOL rdp_recv_client_font_list_pdu(wStream* s)
499{
500 WINPR_ASSERT(s);
501 /* 2.2.1.18 Client Font List PDU */
502 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
503 return FALSE;
504
505 return Stream_SafeSeek(s, 8);
506}
507
508BOOL rdp_recv_client_persistent_key_list_pdu(wStream* s)
509{
510 BYTE flags = 0;
511 size_t count = 0;
512 size_t total = 0;
513 UINT16 cache = 0;
514
515 WINPR_ASSERT(s);
516
517 /* 2.2.1.17.1 Persistent Key List PDU Data (TS_BITMAPCACHE_PERSISTENT_LIST_PDU) */
518 if (!Stream_CheckAndLogRequiredLength(TAG, s, 21))
519 {
520 WLog_ERR(TAG, "short TS_BITMAPCACHE_PERSISTENT_LIST_PDU, need 21 bytes, got %" PRIuz,
521 Stream_GetRemainingLength(s));
522 return FALSE;
523 }
524 /* Read numEntriesCacheX for variable length data in PDU */
525 for (size_t x = 0; x < 5; x++)
526 {
527 Stream_Read_UINT16(s, cache);
528 count += cache;
529 }
530
531 /* Skip totalEntriesCacheX */
532 for (size_t x = 0; x < 5; x++)
533 {
534 UINT16 tmp = 0;
535 Stream_Read_UINT16(s, tmp);
536 total += tmp;
537 }
538
539 if (total > 262144)
540 {
541 WLog_ERR(TAG,
542 "TS_BITMAPCACHE_PERSISTENT_LIST_PDU::totalEntriesCacheX exceeds 262144 entries");
543 return FALSE;
544 }
545
546 Stream_Read_UINT8(s, flags);
547 if ((flags & ~(PERSIST_LAST_PDU | PERSIST_FIRST_PDU)) != 0)
548 {
549 WLog_ERR(TAG,
550 "TS_BITMAPCACHE_PERSISTENT_LIST_PDU::bBitMask has an invalid value of 0x%02" PRIx8,
551 flags);
552 return FALSE;
553 }
554
555 /* Skip padding */
556 if (!Stream_SafeSeek(s, 3))
557 {
558 WLog_ERR(TAG, "short TS_BITMAPCACHE_PERSISTENT_LIST_PDU, need 3 bytes, got %" PRIuz,
559 Stream_GetRemainingLength(s));
560 return FALSE;
561 }
562 /* Skip actual entries sent by client */
563 if (!Stream_SafeSeek(s, count * sizeof(UINT64)))
564 {
565 WLog_ERR(TAG,
566 "short TS_BITMAPCACHE_PERSISTENT_LIST_PDU, need %" PRIuz " bytes, got %" PRIuz,
567 count * sizeof(UINT64), Stream_GetRemainingLength(s));
568 return FALSE;
569 }
570 return TRUE;
571}
572
573WINPR_ATTR_NODISCARD
574static BOOL rdp_write_client_font_list_pdu(wStream* s, UINT16 flags)
575{
576 WINPR_ASSERT(s);
577
578 if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
579 return FALSE;
580 Stream_Write_UINT16(s, 0); /* numberFonts (2 bytes) */
581 Stream_Write_UINT16(s, 0); /* totalNumFonts (2 bytes) */
582 Stream_Write_UINT16(s, flags); /* listFlags (2 bytes) */
583 Stream_Write_UINT16(s, 50); /* entrySize (2 bytes) */
584 return TRUE;
585}
586
587BOOL rdp_send_client_font_list_pdu(rdpRdp* rdp, UINT16 flags)
588{
589 UINT16 sec_flags = 0;
590 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
591 if (!s)
592 return FALSE;
593 if (!rdp_write_client_font_list_pdu(s, flags))
594 {
595 Stream_Free(s, TRUE);
596 return FALSE;
597 }
598
599 WINPR_ASSERT(rdp->mcs);
600 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FONT_LIST, rdp->mcs->userId, sec_flags);
601}
602
603BOOL rdp_recv_font_map_pdu(rdpRdp* rdp, wStream* s)
604{
605 UINT16 numberEntries = 0;
606 UINT16 totalNumEntries = 0;
607 UINT16 mapFlags = 0;
608 UINT16 entrySize = 0;
609
610 WINPR_ASSERT(rdp);
611 WINPR_ASSERT(rdp->settings);
612 WINPR_ASSERT(s);
613 WINPR_ASSERT(!freerdp_settings_get_bool(rdp->settings, FreeRDP_ServerMode));
614
615 if (!rdp_has_reached_state(rdp, CONNECTION_STATE_FINALIZATION_CLIENT_FONT_MAP))
616 return FALSE;
617
618 /* Do not fail here, see https://github.com/FreeRDP/FreeRDP/issues/925 */
619 if (Stream_CheckAndLogRequiredLength(TAG, s, 8))
620 {
621 Stream_Read_UINT16(s, numberEntries); /* numberEntries (2 bytes) */
622 if (numberEntries != 0)
623 WLog_WARN(
624 TAG,
625 "[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU)::numberEntries != 0 "
626 "[%" PRIu16 "]",
627 numberEntries);
628 Stream_Read_UINT16(s, totalNumEntries); /* totalNumEntries (2 bytes) */
629 if (totalNumEntries != 0)
630 WLog_WARN(
631 TAG,
632 "[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU)::totalNumEntries != "
633 "0 [%" PRIu16 "]",
634 totalNumEntries);
635 Stream_Read_UINT16(s, mapFlags); /* mapFlags (2 bytes) */
636 if (mapFlags != (FONTLIST_FIRST | FONTLIST_LAST))
637 WLog_WARN(
638 TAG,
639 "[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU)::mapFlags != 0x0003 "
640 "(FONTLIST_FIRST | FONTLIST_LAST) "
641 "[0x%04" PRIx16 "]",
642 mapFlags);
643 Stream_Read_UINT16(s, entrySize); /* entrySize (2 bytes) */
644 if (entrySize != 4)
645 WLog_WARN(TAG,
646 "[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU)::entrySize != 4 "
647 "[%" PRIu16 "]",
648 entrySize);
649 }
650 else
651 WLog_WARN(TAG,
652 "[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU) paylaod size is "
653 "0 instead of 8");
654
655 return rdp_finalize_set_flag(rdp, FINALIZE_SC_FONT_MAP_PDU);
656}
657
658BOOL rdp_send_server_font_map_pdu(rdpRdp* rdp)
659{
660 UINT16 sec_flags = 0;
661 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
662 if (!s)
663 return FALSE;
664 if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
665 {
666 Stream_Free(s, TRUE);
667 return FALSE;
668 }
669 Stream_Write_UINT16(s, 0); /* numberEntries (2 bytes) */
670 Stream_Write_UINT16(s, 0); /* totalNumEntries (2 bytes) */
671 Stream_Write_UINT16(s, FONTLIST_FIRST | FONTLIST_LAST); /* mapFlags (2 bytes) */
672 Stream_Write_UINT16(s, 4); /* entrySize (2 bytes) */
673
674 WINPR_ASSERT(rdp->mcs);
675 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FONT_MAP, rdp->mcs->userId, sec_flags);
676}
677
678BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s)
679{
680 UINT16 lengthSourceDescriptor = 0;
681
682 WINPR_ASSERT(rdp);
683 WINPR_ASSERT(s);
684
685 if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE)
686 {
687 if (!rdp_finalize_set_flag(rdp, FINALIZE_DEACTIVATE_REACTIVATE))
688 return FALSE;
689
690 rdp->was_deactivated = TRUE;
691 rdp->deactivated_height = freerdp_settings_get_uint32(rdp->settings, FreeRDP_DesktopHeight);
692 rdp->deactivated_width = freerdp_settings_get_uint32(rdp->settings, FreeRDP_DesktopWidth);
693 }
694
695 /*
696 * Windows XP can send short DEACTIVATE_ALL PDU that doesn't contain
697 * the following fields.
698 */
699
700 WINPR_ASSERT(rdp->settings);
701 if (Stream_GetRemainingLength(s) > 0)
702 {
703 do
704 {
705 UINT32 ShareId = 0;
706 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
707 break;
708
709 Stream_Read_UINT32(s, ShareId); /* shareId (4 bytes) */
710 if (!freerdp_settings_set_uint32(rdp->settings, FreeRDP_ShareId, ShareId))
711 return FALSE;
712
713 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
714 break;
715
716 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
717
718 if (!Stream_CheckAndLogRequiredLength(TAG, s, lengthSourceDescriptor))
719 break;
720
721 Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor (should be 0x00) */
722 } while (0);
723 }
724
725 return rdp_client_transition_to_state(rdp,
726 CONNECTION_STATE_CAPABILITIES_EXCHANGE_DEMAND_ACTIVE);
727}
728
729BOOL rdp_send_deactivate_all(rdpRdp* rdp)
730{
731 WINPR_ASSERT(rdp);
732 WINPR_ASSERT(rdp->mcs);
733
734 if (rdp->mcs->userId == 0)
735 {
736 WLog_Print(rdp->log, WLOG_WARN,
737 "rdpMcs::userId == 0, skip sending PDU_TYPE_DEACTIVATE_ALL");
738 return TRUE;
739 }
740
741 UINT16 sec_flags = 0;
742 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
743 BOOL status = FALSE;
744
745 if (!s)
746 return FALSE;
747
748 if (!Stream_CheckAndLogRequiredCapacityWLog(rdp->log, (s), 7))
749 goto fail;
750
751 WINPR_ASSERT(rdp->settings);
752 {
753 const UINT32 ShareId = freerdp_settings_get_uint32(rdp->settings, FreeRDP_ShareId);
754 Stream_Write_UINT32(s, ShareId); /* shareId (4 bytes) */
755 }
756 Stream_Write_UINT16(s, 1); /* lengthSourceDescriptor (2 bytes) */
757 Stream_Write_UINT8(s, 0); /* sourceDescriptor (should be 0x00) */
758
759 WINPR_ASSERT(rdp->mcs);
760 status = rdp_send_pdu(rdp, s, PDU_TYPE_DEACTIVATE_ALL, rdp->mcs->userId, sec_flags);
761fail:
762 Stream_Release(s);
763 return status;
764}
765
766BOOL rdp_server_accept_client_control_pdu(rdpRdp* rdp, wStream* s)
767{
768 UINT16 action = 0;
769 UINT16 GrantId = 0;
770 UINT32 ControlId = 0;
771 const CONNECTION_STATE state = rdp_get_state(rdp);
772
773 WINPR_ASSERT(rdp);
774 WINPR_ASSERT(s);
775
776 if (!rdp_recv_control_pdu(s, &action, &GrantId, &ControlId))
777 return FALSE;
778
779 switch (action)
780 {
781
782 case CTRLACTION_REQUEST_CONTROL:
783 if (!rdp_finalize_is_flag_set(rdp, FINALIZE_CS_CONTROL_COOPERATE_PDU))
784 {
785 char abuffer[128] = WINPR_C_ARRAY_INIT;
786 char buffer[1024] = WINPR_C_ARRAY_INIT;
787 WLog_WARN(TAG,
788 "Received action=%s with GrantId=0x%04" PRIx16 ", ControlId=0x%08" PRIx32
789 " in unexpected state %s [missing %s]",
790 rdp_ctrlaction_string(action, abuffer, sizeof(abuffer)), GrantId,
791 ControlId, rdp_state_string(state),
792 rdp_finalize_flags_to_str(FINALIZE_CS_CONTROL_COOPERATE_PDU, buffer,
793 sizeof(buffer)));
794 return FALSE;
795 }
796 if ((GrantId != 0) || (ControlId != 0))
797 {
798 WLog_WARN(TAG,
799 "Received CTRLACTION_COOPERATE with GrantId=0x%04" PRIx16
800 " != 0x00, ControlId=0x%08" PRIx32 " != 0x00",
801 GrantId, ControlId);
802 return FALSE;
803 }
804 return rdp_finalize_set_flag(rdp, FINALIZE_CS_CONTROL_REQUEST_PDU);
805 case CTRLACTION_COOPERATE:
806 if (!rdp_finalize_is_flag_set(rdp, FINALIZE_CS_SYNCHRONIZE_PDU))
807 {
808 char abuffer[128] = WINPR_C_ARRAY_INIT;
809 char buffer[1024] = WINPR_C_ARRAY_INIT;
810 WLog_WARN(
811 TAG,
812 "Received action=%s with GrantId=0x%04" PRIx16 ", ControlId=0x%08" PRIx32
813 " in unexpected state %s [missing %s]",
814 rdp_ctrlaction_string(action, abuffer, sizeof(abuffer)), GrantId, ControlId,
815 rdp_state_string(state),
816 rdp_finalize_flags_to_str(FINALIZE_CS_SYNCHRONIZE_PDU, buffer, sizeof(buffer)));
817 return FALSE;
818 }
819 if ((GrantId != 0) || (ControlId != 0))
820 {
821 WLog_WARN(TAG,
822 "Received CTRLACTION_COOPERATE with GrantId=0x%04" PRIx16
823 " != 0x00, ControlId=0x%08" PRIx32 " != 0x00",
824 GrantId, ControlId);
825 return FALSE;
826 }
827 return rdp_finalize_set_flag(rdp, FINALIZE_CS_CONTROL_COOPERATE_PDU);
828 default:
829 {
830 char abuffer[128] = WINPR_C_ARRAY_INIT;
831 WLog_WARN(TAG,
832 "Received unexpected action=%s with GrantId=0x%04" PRIx16
833 ", ControlId=0x%08" PRIx32,
834 rdp_ctrlaction_string(action, abuffer, sizeof(abuffer)), GrantId, ControlId);
835 return FALSE;
836 }
837 }
838
839 return TRUE;
840}
841
842BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s)
843{
844 WINPR_ASSERT(rdp);
845 WINPR_ASSERT(s);
846
847 if (!rdp_recv_client_font_list_pdu(s))
848 return FALSE;
849 rdp_finalize_set_flag(rdp, FINALIZE_CS_FONT_LIST_PDU);
850
851 if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_CLIENT_FONT_MAP))
852 return FALSE;
853
854 if (!rdp_send_server_font_map_pdu(rdp))
855 return FALSE;
856
857 if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_ACTIVE))
858 return FALSE;
859
860 return TRUE;
861}
862
863BOOL rdp_server_accept_client_persistent_key_list_pdu(rdpRdp* rdp, wStream* s)
864{
865 WINPR_ASSERT(rdp);
866 WINPR_ASSERT(s);
867
868 if (!rdp_recv_client_persistent_key_list_pdu(s))
869 return FALSE;
870
871 rdp_finalize_set_flag(rdp, FINALIZE_CS_PERSISTENT_KEY_LIST_PDU);
872 // TODO: Actually do something with this
873 return TRUE;
874}
875
876const char* rdp_ctrlaction_string(UINT16 action, char* buffer, size_t size)
877{
878 const char* actstr = nullptr;
879 switch (action)
880 {
881 case CTRLACTION_COOPERATE:
882 actstr = "CTRLACTION_COOPERATE";
883 break;
884 case CTRLACTION_DETACH:
885 actstr = "CTRLACTION_DETACH";
886 break;
887 case CTRLACTION_GRANTED_CONTROL:
888 actstr = "CTRLACTION_GRANTED_CONTROL";
889 break;
890 case CTRLACTION_REQUEST_CONTROL:
891 actstr = "CTRLACTION_REQUEST_CONTROL";
892 break;
893 default:
894 actstr = "CTRLACTION_UNKNOWN";
895 break;
896 }
897
898 (void)_snprintf(buffer, size, "%s [0x%04" PRIx16 "]", actstr, action);
899 return buffer;
900}
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
Definition persistent.h:70