Coverage Report

Created: 2024-09-08 06:20

/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
  (void)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
  REMDESK_CTL_HEADER ctlHeader = { 0 };
355
356
0
  WINPR_ASSERT(remdesk);
357
358
0
  if ((error = remdesk_generate_expert_blob(remdesk)))
359
0
  {
360
0
    WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "", error);
361
0
    return error;
362
0
  }
363
364
0
  const char* expertBlob = remdesk->ExpertBlob;
365
0
  WINPR_ASSERT(remdesk->rdpcontext);
366
0
  rdpSettings* settings = remdesk->rdpcontext->settings;
367
0
  WINPR_ASSERT(settings);
368
369
0
  const char* raConnectionString =
370
0
      freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
371
0
  WCHAR* raConnectionStringW =
372
0
      ConvertUtf8ToWCharAlloc(raConnectionString, &cbRaConnectionStringW);
373
374
0
  if (!raConnectionStringW || (cbRaConnectionStringW > UINT32_MAX / sizeof(WCHAR)))
375
0
    goto out;
376
377
0
  cbRaConnectionStringW = cbRaConnectionStringW * sizeof(WCHAR);
378
379
0
  expertBlobW = ConvertUtf8ToWCharAlloc(expertBlob, &cbExpertBlobW);
380
381
0
  if (!expertBlobW || (cbExpertBlobW > UINT32_MAX / sizeof(WCHAR)))
382
0
    goto out;
383
384
0
  cbExpertBlobW = cbExpertBlobW * sizeof(WCHAR);
385
0
  remdesk_prepare_ctl_header(&(ctlHeader), REMDESK_CTL_AUTHENTICATE,
386
0
                             cbRaConnectionStringW + cbExpertBlobW);
387
0
  s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
388
389
0
  if (!s)
390
0
  {
391
0
    WLog_ERR(TAG, "Stream_New failed!");
392
0
    error = CHANNEL_RC_NO_MEMORY;
393
0
    goto out;
394
0
  }
395
396
0
  remdesk_write_ctl_header(s, &(ctlHeader));
397
0
  Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
398
0
  Stream_Write(s, expertBlobW, cbExpertBlobW);
399
0
  Stream_SealLength(s);
400
401
0
  if ((error = remdesk_virtual_channel_write(remdesk, s)))
402
0
    WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
403
404
0
out:
405
0
  free(raConnectionStringW);
406
0
  free(expertBlobW);
407
408
0
  return error;
409
0
}
410
411
/**
412
 * Function description
413
 *
414
 * @return 0 on success, otherwise a Win32 error code
415
 */
416
static UINT remdesk_send_ctl_remote_control_desktop_pdu(remdeskPlugin* remdesk)
417
0
{
418
0
  UINT error = 0;
419
0
  size_t length = 0;
420
421
0
  WINPR_ASSERT(remdesk);
422
0
  WINPR_ASSERT(remdesk->rdpcontext);
423
0
  rdpSettings* settings = remdesk->rdpcontext->settings;
424
0
  WINPR_ASSERT(settings);
425
426
0
  const char* raConnectionString =
427
0
      freerdp_settings_get_string(settings, FreeRDP_RemoteAssistanceRCTicket);
428
0
  WCHAR* raConnectionStringW = ConvertUtf8ToWCharAlloc(raConnectionString, &length);
429
0
  size_t cbRaConnectionStringW = length * sizeof(WCHAR);
430
431
0
  if (!raConnectionStringW)
432
0
    return ERROR_INTERNAL_ERROR;
433
434
0
  REMDESK_CTL_HEADER ctlHeader = { 0 };
435
0
  remdesk_prepare_ctl_header(&ctlHeader, REMDESK_CTL_REMOTE_CONTROL_DESKTOP,
436
0
                             cbRaConnectionStringW);
437
0
  wStream* s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + ctlHeader.ch.DataLength);
438
439
0
  if (!s)
440
0
  {
441
0
    WLog_ERR(TAG, "Stream_New failed!");
442
0
    error = CHANNEL_RC_NO_MEMORY;
443
0
    goto out;
444
0
  }
445
446
0
  remdesk_write_ctl_header(s, &ctlHeader);
