Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/channels/remdesk/client/remdesk_main.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Remote Assistance Virtual Channel
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2015 Thincast Technologies GmbH
7
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <freerdp/config.h>
23
24
#include <winpr/crt.h>
25
#include <winpr/assert.h>
26
#include <winpr/print.h>
27
28
#include <freerdp/freerdp.h>
29
#include <freerdp/assistance.h>
30
31
#include <freerdp/channels/log.h>
32
#include <freerdp/client/remdesk.h>
33
34
#include "remdesk_main.h"
35
36
/**
37
 * Function description
38
 *
39
 * @return 0 on success, otherwise a Win32 error code
40
 */
41
static UINT remdesk_virtual_channel_write(remdeskPlugin* remdesk, wStream* s)
42
0
{
43
0
  UINT32 status = 0;
44
45
0
  if (!remdesk)
46
0
  {
47
0
    WLog_ERR(TAG, "remdesk was null!");
48
0
    Stream_Free(s, TRUE);
49
0
    return CHANNEL_RC_INVALID_INSTANCE;
50
0
  }
51
52
0
  WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelWriteEx);
53
0
  status = remdesk->channelEntryPoints.pVirtualChannelWriteEx(
54
0
      remdesk->InitHandle, remdesk->OpenHandle, Stream_Buffer(s), (UINT32)Stream_Length(s), s);
55
56
0
  if (status != CHANNEL_RC_OK)
57
0
  {
58
0
    Stream_Free(s, TRUE);
59
0
    WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
60
0
             WTSErrorToString(status), status);
61
0
  }
62
0
  return status;
63
0
}
64
65
/**
66
 * Function description
67
 *
68
 * @return 0 on success, otherwise a Win32 error code
69
 */
70
static UINT remdesk_generate_expert_blob(remdeskPlugin* remdesk)
71
0
{
72
0
  const char* name = NULL;
73
0
  char* pass = NULL;
74
0
  const char* password = NULL;
75
0
  rdpSettings* settings = NULL;
76
77
0
  WINPR_ASSERT(remdesk);
78
79
0
  WINPR_ASSERT(remdesk->rdpcontext);
80
0
  settings = remdesk->rdpcontext->settings;
81
0
  WINPR_ASSERT(settings);
82
83
0
  if (remdesk->ExpertBlob)
84
0
    return CHANNEL_RC_OK;
85
86
0
  password = freerdp_settings_get_string(settings, FreeRDP_RemoteAssistancePassword);
87
0
  if (!password)
88
0
    password = freerdp_settings_get_string(settings, FreeRDP_Password);
89
90
0
  if (!password)
91
0
  {
92
0
    WLog_ERR(TAG, "password was not set!");
93
0
    return ERROR_INTERNAL_ERROR;
94
0
  }
95
96
0
  name = freerdp_settings_get_string(settings, FreeRDP_Username);
97
98
0
  if (!name)
99
0
    name = "Expert";
100
101
0
  const char* stub = freerdp_settings_get_string(settings, FreeRDP_RemoteAssistancePassStub);
102
0
  remdesk->EncryptedPassStub =
103
0
      freerdp_assistance_encrypt_pass_stub(password, stub, &(remdesk->EncryptedPassStubSize));
104
105
0
  if (!remdesk->EncryptedPassStub)
106
0
  {
107
0
    WLog_ERR(TAG, "freerdp_assistance_encrypt_pass_stub failed!");
108
0
    return ERROR_INTERNAL_ERROR;
109
0
  }
110
111
0
  pass = freerdp_assistance_bin_to_hex_string(remdesk->EncryptedPassStub,
112
0
                                              remdesk->EncryptedPassStubSize);
113
114
0
  if (!pass)
115
0
  {
116
0
    WLog_ERR(TAG, "freerdp_assistance_bin_to_hex_string failed!");
117
0
    return ERROR_INTERNAL_ERROR;
118
0
  }
119
120
0
  remdesk->ExpertBlob = freerdp_assistance_construct_expert_blob(name, pass);
121
0
  free(pass);
122
123
0
  if (!remdesk->ExpertBlob)
124
0
  {
125
0
    WLog_ERR(TAG, "freerdp_assistance_construct_expert_blob failed!");
126
0
    return ERROR_INTERNAL_ERROR;
127
0
  }
128
129
0
  return CHANNEL_RC_OK;
130
0
}
131
132
/**
133
 * Function description
134
 *
135
 * @return 0 on success, otherwise a Win32 error code
136
 */
