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