447
0
  Stream_Write(s, raConnectionStringW, cbRaConnectionStringW);
448
0
  Stream_SealLength(s);
449
450
0
  if ((error = remdesk_virtual_channel_write(remdesk, s)))
451
0
    WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
452
453
0
out:
454
0
  free(raConnectionStringW);
455
456
0
  return error;
457
0
}
458
459
/**
460
 * Function description
461
 *
462
 * @return 0 on success, otherwise a Win32 error code
463
 */
464
static UINT remdesk_send_ctl_verify_password_pdu(remdeskPlugin* remdesk)
465
0
{
466
0
  UINT error = ERROR_INTERNAL_ERROR;
467
0
  wStream* s = NULL;
468
0
  size_t cbExpertBlobW = 0;
469
0
  WCHAR* expertBlobW = NULL;
470
0
  REMDESK_CTL_VERIFY_PASSWORD_PDU pdu = { 0 };
471
472
0
  WINPR_ASSERT(remdesk);
473
474
0
  if ((error = remdesk_generate_expert_blob(remdesk)))
475
0
  {
476
0
    WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
477
0
    return error;
478
0
  }
479
480
0
  pdu.expertBlob = remdesk->ExpertBlob;
481
0
  expertBlobW = ConvertUtf8ToWCharAlloc(pdu.expertBlob, &cbExpertBlobW);
482
483
0
  if (!expertBlobW || (cbExpertBlobW > UINT32_MAX / sizeof(WCHAR)))
484
0
    goto out;
485
486
0
  cbExpertBlobW = cbExpertBlobW * sizeof(WCHAR);
487
0
  remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_VERIFY_PASSWORD, cbExpertBlobW);
488
0
  s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
489
490
0
  if (!s)
491
0
  {
492
0
    WLog_ERR(TAG, "Stream_New failed!");
493
0
    error = CHANNEL_RC_NO_MEMORY;
494
0
    goto out;
495
0
  }
496
497
0
  remdesk_write_ctl_header(s, &(pdu.ctlHeader));
498
0
  Stream_Write(s, (BYTE*)expertBlobW, cbExpertBlobW);
499
0
  Stream_SealLength(s);
500
501
0
  if ((error = remdesk_virtual_channel_write(remdesk, s)))
502
0
    WLog_ERR(TAG, "remdesk_virtual_channel_write failed with error %" PRIu32 "!", error);
503
504
0
out:
505
0
  free(expertBlobW);
506
507
0
  return error;
508
0
}
509
510
/**
511
 * Function description
512
 *
513
 * @return 0 on success, otherwise a Win32 error code
514
 */
515
static UINT remdesk_send_ctl_expert_on_vista_pdu(remdeskPlugin* remdesk)
516
0
{
517
0
  UINT error = 0;
518
0
  wStream* s = NULL;
519
0
  REMDESK_CTL_EXPERT_ON_VISTA_PDU pdu;
520
521
0
  WINPR_ASSERT(remdesk);
522
523
0
  if ((error = remdesk_generate_expert_blob(remdesk)))
524
0
  {
525
0
    WLog_ERR(TAG, "remdesk_generate_expert_blob failed with error %" PRIu32 "!", error);
526
0
    return error;
527
0
  }
528
529
0
  pdu.EncryptedPasswordLength = remdesk->EncryptedPassStubSize;
530
0
  pdu.EncryptedPassword = remdesk->EncryptedPassStub;
531
0
  remdesk_prepare_ctl_header(&(pdu.ctlHeader), REMDESK_CTL_EXPERT_ON_VISTA,
532
0
                             pdu.EncryptedPasswordLength);
533
0
  s = Stream_New(NULL, REMDESK_CHANNEL_CTL_SIZE + pdu.ctlHeader.ch.DataLength);
534
535
0
  if (!s)
536
0
  {
537
0
    WLog_ERR(TAG, "Stream_New failed!");
538
0
    return CHANNEL_RC_NO_MEMORY;
539
0
  }
540
541
0
  remdesk_write_ctl_header(s, &(pdu.ctlHeader));
542
0
  Stream_Write(s, pdu.EncryptedPassword, pdu.EncryptedPasswordLength);
543
0
  Stream_SealLength(s);
544
0
  return remdesk_virtual_channel_write(remdesk, s);
545
0
}
546
547
/**
548
 * Function description
549
 *
550
 * @return 0 on success, otherwise a Win32 error code
551
 */