137
static UINT remdesk_read_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header)
138
0
{
139
0
  UINT32 ChannelNameLen = 0;
140
141
0
  WINPR_ASSERT(s);
142
0
  WINPR_ASSERT(header);
143
144
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
145
0
    return ERROR_INVALID_DATA;
146
147
0
  Stream_Read_UINT32(s, ChannelNameLen);     /* ChannelNameLen (4 bytes) */
148
0
  Stream_Read_UINT32(s, header->DataLength); /* DataLen (4 bytes) */
149
150
0
  if (ChannelNameLen > 64)
151
0
  {
152
0
    WLog_ERR(TAG, "ChannelNameLen > 64!");
153
0
    return ERROR_INVALID_DATA;
154
0
  }
155
156
0
  if ((ChannelNameLen % 2) != 0)
157
0
  {
158
0
    WLog_ERR(TAG, "ChannelNameLen %% 2) != 0 ");
159
0
    return ERROR_INVALID_DATA;
160
0
  }
161
162
0
  if (Stream_Read_UTF16_String_As_UTF8_Buffer(s, ChannelNameLen / sizeof(WCHAR),
163
0
                                              header->ChannelName,
164
0
                                              ARRAYSIZE(header->ChannelName)) < 0)
165
0
    return ERROR_INTERNAL_ERROR;
166
167
0
  return CHANNEL_RC_OK;
168
0
}
169
170
/**
171
 * Function description
172
 *
173
 * @return 0 on success, otherwise a Win32 error code
174
 */
175
static UINT remdesk_write_channel_header(wStream* s, REMDESK_CHANNEL_HEADER* header)
176
0
{
177
0
  UINT32 ChannelNameLen = 0;
178
0
  WCHAR ChannelNameW[32] = { 0 };
179
180
0
  WINPR_ASSERT(s);
181
0
  WINPR_ASSERT(header);
182
183
0
  for (size_t index = 0; index < 32; index++)
184
0
  {
185
0
    ChannelNameW[index] = (WCHAR)header->ChannelName[index];
186
0
  }
187
188
0
  ChannelNameLen = (strnlen(header->ChannelName, sizeof(header->ChannelName)) + 1) * 2;
189
0
  Stream_Write_UINT32(s, ChannelNameLen);        /* ChannelNameLen (4 bytes) */
190
0
  Stream_Write_UINT32(s, header->DataLength);    /* DataLen (4 bytes) */
191
0
  Stream_Write(s, ChannelNameW, ChannelNameLen); /* ChannelName (variable) */
192
0
  return CHANNEL_RC_OK;
193
0
}
194
195
/**
196
 * Function description
197
 *
198
 * @return 0 on success, otherwise a Win32 error code
199
 */
200
static UINT remdesk_write_ctl_header(wStream* s, REMDESK_CTL_HEADER* ctlHeader)
201
0
{
202
0
  WINPR_ASSERT(s);
203
0
  WINPR_ASSERT(ctlHeader);
204
205
0
  remdesk_write_channel_header(s, &ctlHeader->ch);
206
0
  Stream_Write_UINT32(s, ctlHeader->msgType); /* msgType (4 bytes) */
207
0
  return CHANNEL_RC_OK;
208
0
}
209
210
/**
211
 * Function description
212
 *
213
 * @return 0 on success, otherwise a Win32 error code
214
 */
215
static UINT remdesk_prepare_ctl_header(REMDESK_CTL_HEADER* ctlHeader, UINT32 msgType,
216
                                       UINT32 msgSize)
217
0
{
218
0
  WINPR_ASSERT(ctlHeader);
219
220
0
  ctlHeader->msgType = msgType;
221
0
  sprintf_s(ctlHeader->ch.ChannelName, ARRAYSIZE(ctlHeader->ch.ChannelName),
222
0
            REMDESK_CHANNEL_CTL_NAME);
223
0
  ctlHeader->ch.DataLength = 4 + msgSize;
224
0
  return CHANNEL_RC_OK;
225
0
}
226
227
/**
228
 * Function description
229
 *
230
 * @return 0 on success, otherwise a Win32 error code
231
 */
232
static UINT remdesk_recv_ctl_server_announce_pdu(remdeskPlugin* remdesk, wStream* s,
233
                                                 REMDESK_CHANNEL_HEADER* header)
234
0
{
235
0
  WINPR_ASSERT(remdesk);
236
0
  WINPR_ASSERT(s);
237
0
  WINPR_ASSERT(header);
238
239
0
  return CHANNEL_RC_OK;
240
0
}
241
242
/**
243
 * Function description
244
 *
245
 * @return 0 on success, otherwise a Win32 error code
246
 */
247
static UINT remdesk_recv_ctl_version_info_pdu(remdeskPlugin* remdesk, wStream* s,
248
                                              REMDESK_CHANNEL_HEADER* header)
249
0
{
250
0
  UINT32 versionMajor = 0;
251
0
  UINT32 versionMinor = 0;
252
253
0
  WINPR_ASSERT(remdesk);
254
0
  WINPR_ASSERT(s);
255
0
  WINPR_ASSERT(header);
256
257
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
258
0
    return ERROR_INVALID_DATA;
259
260
0
  Stream_Read_UINT32(s, versionMajor); /* versionMajor (4 bytes) */
261
0
  Stream_Read_UINT32(s, versionMinor); /* versionMinor (4 bytes) */
262
263
0
  if ((versionMajor != 1) || (versionMinor > 2) || (versionMinor == 0))
264
0
  {
265
0
    WLog_ERR(TAG, "Unsupported protocol version %" PRId32 ".%" PRId32, versionMajor,
266
0
             versionMinor);
267
0
  }
268
269
0
  remdesk->Version = versionMinor;
270
0
  return CHANNEL_RC_OK;
271
0
}
272
273
/**
274
 * Function description
275
 *
276
 * @return 0 on success, otherwise a Win32 error code
277
 */
