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