552
static UINT remdesk_recv_ctl_pdu(remdeskPlugin* remdesk, wStream* s, REMDESK_CHANNEL_HEADER* header)
553
0
{
554
0
  UINT error = CHANNEL_RC_OK;
555
0
  UINT32 msgType = 0;
556
0
  UINT32 result = 0;
557
558
0
  WINPR_ASSERT(remdesk);
559
0
  WINPR_ASSERT(s);
560
0
  WINPR_ASSERT(header);
561
562
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
563
0
    return ERROR_INVALID_DATA;
564
565
0
  Stream_Read_UINT32(s, msgType); /* msgType (4 bytes) */
566
567
  // WLog_DBG(TAG, "msgType: %"PRIu32"", msgType);
568
569
0
  switch (msgType)
570
0
  {
571
0
    case REMDESK_CTL_REMOTE_CONTROL_DESKTOP:
572
0
      break;
573
574
0
    case REMDESK_CTL_RESULT:
575
0
      if ((error = remdesk_recv_ctl_result_pdu(remdesk, s, header, &result)))
576
0
        WLog_ERR(TAG, "remdesk_recv_ctl_result_pdu failed with error %" PRIu32 "", error);
577
578
0
      break;
579
580
0
    case REMDESK_CTL_AUTHENTICATE:
581
0
      break;
582
583
0
    case REMDESK_CTL_SERVER_ANNOUNCE:
584
0
      if ((error = remdesk_recv_ctl_server_announce_pdu(remdesk, s, header)))
585
0
        WLog_ERR(TAG, "remdesk_recv_ctl_server_announce_pdu failed with error %" PRIu32 "",
586
0
                 error);
587
588
0
      break;
589
590
0
    case REMDESK_CTL_DISCONNECT:
591
0
      break;
592
593
0
    case REMDESK_CTL_VERSIONINFO:
594
0
      if ((error = remdesk_recv_ctl_version_info_pdu(remdesk, s, header)))
595
0
      {
596
0
        WLog_ERR(TAG, "remdesk_recv_ctl_version_info_pdu failed with error %" PRIu32 "",
597
0
                 error);
598
0
        break;
599
0
      }
600
601
0
      if (remdesk->Version == 1)
602
0
      {
603
0
        if ((error = remdesk_send_ctl_version_info_pdu(remdesk)))
604
0
        {
605
0
          WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "",
606
0
                   error);
607
0
          break;
608
0
        }
609
610
0
        if ((error = remdesk_send_ctl_authenticate_pdu(remdesk)))
611
0
        {
612
0
          WLog_ERR(TAG, "remdesk_send_ctl_authenticate_pdu failed with error %" PRIu32 "",
613
0
                   error);
614
0
          break;
615
0
        }
616
617
0
        if ((error = remdesk_send_ctl_remote_control_desktop_pdu(remdesk)))
618
0
        {
619
0
          WLog_ERR(
620
0
              TAG,
621
0
              "remdesk_send_ctl_remote_control_desktop_pdu failed with error %" PRIu32 "",
622
0
              error);
623
0
          break;
624
0
        }
625
0
      }
626
0
      else if (remdesk->Version == 2)
627
0
      {
628
0
        if ((error = remdesk_send_ctl_expert_on_vista_pdu(remdesk)))
629
0
        {
630
0
          WLog_ERR(TAG,
631
0
                   "remdesk_send_ctl_expert_on_vista_pdu failed with error %" PRIu32 "",
632
0
                   error);
633
0
          break;
634
0
        }
635
636
0
        if ((error = remdesk_send_ctl_verify_password_pdu(remdesk)))
637
0
        {
638
0
          WLog_ERR(TAG,
639
0
                   "remdesk_send_ctl_verify_password_pdu failed with error %" PRIu32 "",
640
0
                   error);
641
0
          break;
642
0
        }
643
0
      }
644
645
0
      break;
646
647
0
    case REMDESK_CTL_ISCONNECTED:
648
0
      break;
649
650
0
    case REMDESK_CTL_VERIFY_PASSWORD:
651
0
      break;
652
653
0
    case REMDESK_CTL_EXPERT_ON_VISTA:
654
0
      break;
655
656
0
    case REMDESK_CTL_RANOVICE_NAME:
657
0
      break;
658
659
0
    case REMDESK_CTL_RAEXPERT_NAME:
660
0
      break;
661
662
0
    case REMDESK_CTL_TOKEN:
663
0
      break;
664
665
0
    default:
666
0
      WLog_ERR(TAG, "unknown msgType: %" PRIu32 "", msgType);
667
0
      error = ERROR_INVALID_DATA;
668
0
      break;
669
0
  }