278
static UINT remdesk_send_ctl_version_info_pdu(remdeskPlugin* remdesk)
279
0
{
280
0
  wStream* s = NULL;
281
0
  REMDESK_CTL_VERSION_INFO_PDU pdu;
282
0
  UINT error = 0;
283
284
0
  WINPR_ASSERT(remdesk);
285
286
0
  remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERSIONINFO, 8);
287
0
  pdu.versionMajor = 1;
288
0
  pdu.versionMinor = 2;
289
0
  s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
290
291
0
  if (!s)
292
0
  {
293
0
    WLog_ERR(TAG, "Stream_New failed!");
294
0
    return CHANNEL_RC_NO_MEMORY;
295
0
  }
296
297
0
  remdesk_write_ctl_header(s, &(pdu.ctlHeader));
298
0
  Stream_Write_UINT32(s, pdu.versionMajor); /* versionMajor (4 bytes) */
299
0
  Stream_Write_UINT32(s, pdu.versionMinor); /* versionMinor (4 bytes) */
300
0
  Stream_SealLength(s);
301
302
0
  if ((error = remdesk_virtual_channel_write(remdesk, s)))
303
0
    WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
304
305
0
  return error;
306
0
}
307
308
/**
309
 * Function description
310
 *
311
 * @return 0 on success, otherwise a Win32 error code
312
 */
313
static UINT remdesk_recv_ctl_result_pdu(remdeskPlugin* remdesk, wStream* s,
314
                                        REMDESK_CHANNEL_HEADER* header, UINT32* pResult)
315
0
{
316
0
  UINT32 result = 0;
317
318
0
  WINPR_ASSERT(remdesk);
319
0
  WINPR_ASSERT(s);
320
0
  WINPR_ASSERT(header);
321
0
  WINPR_ASSERT(pResult);
322
323
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
324
0
    return ERROR_INVALID_DATA;
325
326
0
  Stream_Read_UINT32(s, result); /* result (4 bytes) */
327
0
  *pResult = result;
328
  // WLog_DBG(TAG, "RemdeskRecvResult: 0x%08"PRIX32"", result);
329
0
  switch (result)
330
0
  {
331
0
    case REMDESK_ERROR_HELPEESAIDNO:
332
0
      WLog_DBG(TAG, "remote assistance connection request was denied");
333
0
      return ERROR_CONNECTION_REFUSED;
334
335
0
    default:
336
0
      break;
337
0
  }
338
339
0
  return CHANNEL_RC_OK;
340
0
}
341
342
/**
343
 * Function description
344
 *
345
 * @return 0 on success, otherwise a Win32 error code
346
 */
347
static UINT remdesk_send_ctl_authenticate_pdu(remdeskPlugin* remdesk)
348
0
{
349
0
  UINT error = ERROR_INTERNAL_ERROR;
350
0
  wStream* s = NULL;
351
0
  size_t cbExpertBlobW = 0;
352
0
  WCHAR* expertBlobW = NULL;
353
0
  size_t cbRaConnectionStringW = 0;
354
0
  WCHAR* raConnectionStringW = NULL;
355
0
  REMDESK_CTL_AUTHENTICATE_PDU pdu = { 0 };
356
0
  rdpSettings* settings = NULL;
357
358
0
  WINPR_ASSERT(remdesk);
359
360
0
  if ((error = remdesk_generate_expert_blob(remdesk)))
361
0
  {
362
0
    WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "", error);
363
0
    return error;
364
0
  }
365
366
0
  pdu.expertBlob = remdesk->ExpertBlob;
367
0
  WINPR_ASSERT(remdesk->rdpcontext);
368
0
  settings = remdesk->rdpcontext->settings;
369
0
  WINPR_ASSERT(settings);
370
371
0
  pdu.raConnectionString =
372
0
      freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
373
0
  raConnectionStringW = ConvertUtf8ToWCharAlloc(pdu.raConnectionString, &cbRaConnectionStringW);
374
375
0
  if (!raConnectionStringW || (cbRaConnectionStringW > UINT32_MAX / sizeof(WCHAR)))
376
0
    goto out;
377
378
0
  cbRaConnectionStringW = cbRaConnectionStringW * sizeof(WCHAR);
379
380
0
  expertBlobW = ConvertUtf8ToWCharAlloc(pdu.expertBlob, &cbExpertBlobW);
381
382
0
  if (!expertBlobW || (cbExpertBlobW > UINT32_MAX / sizeof(WCHAR)))
383
0
    goto out;
384
385
0
  cbExpertBlobW = cbExpertBlobW * sizeof(WCHAR);
386
0
  remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_AUTHENTICATE,
