Coverage Report

Created: 2024-05-20 06:11

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