670
671
0
  return error;
672
0
}
673
674
/**
675
 * Function description
676
 *
677
 * @return 0 on success, otherwise a Win32 error code
678
 */
679
static UINT remdesk_process_receive(remdeskPlugin* remdesk, wStream* s)
680
0
{
681
0
  UINT status = 0;
682
0
  REMDESK_CHANNEL_HEADER header;
683
684
0
  WINPR_ASSERT(remdesk);
685
0
  WINPR_ASSERT(s);
686
687
#if 0
688
  WLog_DBG(TAG, "RemdeskReceive: %"PRIuz"", Stream_GetRemainingLength(s));
689
  winpr_HexDump(Stream_ConstPointer(s), Stream_GetRemainingLength(s));
690
#endif
691
692
0
  if ((status = remdesk_read_channel_header(s, &header)))
693
0
  {
694
0
    WLog_ERR(TAG, "remdesk_read_channel_header failed with error %" PRIu32 "", status);
695
0
    return status;
696
0
  }
697
698
0
  if (strcmp(header.ChannelName, "RC_CTL") == 0)
699
0
  {
700
0
    status = remdesk_recv_ctl_pdu(remdesk, s, &header);
701
0
  }
702
0
  else if (strcmp(header.ChannelName, "70") == 0)
703
0
  {
704
0
  }
705
0
  else if (strcmp(header.ChannelName, "71") == 0)
706
0
  {
707
0
  }
708
0
  else if (strcmp(header.ChannelName, ".") == 0)
709
0
  {
710
0
  }
711
0
  else if (strcmp(header.ChannelName, "1000.") == 0)
712
0
  {
713
0
  }
714
0
  else if (strcmp(header.ChannelName, "RA_FX") == 0)
715
0
  {
716
0
  }
717
0
  else
718
0
  {
719
0
  }
720
721
0
  return status;
722
0
}
723
724
static void remdesk_process_connect(remdeskPlugin* remdesk)
725
0
{
726
0
  WINPR_ASSERT(remdesk);
727
0
}
728
729
/**
730
 * Function description
731
 *
732
 * @return 0 on success, otherwise a Win32 error code
733
 */
734
static UINT remdesk_virtual_channel_event_data_received(remdeskPlugin* remdesk, const void* pData,
735
                                                        UINT32 dataLength, UINT32 totalLength,
736
                                                        UINT32 dataFlags)
737
0
{
738
0
  wStream* data_in = NULL;
739
740
0
  WINPR_ASSERT(remdesk);
741
742
0
  if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
743
0
  {
744
0
    return CHANNEL_RC_OK;
745
0
  }
746
747
0
  if (dataFlags & CHANNEL_FLAG_FIRST)
748
0
  {
749
0
    if (remdesk->data_in)
750
0
      Stream_Free(remdesk->data_in, TRUE);
751
752
0
    remdesk->data_in = Stream_New(NULL, totalLength);
753
754
0
    if (!remdesk->data_in)
755
0
    {
756
0
      WLog_ERR(TAG, "Stream_New failed!");
757
0
      return CHANNEL_RC_NO_MEMORY;
758
0
    }
759
0
  }
760
761
0
  data_in = remdesk->data_in;
762
763
0
  if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
764
0
  {
765
0
    WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
766
0
    return CHANNEL_RC_NO_MEMORY;
767
0
  }
768
769
0
  Stream_Write(data_in, pData, dataLength);
770
771
0
  if (dataFlags & CHANNEL_FLAG_LAST)
772
0
  {
773
0
    if (Stream_Capacity(data_in) != Stream_GetPosition(data_in))
774
0
    {
775
0
      WLog_ERR(TAG, "read error");
776
0
      return ERROR_INTERNAL_ERROR;
777
0
    }
778
779
0
    remdesk->data_in = NULL;
780
0
    Stream_SealLength(data_in);
781
0
    Stream_SetPosition(data_in, 0);
782
783
0
    if (!MessageQueue_Post(remdesk->queue, NULL, 0, (void*)data_in, NULL))
784
0
    {
785
0
      WLog_ERR(TAG, "MessageQueue_Post failed!");
786
0
      return ERROR_INTERNAL_ERROR;
787
0
    }
788
0
  }
789
790
0
  return CHANNEL_RC_OK;
791
0
}
792
793
static VOID VCAPITYPE remdesk_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
794
                                                            UINT event, LPVOID pData,