387
0
                             cbRaConnectionStringW + cbExpertBlobW);
388
0
  s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
389
390
0
  if (!s)
391
0
  {
392
0
    WLog_ERR(TAG, "Stream_New failed!");
393
0
    error = CHANNEL_RC_NO_MEMORY;
394
0
    goto out;
395
0
  }
396
397
0
  remdesk_write_ctl_header(s, &(pdu.ctlHeader));
398
0
  Stream_Write(s, (BYTE*)raConnectionStringW, cbRaConnectionStringW);
399
0
  Stream_Write(s, (BYTE*)expertBlobW, cbExpertBlobW);
400
0
  Stream_SealLength(s);
401
402
0
  if ((error = remdesk_virtual_channel_write(remdesk, s)))
403
0
    WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
404
405
0
out:
406
0
  free(raConnectionStringW);
407
0
  free(expertBlobW);
408
409
0
  return error;
410
0
}
411
412
/**
413
 * Function description
414
 *
415
 * @return 0 on success, otherwise a Win32 error code
416
 */
417
static UINT remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk)
418
0
{
419
0
  UINT error = 0;
420
0
  size_t length = 0;
421
0
  wStream* s = NULL;
422
0
  size_t cbRaConnectionStringW = 0;
423
0
  WCHAR* raConnectionStringW = NULL;
424
0
  REMDESK_CTL_REMOTE_CONTROL_DESKTOP_PDU pdu = { 0 };
425
0
  rdpSettings* settings = NULL;
426
427
0
  WINPR_ASSERT(remdesk);
428
0
  WINPR_ASSERT(remdesk->rdpcontext);
429
0
  settings = remdesk->rdpcontext->settings;
430
0
  WINPR_ASSERT(settings);
431
432
0
  pdu.raConnectionString =
433
0
      freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
434
0
  raConnectionStringW = ConvertUtf8ToWCharAlloc(pdu.raConnectionString, &length);
435
436
0
  if (!raConnectionStringW)
437
0
    return ERROR_INTERNAL_ERROR;
438
439
0
  cbRaConnectionStringW = length * sizeof(WCHAR);
440
0
  remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_REMOTE_CONTROL_DESKTOP,
441
0
                             cbRaConnectionStringW);
442
0
  s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
443
444
0
  if (!s)
445
0
  {
446
0
    WLog_ERR(TAG, "Stream_New failed!");
447
0
    error = CHANNEL_RC_NO_MEMORY;
448
0
    goto out;
449
0
  }
450
451
0
  remdesk_write_ctl_header(s, &(pdu.ctlHeader));
452
0
  Stream_Write(s, (BYTE*)raConnectionStringW, cbRaConnectionStringW);
453
0
  Stream_SealLength(s);
454
455
0
  if ((error = remdesk_virtual_channel_write(remdesk, s)))
456
0
    WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
457
458
0
out:
459
0
  free(raConnectionStringW);
460
461
0
  return error;
462
0
}
463
464
/**
465
 * Function description
466
 *
467
 * @return 0 on success, otherwise a Win32 error code
468
 */
469
static UINT remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk)
470
0
{
471
0
  UINT error = ERROR_INTERNAL_ERROR;
472
0
  wStream* s = NULL;
473
0
  size_t cbExpertBlobW = 0;
474
0
  WCHAR* expertBlobW = NULL;
475
0
  REMDESK_CTL_VERIFY_PASSWORD_PDU pdu = { 0 };
476
477
0
  WINPR_ASSERT(remdesk);
478
479
0
  if ((error = remdesk_generate_expert_blob(remdesk)))
480
0
  {
481
0
    WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
482
0
    return error;
483
0
  }
484
485
0
  pdu.expertBlob = remdesk->ExpertBlob;
486
0
  expertBlobW = ConvertUtf8ToWCharAlloc(pdu.expertBlob, &cbExpertBlobW);
487
488
0
  if (!expertBlobW || (cbExpertBlobW > UINT32_MAX / sizeof(WCHAR)))
489
0
    goto out;
490
491
0
  cbExpertBlobW = cbExpertBlobW * sizeof(WCHAR);
492
0
  remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW);
493
0
  s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
494
495
0
  if (!s)
496
0
  {
497
0
    WLog_ERR(TAG, "Stream_New failed!");
498
0
    error = CHANNEL_RC_NO_MEMORY;
499
0
    goto out;
500
0
  }
501
502
0
  remdesk_write_ctl_header(s, &(pdu.ctlHeader));
503
0
  Stream_Write(s, (BYTE*)expertBlobW, cbExpertBlobW);
504
0
  Stream_SealLength(s);
505
506
0
  if ((error = remdesk_virtual_channel_write(remdesk, s)))
507
0
    WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
508
509
0
out:
510
0
  free(expertBlobW);
511
512
0
  return error;
513
0
}
514
515
/**
516
 * Function description
517
 *
518
 * @return 0 on success, otherwise a Win32 error code
519
 */
