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