795
                                                            UINT32 dataLength, UINT32 totalLength,
796
                                                            UINT32 dataFlags)
797
0
{
798
0
  UINT error = CHANNEL_RC_OK;
799
0
  remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
800
801
0
  switch (event)
802
0
  {
803
0
    case CHANNEL_EVENT_INITIALIZED:
804
0
      break;
805
806
0
    case CHANNEL_EVENT_DATA_RECEIVED:
807
0
      if (!remdesk || (remdesk->OpenHandle != openHandle))
808
0
      {
809
0
        WLog_ERR(TAG, "error no match");
810
0
        return;
811
0
      }
812
0
      if ((error = remdesk_virtual_channel_event_data_received(remdesk, pData, dataLength,
813
0
                                                               totalLength, dataFlags)))
814
0
        WLog_ERR(TAG,
815
0
                 "remdesk_virtual_channel_event_data_received failed with error %" PRIu32
816
0
                 "!",
817
0
                 error);
818
819
0
      break;
820
821
0
    case CHANNEL_EVENT_WRITE_CANCELLED:
822
0
    case CHANNEL_EVENT_WRITE_COMPLETE:
823
0
    {
824
0
      wStream* s = (wStream*)pData;
825
0
      Stream_Free(s, TRUE);
826
0
    }
827
0
    break;
828
829
0
    case CHANNEL_EVENT_USER:
830
0
      break;
831
832
0
    default:
833
0
      WLog_ERR(TAG, "unhandled event %" PRIu32 "!", event);
834
0
      error = ERROR_INTERNAL_ERROR;
835
0
      break;
836
0
  }
837
838
0
  if (error && remdesk && remdesk->rdpcontext)
839
0
    setChannelError(remdesk->rdpcontext, error,
840
0
                    "remdesk_virtual_channel_open_event_ex reported an error");
841
0
}
842
843
static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
844
0
{
845
0
  wStream* data = NULL;
846
0
  wMessage message = { 0 };
847
0
  remdeskPlugin* remdesk = (remdeskPlugin*)arg;
848
0
  UINT error = CHANNEL_RC_OK;
849
850
0
  WINPR_ASSERT(remdesk);
851
852
0
  remdesk_process_connect(remdesk);
853
854
0
  while (1)
855
0
  {
856
0
    if (!MessageQueue_Wait(remdesk->queue))
857
0
    {
858
0
      WLog_ERR(TAG, "MessageQueue_Wait failed!");
859
0
      error = ERROR_INTERNAL_ERROR;
860
0
      break;
861
0
    }
862
863
0
    if (!MessageQueue_Peek(remdesk->queue, &message, TRUE))
864
0
    {
865
0
      WLog_ERR(TAG, "MessageQueue_Peek failed!");
866
0
      error = ERROR_INTERNAL_ERROR;
867
0
      break;
868
0
    }
869
870
0
    if (message.id == WMQ_QUIT)
871
0
      break;
872
873
0
    if (message.id == 0)
874
0
    {
875
0
      data = (wStream*)message.wParam;
876
877
0
      if ((error = remdesk_process_receive(remdesk, data)))
878
0
      {
879
0
        WLog_ERR(TAG, "remdesk_process_receive failed with error %" PRIu32 "!", error);
880
0
        Stream_Free(data, TRUE);
881
0
        break;
882
0
      }
883
884
0
      Stream_Free(data, TRUE);
885
0
    }
886
0
  }
887
888
0
  if (error && remdesk->rdpcontext)
889
0
    setChannelError(remdesk->rdpcontext, error,
890
0
                    "remdesk_virtual_channel_client_thread reported an error");
891
892
0
  ExitThread(error);
893
0
  return error;
894
0
}
895
896
/**
897
 * Function description
898
 *
899
 * @return 0 on success, otherwise a Win32 error code
900
 */