520
static UINT remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk)
521
0
{
522
0
  UINT error = 0;
523
0
  wStream* s = NULL;
524
0
  REMDESK_CTL_EXPERT_ON_VISTA_PDU pdu;
525
526
0
  WINPR_ASSERT(remdesk);
527
528
0
  if ((error = remdesk_generate_expert_blob(remdesk)))
529
0
  {
530
0
    WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
531
0
    return error;
532
0
  }
533
534
0
  pdu.EncryptedPasswordLength = remdesk->EncryptedPassStubSize;
535
0
  pdu.EncryptedPassword = remdesk->EncryptedPassStub;
536
0
  remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA,
537
0
                             pdu.EncryptedPasswordLength);
538
0
  s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
539
540
0
  if (!s)
541
0
  {
542
0
    WLog_ERR(TAG, "Stream_New failed!");
543
0
    return CHANNEL_RC_NO_MEMORY;
544
0
  }
545
546
0
  remdesk_write_ctl_header(s, &(pdu.ctlHeader));
547
0
  Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength);
548
0
  Stream_SealLength(s);
549
0
  return remdesk_virtual_channel_write(remdesk, s);
550
0
}
551
552
/**
553
 * Function description
554
 *
555
 * @return 0 on success, otherwise a Win32 error code
556
 */
557
static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header)
558
0
{
559
0
  UINT error = CHANNEL_RC_OK;
560
0
  UINT32 msgType = 0;
561
0
  UINT32 result = 0;
562
563
0
  WINPR_ASSERT(remdesk);
564
0
  WINPR_ASSERT(s);
565
0
  WINPR_ASSERT(header);
566
567
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
568
0
    return ERROR_INVALID_DATA;
569
570
0
  Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */
571
572
  // WLog_DBG(TAG, "msgType: %"PRIu32"", msgType);
573
574
0
  switch (msgType)
575
0
  {
576
0
    case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
577
0
      break;
578
579
0
    case REMDESK_CTL_RESULT:
580
0
      if ((error = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result)))
581
0
        WLog_ERR(TAG, "remdesk_recv_ctl_result_pdu failed with error %" PRIu32 "", error);
582
583
0
      break;
584
585
0
    case REMDESK_CTL_AUTHENTICATE:
586
0
      break;
587
588
0
    case REMDESK_CTL_SERVER_ANNOUNCE:
589
0
      if ((error = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header)))
590
0
        WLog_ERR(TAG, "remdesk_recv_ctl_server_announce_pdu failed with error %" PRIu32 "",
591
0
                 error);
592
593
0
      break;
594
595
0
    case REMDESK_CTL_DISCONNECT:
596
0
      break;
597
598
0
    case REMDESK_CTL_VERSIONINFO:
599
0
      if ((error = remdesk_recv_ctl_version_info_pdu(remdesk, s, header)))
600
0
      {
601
0
        WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32 "",
602
0
                 error);
603
0
        break;
604
0
      }
605
606
0
      if (remdesk->Version == 1)
607
0
      {
608
0
        if ((error = remdesk_send_ctl_version_info_pdu(remdesk)))
609
0
        {
610
0
          WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "",
611
0
                   error);
612
0
          break;
613
0
        }
614
615
0
        if ((error = remdesk_send_ctl_authenticate_pdu(remdesk)))
616
0
        {
617
0
          WLog_ERR(TAG, "remdesk_send_ctl_authenticate_pdu failed with error %" PRIu32 "",
618
0
                   error);
619
0
          break;
620
0
        }
621
622
0
        if ((error = remdesk_send_ctl_remote_control_desktop_pdu(remdesk)))
623
0
        {
624
0
          WLog_ERR(
625
0
              TAG,
626
0
              "remdesk_send_ctl_remote_control_desktop_pdu failed with error %" PRIu32 "",
627
0
              error);
628
0
          break;
629
0
        }
630
0
      }
631
0
      else if (remdesk->Version == 2)
632
0
      {
633
0
        if ((error = remdesk_send_ctl_expert_on_vista_pdu(remdesk)))
634
0
        {
635
0
          WLog_ERR(TAG,
636
0
                   "remdesk_send_ctl_expert_on_vista_pdu failed with error %" PRIu32 "",
637
0
                   error);
638
0
          break;
639
0
        }
640
641
0
        if ((error = remdesk_send_ctl_verify_password_pdu(remdesk)))
642
0
        {
643
0
          WLog_ERR(TAG,
644
0
                   "remdesk_send_ctl_verify_password_pdu failed with error %" PRIu32 "",
645
0
                   error);
646
0
          break;
647
0
        }
648
0
      }
649
650
0
      break;
651
652
0
    case REMDESK_CTL_ISCONNECTED:
653
0
      break;
654
655
0
    case REMDESK_CTL_VERIFY_PASSWORD:
656
0
      break;
657
658
0
    case REMDESK_CTL_EXPERT_ON_VISTA:
659
0
      break;
660
661
0
    case REMDESK_CTL_RANOVICE_NAME:
662
0
      break;
663
664
0
    case REMDESK_CTL_RAEXPERT_NAME:
