Coverage Report

Created: 2025-07-01 06:46

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