901
static UINT remdesk_virtual_channel_event_connected(remdeskPlugin* remdesk, LPVOID pData,
902
                                                    UINT32 dataLength)
903
0
{
904
0
  UINT error = 0;
905
906
0
  WINPR_ASSERT(remdesk);
907
908
0
  remdesk->queue = MessageQueue_New(NULL);
909
910
0
  if (!remdesk->queue)
911
0
  {
912
0
    WLog_ERR(TAG, "MessageQueue_New failed!");
913
0
    error = CHANNEL_RC_NO_MEMORY;
914
0
    goto error_out;
915
0
  }
916
917
0
  remdesk->thread =
918
0
      CreateThread(NULL, 0, remdesk_virtual_channel_client_thread, (void*)remdesk, 0, NULL);
919
920
0
  if (!remdesk->thread)
921
0
  {
922
0
    WLog_ERR(TAG, "CreateThread failed");
923
0
    error = ERROR_INTERNAL_ERROR;
924
0
    goto error_out;
925
0
  }
926
927
0
  return remdesk->channelEntryPoints.pVirtualChannelOpenEx(
928
0
      remdesk->InitHandle, &remdesk->OpenHandle, remdesk->channelDef.name,
929
0
      remdesk_virtual_channel_open_event_ex);
930
0
error_out:
931
0
  MessageQueue_Free(remdesk->queue);
932
0
  remdesk->queue = NULL;
933
0
  return error;
934
0
}
935
936
/**
937
 * Function description
938
 *
939
 * @return 0 on success, otherwise a Win32 error code
940
 */
941
static UINT remdesk_virtual_channel_event_disconnected(remdeskPlugin* remdesk)
942
0
{
943
0
  UINT rc = CHANNEL_RC_OK;
944
945
0
  WINPR_ASSERT(remdesk);
946
947
0
  if (remdesk->queue && remdesk->thread)
948
0
  {
949
0
    if (MessageQueue_PostQuit(remdesk->queue, 0) &&
950
0
        (WaitForSingleObject(remdesk->thread, INFINITE) == WAIT_FAILED))
951
0
    {
952
0
      rc = GetLastError();
953
0
      WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", rc);
954
0
      return rc;
955
0
    }
956
0
  }
957
958
0
  if (remdesk->OpenHandle != 0)
959
0
  {
960
0
    WINPR_ASSERT(remdesk->channelEntryPoints.pVirtualChannelCloseEx);
961
0
    rc = remdesk->channelEntryPoints.pVirtualChannelCloseEx(remdesk->InitHandle,
962
0
                                                            remdesk->OpenHandle);
963
964
0
    if (CHANNEL_RC_OK != rc)
965
0
    {
966
0
      WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
967
0
               WTSErrorToString(rc), rc);
968
0
    }
969
970
0
    remdesk->OpenHandle = 0;
971
0
  }
972
0
  MessageQueue_Free(remdesk->queue);
973
0
  CloseHandle(remdesk->thread);
974
0
  Stream_Free(remdesk->data_in, TRUE);
975
0
  remdesk->data_in = NULL;
976
0
  remdesk->queue = NULL;
977
0
  remdesk->thread = NULL;
978
0
  return rc;
979
0
}
980
981
static void remdesk_virtual_channel_event_terminated(remdeskPlugin* remdesk)
982
0
{
983
0
  WINPR_ASSERT(remdesk);
984
985
0
  remdesk->InitHandle = 0;
986
0
  free(remdesk->context);
987
0
  free(remdesk);
988
0
}
989
990
static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
991
                                                            UINT event, LPVOID pData,
992
                                                            UINT dataLength)