665
0
      break;
666
667
0
    case REMDESK_CTL_TOKEN:
668
0
      break;
669
670
0
    default:
671
0
      WLog_ERR(TAG, "unknown msgType: %" PRIu32 "", msgType);
672
0
      error = ERROR_INVALID_DATA;
673
0
      break;
674
0
  }
675
676
0
  return error;
677
0
}
678
679
/**
680
 * Function description
681
 *
682
 * @return 0 on success, otherwise a Win32 error code
683
 */
684
static UINT remdesk_process_receive(remdeskPlugin* remdesk, wStream* s)
685
0
{
686
0
  UINT status = 0;
687
0
  REMDESK_CHANNEL_HEADER header;
688
689
0
  WINPR_ASSERT(remdesk);
690
0
  WINPR_ASSERT(s);
691
692
#if 0
693
  WLog_DBG(TAG, "RemdeskReceive: %"PRIuz"", Stream_GetRemainingLength(s));
694
  winpr_HexDump(Stream_ConstPointer(s), Stream_GetRemainingLength(s));
695
#endif
696
697
0
  if ((status = remdesk_read_channel_header(s, &header)))
698
0
  {
699
0
    WLog_ERR(TAG, "remdesk_read_channel_header failed with error %" PRIu32 "", status);
700
0
    return status;
701
0
  }
702
703
0
  if (strcmp(header.ChannelName, "RC_CTL") == 0)
704
0
  {
705
0
    status = remdesk_recv_ctl_pdu(remdesk, s, &header);
706
0
  }
707
0
  else if (strcmp(header.ChannelName, "70") == 0)
708
0
  {
709
0
  }
710
0
  else if (strcmp(header.ChannelName, "71") == 0)
711
0
  {
712
0
  }
713
0
  else if (strcmp(header.ChannelName, ".") == 0)
714
0
  {
715
0
  }
716
0
  else if (strcmp(header.ChannelName, "1000.") == 0)
717
0
  {
718
0
  }
719
0
  else if (strcmp(header.ChannelName, "RA_FX") == 0)
720
0
  {
721
0
  }
722
0
  else
723
0
  {
724
0
  }
725
726
0
  return status;
727
0
}
728
729
static void remdesk_process_connect(remdeskPlugin* remdesk)
730
0
{
731
0
  WINPR_ASSERT(remdesk);
732
0
}
733
734
/**
735
 * Function description
736
 *
737
 * @return 0 on success, otherwise a Win32 error code
738
 */
739
static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, const void* pData,
740
                                                        UINT32 dataLength, UINT32 totalLength,
741
                                                        UINT32 dataFlags)
742
0
{
743
0
  wStream* data_in = NULL;
744
745
0
  WINPR_ASSERT(remdesk);
746
747
0
  if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
748
0
  {
749
0
    return CHANNEL_RC_OK;
750
0
  }
751
752
0
  if (dataFlags & CHANNEL_FLAG_FIRST)
753
0
  {
754
0
    if (remdesk->data_in)
755
0
      Stream_Free(remdesk->data_in, TRUE);
756
757
0
    remdesk->data_in = Stream_New(NULL, totalLength);
758
759
0
    if (!remdesk->data_in)
760
0
    {
761
0
      WLog_ERR(TAG, "Stream_New failed!");
762
0
      return CHANNEL_RC_NO_MEMORY;
763
0
    }
764
0
  }
765
766
0
  data_in = remdesk->data_in;
767
768
0
  if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
769
0
  {
770
0
    WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
771
0
    return CHANNEL_RC_NO_MEMORY;
772
0
  }
773
774
0
  Stream_Write(data_in, pData, dataLength);
775
776
0
  if (dataFlags & CHANNEL_FLAG_LAST)
777
0
  {
778
0
    if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
779
0
    {
780
0
      WLog_ERR(TAG, "read error");
781
0
      return ERROR_INTERNAL_ERROR;
782
0
    }
783
784
0
    remdesk->data_in = NULL;
785
0
    Stream_SealLength(data_in);
786
0
    Stream_SetPosition(data_in, 0);
787
788
0
    if (!MessageQueue_Post(remdesk->queue, NULL, 0, (void*)data_in, NULL))
789
0
    {
790
0
      WLog_ERR(TAG, "MessageQueue_Post failed!");
791
0
      return ERROR_INTERNAL_ERROR;
792
0
    }
793
0
  }
794
795
0
  return CHANNEL_RC_OK;
796
0
}
797
798
static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
799
                                                            UINT event, LPVOID pData,
800
                                                            UINT32 dataLength, UINT32 totalLength,
801
                                                            UINT32 dataFlags)
802
0
{
803
0
  UINT error = CHANNEL_RC_OK;
804
0
  remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
805
806
0
  switch (event)
807
0
  {
808
0
    case CHANNEL_EVENT_INITIALIZED:
809
0
      break;
810
811
0
    case CHANNEL_EVENT_DATA_RECEIVED:
812
0
      if (!remdesk || (remdesk->OpenHandle != openHandle))
813
0
      {
814
0
        WLog_ERR(TAG, "error no match");
815
0
        return;
816
0
      }
817
0
      if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength,
818
0
                                                               totalLength, dataFlags)))
819
0
        WLog_ERR(TAG,
820
0
                 "remdesk_virtual_channel_event_data_received failed with error %" PRIu32
821
0
                 "!",
822
0
                 error);
823
824
0
      break;
825
826
0
    case CHANNEL_EVENT_WRITE_CANCELLED:
827
0
    case CHANNEL_EVENT_WRITE_COMPLETE:
828
0
    {
829
0
      wStream* s = (wStream*)pData;
830
0
      Stream_Free(s, TRUE);
831
0
    }
832
0
    break;
833
834
0
    case CHANNEL_EVENT_USER:
835
0
      break;
836
837
0
    default:
838
0
      WLog_ERR(TAG, "unhandled event %" PRIu32 "!", event);
839
0
      error = ERROR_INTERNAL_ERROR;
840
0
      break;
841
0
  }
842
843
0
  if (error && remdesk && remdesk->rdpcontext)
844
0
    setChannelError(remdesk->rdpcontext, error,
845
0
                    "remdesk_virtual_channel_open_event_ex reported an error");
846
0
}
847
848
static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
849
0
{
850
0
  wStream* data = NULL;
851
0
  wMessage message = { 0 };
852
0
  remdeskPlugin* remdesk = (remdeskPlugin*)arg;
853
0
  UINT error = CHANNEL_RC_OK;
854
855
0
  WINPR_ASSERT(remdesk);
856
857
0
  remdesk_process_connect(remdesk);
858
859
0
  while (1)
860
0
  {
861
0
    if (!MessageQueue_Wait(remdesk->queue))
862
0
    {
863
0
      WLog_ERR(TAG, "MessageQueue_Wait failed!");
864
0
      error = ERROR_INTERNAL_ERROR;
865
0
      break;
866
0
    }
867
868
0
    if (!MessageQueue_Peek(remdesk->queue, &message, TRUE))
869
0
    {
870
0
      WLog_ERR(TAG, "MessageQueue_Peek failed!");
871
0
      error = ERROR_INTERNAL_ERROR;
872
0
      break;
873
0
    }
874
875
0
    if (message.id == WMQ_QUIT)
876
0
      break;
877
878
0
    if (message.id == 0)
879
0
    {
880
0
      data = (wStream*)message.wParam;
881
882
0
      if ((error = remdesk_process_receive(remdesk, data)))
883
0
      {
884
0
        WLog_ERR(TAG, "remdesk_process_receive failed with error %" PRIu32 "!", error);
885
0
        Stream_Free(data, TRUE);
886
0
        break;
887
0
      }
888
889
0
      Stream_Free(data, TRUE);
890
0
    }
891
0
  }
892
893
0
  if (error && remdesk->rdpcontext)
894
0
    setChannelError(remdesk->rdpcontext, error,
895
0
                    "remdesk_virtual_channel_client_thread reported an error");
896
897
0
  ExitThread(error);
898
0
  return error;
899
0
}
900
901
/**
902
 * Function description
903
 *
904
 * @return 0 on success, otherwise a Win32 error code
905
 */
906
static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, LPVOID pData,
907
                                                    UINT32 dataLength)
908
0
{
909
0
  UINT error = 0;
910
911
0
  WINPR_ASSERT(remdesk);
912
913
0
  remdesk->queue = MessageQueue_New(NULL);
914
915
0
  if (!remdesk->queue)
916
0
  {
917
0
    WLog_ERR(TAG, "MessageQueue_New failed!");
918
0
    error = CHANNEL_RC_NO_MEMORY;
919
0
    goto error_out;
920
0
  }
921
922
0
  remdesk->thread =
923
0
      CreateThread(NULL, 0, remdesk_virtual_channel_client_thread, (void*)remdesk, 0, NULL);
924
925
0
  if (!remdesk->thread)
926
0
  {
927
0
    WLog_ERR(TAG, "CreateThread failed");
928
0
    error = ERROR_INTERNAL_ERROR;
929
0
    goto error_out;
930
0
  }
931
932
0
  return remdesk->channelEntryPoints.pVirtualChannelOpenEx(
933
0
      remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name,
934
0
      remdesk_virtual_channel_open_event_ex);
935
0
error_out:
936
0
  MessageQueue_Free(remdesk->queue);
937
0
  remdesk->queue = NULL;
938
0
  return error;
939
0
}
940
941
/**
942
 * Function description
943
 *
944
 * @return 0 on success, otherwise a Win32 error code
945
 */