993
0
{
994
0
  UINT error = CHANNEL_RC_OK;
995
0
  remdeskPlugin* remdesk = (remdeskPlugin*)lpUserParam;
996
997
0
  if (!remdesk || (remdesk->InitHandle != pInitHandle))
998
0
  {
999
0
    WLog_ERR(TAG, "error no match");
1000
0
    return;
1001
0
  }
1002
1003
0
  switch (event)
1004
0
  {
1005
0
    case CHANNEL_EVENT_CONNECTED:
1006
0
      if ((error = remdesk_virtual_channel_event_connected(remdesk, pData, dataLength)))
1007
0
        WLog_ERR(TAG,
1008
0
                 "remdesk_virtual_channel_event_connected failed with error %" PRIu32 "",
1009
0
                 error);
1010
1011
0
      break;
1012
1013
0
    case CHANNEL_EVENT_DISCONNECTED:
1014
0
      if ((error = remdesk_virtual_channel_event_disconnected(remdesk)))
1015
0
        WLog_ERR(TAG,
1016
0
                 "remdesk_virtual_channel_event_disconnected failed with error %" PRIu32 "",
1017
0
                 error);
1018
1019
0
      break;
1020
1021
0
    case CHANNEL_EVENT_TERMINATED:
1022
0
      remdesk_virtual_channel_event_terminated(remdesk);
1023
0
      break;
1024
1025
0
    case CHANNEL_EVENT_ATTACHED:
1026
0
    case CHANNEL_EVENT_DETACHED:
1027
0
    default:
1028
0
      break;
1029
0
  }
1030
1031
0
  if (error && remdesk->rdpcontext)
1032
0
    setChannelError(remdesk->rdpcontext, error,
1033
0
                    "remdesk_virtual_channel_init_event reported an error");
1034
0
}
1035
1036
/* remdesk is always built-in */
1037
#define VirtualChannelEntryEx remdesk_VirtualChannelEntryEx
1038
1039
FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
1040
                                                         PVOID pInitHandle))
1041
0
{
1042
0
  UINT rc = 0;
1043
0
  remdeskPlugin* remdesk = NULL;
1044
0
  RemdeskClientContext* context = NULL;
1045
0
  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
1046
1047
0
  if (!pEntryPoints)
1048
0
  {
1049
0
    return FALSE;
1050
0
  }
1051
1052
0
  remdesk = (remdeskPlugin*)calloc(1, sizeof(remdeskPlugin));
1053
1054
0
  if (!remdesk)
1055
0
  {
1056
0
    WLog_ERR(TAG, "calloc failed!");
1057
0
    return FALSE;
1058
0
  }
1059
1060
0
  remdesk->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1061
0
                                CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1062
0
  (void)sprintf_s(remdesk->channelDef.name, ARRAYSIZE(remdesk->channelDef.name),
1063
0
                  REMDESK_SVC_CHANNEL_NAME);
1064
0
  remdesk->Version = 2;
1065
0
  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1066
1067
0
  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1068
0
      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1069
0
  {
1070
0
    context = (RemdeskClientContext*)calloc(1, sizeof(RemdeskClientContext));
1071
1072
0
    if (!context)
1073
0
    {
1074
0
      WLog_ERR(TAG, "calloc failed!");
1075
0
      goto error_out;
1076
0
    }
1077
1078
0
    context->handle = (void*)remdesk;
1079
0
    remdesk->context = context;
1080
0
    remdesk->rdpcontext = pEntryPointsEx->context;
1081
0
  }
1082
1083
0
  CopyMemory(&(remdesk->channelEntryPoints), pEntryPoints,
1084
0
             sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
1085
0
  remdesk->InitHandle = pInitHandle;
1086
0
  rc = remdesk->channelEntryPoints.pVirtualChannelInitEx(
1087
0
      remdesk, context, pInitHandle, &remdesk->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1088
0
      remdesk_virtual_channel_init_event_ex);
1089
1090
0
  if (CHANNEL_RC_OK != rc)
1091
0
  {
1092
0
    WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1093
0
             rc);
1094
0
    goto error_out;
1095
0
  }
1096
1097
0
  remdesk->channelEntryPoints.pInterface = context;
1098
0
  return TRUE;
1099
0
error_out:
1100
0
  free(remdesk);
1101
0
  free(context);
1102
0
  return FALSE;
1103
0
}