946
static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
947
0
{
948
0
  UINT rc = CHANNEL_RC_OK;
949
950
0
  WINPR_ASSERT(remdesk);
951
952
0
  if (remdesk->queue && remdesk->thread)
953
0
  {
954
0
    if (MessageQueue_PostQuit(remdesk->queue, 0) &&
955
0
        (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED))
956
0
    {
957
0
      rc = GetLastError();
958
0
      WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
959
0
      return rc;
960
0
    }
961
0
  }
962
963
0
  if (remdesk->OpenHandle != 0)
964
0
  {
965
0
    WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
966
0
    rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
967
0
                                                            remdesk->OpenHandle);
968
969
0
    if (CHANNEL_RC_OK != rc)
970
0
    {
971
0
      WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
972
0
               WTSErrorToString(rc), rc);
973
0
    }
974
975
0
    remdesk->OpenHandle = 0;
976
0
  }
977
0
  MessageQueue_Free(remdesk->queue);
978
0
  CloseHandle(remdesk->thread);
979
0
  Stream_Free(remdesk->data_in, TRUE);
980
0
  remdesk->data_in = NULL;
981
0
  remdesk->queue = NULL;
982
0
  remdesk->thread = NULL;
983
0
  return rc;
984
0
}
985
986
static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
987
0
{
988
0
  WINPR_ASSERT(remdesk);
989
990
0
  remdesk->InitHandle = 0;
991
0
  free(remdesk->context);
992
0
  free(remdesk);
993
0
}
994
995
static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
996
                                                            UINT event, LPVOID pData,
997
                                                            UINT dataLength)
998
0
{
999
0
  UINT error = CHANNEL_RC_OK;
1000
0
  remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
1001
1002
0
  if (!remdesk || (remdesk->InitHandle != pInitHandle))
1003
0
  {
1004
0
    WLog_ERR(TAG, "error no match");
1005
0
    return;
1006
0
  }
1007
1008
0
  switch (event)
1009
0
  {
1010
0
    case CHANNEL_EVENT_CONNECTED:
1011
0
      if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength)))
1012
0
        WLog_ERR(TAG,
1013
0
                 "remdesk_virtual_channel_event_connected failed with error %" PRIu32 "",
1014
0
                 error);
1015
1016
0
      break;
1017
1018
0
    case CHANNEL_EVENT_DISCONNECTED:
1019
0
      if ((error = remdesk_virtual_channel_event_disconnected(remdesk)))
1020
0
        WLog_ERR(TAG,
1021
0
                 "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32 "",
1022
0
                 error);
1023
1024
0
      break;
1025
1026
0
    case CHANNEL_EVENT_TERMINATED:
1027
0
      remdesk_virtual_channel_event_terminated(remdesk);
1028
0
      break;
1029
1030
0
    case CHANNEL_EVENT_ATTACHED:
1031
0
    case CHANNEL_EVENT_DETACHED:
1032
0
    default:
1033
0
      break;
1034
0
  }
1035
1036
0
  if (error && remdesk->rdpcontext)
1037
0
    setChannelError(remdesk->rdpcontext, error,
1038
0
                    "remdesk_virtual_channel_init_event reported an error");
1039
0
}
1040
1041
/* remdesk is always built-in */
1042
#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx
1043
1044
FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
1045
                                                         PVOID pInitHandle))
1046
0
{
1047
0
  UINT rc = 0;
1048
0
  remdeskPlugin* remdesk = NULL;
1049
0
  RemdeskClientContext* context = NULL;
1050
0
  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
1051
1052
0
  if (!pEntryPoints)
1053
0
  {
1054
0
    return FALSE;
1055
0
  }
1056
1057
0
  remdesk = (remdeskPlugin*)calloc(1, sizeof(remdeskPlugin));
1058
1059
0
  if (!remdesk)
1060
0
  {
1061
0
    WLog_ERR(TAG, "calloc failed!");
1062
0
    return FALSE;
1063
0
  }
1064
1065
0
  remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1066
0
                                CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1067
0
  sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name),
1068
0
            REMDESK_SVC_CHANNEL_NAME);
1069
0
  remdesk->Version = 2;
1070
0
  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1071
1072
0
  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1073
0
      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1074
0
  {
1075
0
    context = (RemdeskClientContext*)calloc(1, sizeof(RemdeskClientContext));
1076
1077
0
    if (!context)
1078
0
    {
1079
0
      WLog_ERR(TAG, "calloc failed!");
1080
0
      goto error_out;
1081
0
    }
1082
1083
0
    context->handle = (void*)remdesk;
1084
0
    remdesk->context = context;
1085
0
    remdesk->rdpcontext = pEntryPointsEx->context;
1086
0
  }
1087
1088
0
  CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints,
1089
0
             sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
1090
0
  remdesk->InitHandle = pInitHandle;
1091
0
  rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(
1092
0
      remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1093
0
      remdesk_virtual_channel_init_event_ex);
1094
1095
0
  if (CHANNEL_RC_OK != rc)
1096
0
  {
1097
0
    WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1098
0
             rc);
1099
0
    goto error_out;
1100
0
  }
1101
1102
0
  remdesk->channelEntryPoints.pInterface = context;
1103
0
  return TRUE;
1104
0
error_out:
1105
0
  free(remdesk);
1106
0
  free(context);
1107
0
  return FALSE;
1108
0
}