Coverage Report

Created: 2024-09-08 06:20

/src/FreeRDP/channels/cliprdr/client/cliprdr_main.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Clipboard Virtual Channel
4
 *
5
 * Copyright 2009-2011 Jay Sorg
6
 * Copyright 2010-2011 Vic Lee
7
 * Copyright 2015 Thincast Technologies GmbH
8
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 *     http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22
23
#include <freerdp/config.h>
24
25
#include <winpr/wtypes.h>
26
#include <winpr/assert.h>
27
#include <winpr/crt.h>
28
#include <winpr/print.h>
29
30
#include <freerdp/types.h>
31
#include <freerdp/constants.h>
32
#include <freerdp/freerdp.h>
33
#include <freerdp/client/cliprdr.h>
34
35
#include "../../../channels/client/addin.h"
36
37
#include "cliprdr_main.h"
38
#include "cliprdr_format.h"
39
#include "../cliprdr_common.h"
40
41
const char* type_FileGroupDescriptorW = "FileGroupDescriptorW";
42
const char* type_FileContents = "FileContents";
43
44
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr)
45
0
{
46
0
  CliprdrClientContext* pInterface = NULL;
47
48
0
  if (!cliprdr)
49
0
    return NULL;
50
51
0
  pInterface = (CliprdrClientContext*)cliprdr->channelEntryPoints.pInterface;
52
0
  return pInterface;
53
0
}
54
55
/**
56
 * Function description
57
 *
58
 * @return 0 on success, otherwise a Win32 error code
59
 */
60
static UINT cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s)
61
0
{
62
0
  size_t pos = 0;
63
0
  UINT32 dataLen = 0;
64
0
  UINT status = CHANNEL_RC_OK;
65
66
0
  WINPR_ASSERT(cliprdr);
67
0
  WINPR_ASSERT(s);
68
69
0
  pos = Stream_GetPosition(s);
70
0
  dataLen = pos - 8;
71
0
  Stream_SetPosition(s, 4);
72
0
  Stream_Write_UINT32(s, dataLen);
73
0
  Stream_SetPosition(s, pos);
74
75
0
  WLog_DBG(TAG, "Cliprdr Sending (%" PRIu32 " bytes)", dataLen + 8);
76
77
0
  if (!cliprdr)
78
0
  {
79
0
    status = CHANNEL_RC_BAD_INIT_HANDLE;
80
0
  }
81
0
  else
82
0
  {
83
0
    WINPR_ASSERT(cliprdr->channelEntryPoints.pVirtualChannelWriteEx);
84
0
    status = cliprdr->channelEntryPoints.pVirtualChannelWriteEx(
85
0
        cliprdr->InitHandle, cliprdr->OpenHandle, Stream_Buffer(s),
86
0
        (UINT32)Stream_GetPosition(s), s);
87
0
  }
88
89
0
  if (status != CHANNEL_RC_OK)
90
0
  {
91
0
    Stream_Free(s, TRUE);
92
0
    WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08" PRIX32 "]",
93
0
             WTSErrorToString(status), status);
94
0
  }
95
96
0
  return status;
97
0
}
98
99
UINT cliprdr_send_error_response(cliprdrPlugin* cliprdr, UINT16 type)
100
0
{
101
0
  wStream* s = cliprdr_packet_new(type, CB_RESPONSE_FAIL, 0);
102
0
  if (!s)
103
0
  {
104
0
    WLog_ERR(TAG, "cliprdr_packet_new failed!");
105
0
    return ERROR_OUTOFMEMORY;
106
0
  }
107
108
0
  return cliprdr_packet_send(cliprdr, s);
109
0
}
110
111
static void cliprdr_print_general_capability_flags(UINT32 flags)
112
0
{
113
0
  WLog_DBG(TAG, "generalFlags (0x%08" PRIX32 ") {", flags);
114
115
0
  if (flags & CB_USE_LONG_FORMAT_NAMES)
116
0
    WLog_DBG(TAG, "\tCB_USE_LONG_FORMAT_NAMES");
117
118
0
  if (flags & CB_STREAM_FILECLIP_ENABLED)
119
0
    WLog_DBG(TAG, "\tCB_STREAM_FILECLIP_ENABLED");
120
121
0
  if (flags & CB_FILECLIP_NO_FILE_PATHS)
122
0
    WLog_DBG(TAG, "\tCB_FILECLIP_NO_FILE_PATHS");
123
124
0
  if (flags & CB_CAN_LOCK_CLIPDATA)
125
0
    WLog_DBG(TAG, "\tCB_CAN_LOCK_CLIPDATA");
126
127
0
  if (flags & CB_HUGE_FILE_SUPPORT_ENABLED)
128
0
    WLog_DBG(TAG, "\tCB_HUGE_FILE_SUPPORT_ENABLED");
129
130
0
  WLog_DBG(TAG, "}");
131
0
}
132
133
/**
134
 * Function description
135
 *
136
 * @return 0 on success, otherwise a Win32 error code
137
 */
138
static UINT cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* s)
139
0
{
140
0
  UINT32 version = 0;
141
0
  UINT32 generalFlags = 0;
142
0
  CLIPRDR_CAPABILITIES capabilities = { 0 };
143
0
  CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet = { 0 };
144
0
  CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
145
0
  UINT error = CHANNEL_RC_OK;
146
147
0
  WINPR_ASSERT(cliprdr);
148
0
  WINPR_ASSERT(s);
149
150
0
  if (!context)
151
0
  {
152
0
    WLog_ERR(TAG, "cliprdr_get_client_interface failed!");
153
0
    return ERROR_INTERNAL_ERROR;
154
0
  }
155
156
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
157
0
    return ERROR_INVALID_DATA;
158
159
0
  Stream_Read_UINT32(s, version);      /* version (4 bytes) */
160
0
  Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
161
0
  WLog_DBG(TAG, "Version: %" PRIu32 "", version);
162
163
0
  cliprdr_print_general_capability_flags(generalFlags);
164
165
0
  cliprdr->useLongFormatNames = (generalFlags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : FALSE;
166
0
  cliprdr->streamFileClipEnabled = (generalFlags & CB_STREAM_FILECLIP_ENABLED) ? TRUE : FALSE;
167
0
  cliprdr->fileClipNoFilePaths = (generalFlags & CB_FILECLIP_NO_FILE_PATHS) ? TRUE : FALSE;
168
0
  cliprdr->canLockClipData = (generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE;
169
0
  cliprdr->hasHugeFileSupport = (generalFlags & CB_HUGE_FILE_SUPPORT_ENABLED) ? TRUE : FALSE;
170
0
  cliprdr->capabilitiesReceived = TRUE;
171
172
0
  capabilities.common.msgType = CB_CLIP_CAPS;
173
0
  capabilities.cCapabilitiesSets = 1;
174
0
  capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&(generalCapabilitySet);
175
0
  generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL;
176
0
  generalCapabilitySet.capabilitySetLength = 12;
177
0
  generalCapabilitySet.version = version;
178
0
  generalCapabilitySet.generalFlags = generalFlags;
179
0
  IFCALLRET(context->ServerCapabilities, error, context, &capabilities);
180
181
0
  if (error)
182
0
    WLog_ERR(TAG, "ServerCapabilities failed with error %" PRIu32 "!", error);
183
184
0
  return error;
185
0
}
186
187
/**
188
 * Function description
189
 *
190
 * @return 0 on success, otherwise a Win32 error code
191
 */
192
static UINT cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT32 length,
193
                                      UINT16 flags)
194
0
{
195
0
  UINT16 lengthCapability = 0;
196
0
  UINT16 cCapabilitiesSets = 0;
197
0
  UINT16 capabilitySetType = 0;
198
0
  UINT error = CHANNEL_RC_OK;
199
200
0
  WINPR_ASSERT(cliprdr);
201
0
  WINPR_ASSERT(s);
202
203
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
204
0
    return ERROR_INVALID_DATA;
205
206
0
  Stream_Read_UINT16(s, cCapabilitiesSets); /* cCapabilitiesSets (2 bytes) */
207
0
  Stream_Seek_UINT16(s);                    /* pad1 (2 bytes) */
208
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerCapabilities");
209
210
0
  for (UINT16 index = 0; index < cCapabilitiesSets; index++)
211
0
  {
212
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
213
0
      return ERROR_INVALID_DATA;
214
215
0
    Stream_Read_UINT16(s, capabilitySetType); /* capabilitySetType (2 bytes) */
216
0
    Stream_Read_UINT16(s, lengthCapability);  /* lengthCapability (2 bytes) */
217
218
0
    if ((lengthCapability < 4) ||
219
0
        (!Stream_CheckAndLogRequiredLength(TAG, s, lengthCapability - 4U)))
220
0
      return ERROR_INVALID_DATA;
221
222
0
    switch (capabilitySetType)
223
0
    {
224
0
      case CB_CAPSTYPE_GENERAL:
225
0
        if ((error = cliprdr_process_general_capability(cliprdr, s)))
226
0
        {
227
0
          WLog_ERR(TAG,
228
0
                   "cliprdr_process_general_capability failed with error %" PRIu32 "!",
229
0
                   error);
230
0
          return error;
231
0
        }
232
233
0
        break;
234
235
0
      default:
236
0
        WLog_ERR(TAG, "unknown cliprdr capability set: %" PRIu16 "", capabilitySetType);
237
0
        return CHANNEL_RC_BAD_PROC;
238
0
    }
239
0
  }
240
241
0
  return error;
242
0
}
243
244
/**
245
 * Function description
246
 *
247
 * @return 0 on success, otherwise a Win32 error code
248
 */
249
static UINT cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT32 length,
250
                                          UINT16 flags)
251
0
{
252
0
  CLIPRDR_MONITOR_READY monitorReady = { 0 };
253
0
  CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
254
0
  UINT error = CHANNEL_RC_OK;
255
256
0
  WINPR_ASSERT(cliprdr);
257
0
  WINPR_ASSERT(s);
258
259
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "MonitorReady");
260
261
0
  if (!cliprdr->capabilitiesReceived)
262
0
  {
263
    /**
264
     * The clipboard capabilities pdu from server to client is optional,
265
     * but a server using it must send it before sending the monitor ready pdu.
266
     * When the server capabilities pdu is not used, default capabilities
267
     * corresponding to a generalFlags field set to zero are assumed.
268
     */
269
0
    cliprdr->useLongFormatNames = FALSE;
270
0
    cliprdr->streamFileClipEnabled = FALSE;
271
0
    cliprdr->fileClipNoFilePaths = TRUE;
272
0
    cliprdr->canLockClipData = FALSE;
273
0
  }
274
275
0
  monitorReady.common.msgType = CB_MONITOR_READY;
276
0
  monitorReady.common.msgFlags = flags;
277
0
  monitorReady.common.dataLen = length;
278
0
  IFCALLRET(context->MonitorReady, error, context, &monitorReady);
279
280
0
  if (error)
281
0
    WLog_ERR(TAG, "MonitorReady failed with error %" PRIu32 "!", error);
282
283
0
  return error;
284
0
}
285
286
/**
287
 * Function description
288
 *
289
 * @return 0 on success, otherwise a Win32 error code
290
 */
291
static UINT cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream* s, UINT32 length,
292
                                                 UINT16 flags)
293
0
{
294
0
  CLIPRDR_FILE_CONTENTS_REQUEST request = { 0 };
295
0
  CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
296
0
  UINT error = CHANNEL_RC_OK;
297
298
0
  WINPR_ASSERT(cliprdr);
299
0
  WINPR_ASSERT(s);
300
301
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsRequest");
302
303
0
  request.common.msgType = CB_FILECONTENTS_REQUEST;
304
0
  request.common.msgFlags = flags;
305
0
  request.common.dataLen = length;
306
307
0
  if ((error = cliprdr_read_file_contents_request(s, &request)))
308
0
    return error;
309
310
0
  const UINT32 mask =
311
0
      freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
312
0
  if ((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) == 0)
313
0
  {
314
0
    WLog_WARN(TAG, "local -> remote file copy disabled, ignoring request");
315
0
    return cliprdr_send_error_response(cliprdr, CB_FILECONTENTS_RESPONSE);
316
0
  }
317
0
  IFCALLRET(context->ServerFileContentsRequest, error, context, &request);
318
319
0
  if (error)
320
0
    WLog_ERR(TAG, "ServerFileContentsRequest failed with error %" PRIu32 "!", error);
321
322
0
  return error;
323
0
}
324
325
/**
326
 * Function description
327
 *
328
 * @return 0 on success, otherwise a Win32 error code
329
 */
330
static UINT cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, wStream* s, UINT32 length,
331
                                                  UINT16 flags)
332
0
{
333
0
  CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 };
334
0
  CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
335
0
  UINT error = CHANNEL_RC_OK;
336
337
0
  WINPR_ASSERT(cliprdr);
338
0
  WINPR_ASSERT(s);
339
340
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "FileContentsResponse");
341
342
0
  response.common.msgType = CB_FILECONTENTS_RESPONSE;
343
0
  response.common.msgFlags = flags;
344
0
  response.common.dataLen = length;
345
346
0
  if ((error = cliprdr_read_file_contents_response(s, &response)))
347
0
    return error;
348
349
0
  IFCALLRET(context->ServerFileContentsResponse, error, context, &response);
350
351
0
  if (error)
352
0
    WLog_ERR(TAG, "ServerFileContentsResponse failed with error %" PRIu32 "!", error);
353
354
0
  return error;
355
0
}
356
357
/**
358
 * Function description
359
 *
360
 * @return 0 on success, otherwise a Win32 error code
361
 */
362
static UINT cliprdr_process_lock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length,
363
                                          UINT16 flags)
364
0
{
365
0
  CLIPRDR_LOCK_CLIPBOARD_DATA lockClipboardData = { 0 };
366
0
  CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
367
0
  UINT error = CHANNEL_RC_OK;
368
369
0
  WINPR_ASSERT(cliprdr);
370
0
  WINPR_ASSERT(s);
371
372
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "LockClipData");
373
374
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
375
0
    return ERROR_INVALID_DATA;
376
377
0
  lockClipboardData.common.msgType = CB_LOCK_CLIPDATA;
378
0
  lockClipboardData.common.msgFlags = flags;
379
0
  lockClipboardData.common.dataLen = length;
380
0
  Stream_Read_UINT32(s, lockClipboardData.clipDataId); /* clipDataId (4 bytes) */
381
0
  IFCALLRET(context->ServerLockClipboardData, error, context, &lockClipboardData);
382
383
0
  if (error)
384
0
    WLog_ERR(TAG, "ServerLockClipboardData failed with error %" PRIu32 "!", error);
385
386
0
  return error;
387
0
}
388
389
/**
390
 * Function description
391
 *
392
 * @return 0 on success, otherwise a Win32 error code
393
 */
394
static UINT cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, UINT32 length,
395
                                            UINT16 flags)
396
0
{
397
0
  CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData = { 0 };
398
0
  CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr);
399
0
  UINT error = CHANNEL_RC_OK;
400
401
0
  WINPR_ASSERT(cliprdr);
402
0
  WINPR_ASSERT(s);
403
404
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "UnlockClipData");
405
406
0
  if ((error = cliprdr_read_unlock_clipdata(s, &unlockClipboardData)))
407
0
    return error;
408
409
0
  unlockClipboardData.common.msgType = CB_UNLOCK_CLIPDATA;
410
0
  unlockClipboardData.common.msgFlags = flags;
411
0
  unlockClipboardData.common.dataLen = length;
412
413
0
  IFCALLRET(context->ServerUnlockClipboardData, error, context, &unlockClipboardData);
414
415
0
  if (error)
416
0
    WLog_ERR(TAG, "ServerUnlockClipboardData failed with error %" PRIu32 "!", error);
417
418
0
  return error;
419
0
}
420
421
/**
422
 * Function description
423
 *
424
 * @return 0 on success, otherwise a Win32 error code
425
 */
426
static UINT cliprdr_order_recv(LPVOID userdata, wStream* s)
427
0
{
428
0
  cliprdrPlugin* cliprdr = userdata;
429
0
  UINT16 msgType = 0;
430
0
  UINT16 msgFlags = 0;
431
0
  UINT32 dataLen = 0;
432
0
  UINT error = 0;
433
434
0
  WINPR_ASSERT(cliprdr);
435
0
  WINPR_ASSERT(s);
436
437
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
438
0
    return ERROR_INVALID_DATA;
439
440
0
  Stream_Read_UINT16(s, msgType);  /* msgType (2 bytes) */
441
0
  Stream_Read_UINT16(s, msgFlags); /* msgFlags (2 bytes) */
442
0
  Stream_Read_UINT32(s, dataLen);  /* dataLen (4 bytes) */
443
444
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, dataLen))
445
0
    return ERROR_INVALID_DATA;
446
447
0
  char buffer1[64] = { 0 };
448
0
  char buffer2[64] = { 0 };
449
0
  WLog_DBG(TAG, "msgType: %s (%" PRIu16 "), msgFlags: %s dataLen: %" PRIu32 "",
450
0
           CB_MSG_TYPE_STRING(msgType, buffer1, sizeof(buffer1)), msgType,
451
0
           CB_MSG_FLAGS_STRING(msgFlags, buffer2, sizeof(buffer2)), dataLen);
452
453
0
  switch (msgType)
454
0
  {
455
0
    case CB_CLIP_CAPS:
456
0
      if ((error = cliprdr_process_clip_caps(cliprdr, s, dataLen, msgFlags)))
457
0
        WLog_ERR(TAG, "cliprdr_process_clip_caps failed with error %" PRIu32 "!", error);
458
459
0
      break;
460
461
0
    case CB_MONITOR_READY:
462
0
      if ((error = cliprdr_process_monitor_ready(cliprdr, s, dataLen, msgFlags)))
463
0
        WLog_ERR(TAG, "cliprdr_process_monitor_ready failed with error %" PRIu32 "!",
464
0
                 error);
465
466
0
      break;
467
468
0
    case CB_FORMAT_LIST:
469
0
      if ((error = cliprdr_process_format_list(cliprdr, s, dataLen, msgFlags)))
470
0
        WLog_ERR(TAG, "cliprdr_process_format_list failed with error %" PRIu32 "!", error);
471
472
0
      break;
473
474
0
    case CB_FORMAT_LIST_RESPONSE:
475
0
      if ((error = cliprdr_process_format_list_response(cliprdr, s, dataLen, msgFlags)))
476
0
        WLog_ERR(TAG, "cliprdr_process_format_list_response failed with error %" PRIu32 "!",
477
0
                 error);
478
479
0
      break;
480
481
0
    case CB_FORMAT_DATA_REQUEST:
482
0
      if ((error = cliprdr_process_format_data_request(cliprdr, s, dataLen, msgFlags)))
483
0
        WLog_ERR(TAG, "cliprdr_process_format_data_request failed with error %" PRIu32 "!",
484
0
                 error);
485
486
0
      break;
487
488
0
    case CB_FORMAT_DATA_RESPONSE:
489
0
      if ((error = cliprdr_process_format_data_response(cliprdr, s, dataLen, msgFlags)))
490
0
        WLog_ERR(TAG, "cliprdr_process_format_data_response failed with error %" PRIu32 "!",
491
0
                 error);
492
493
0
      break;
494
495
0
    case CB_FILECONTENTS_REQUEST:
496
0
      if ((error = cliprdr_process_filecontents_request(cliprdr, s, dataLen, msgFlags)))
497
0
        WLog_ERR(TAG, "cliprdr_process_filecontents_request failed with error %" PRIu32 "!",
498
0
                 error);
499
500
0
      break;
501
502
0
    case CB_FILECONTENTS_RESPONSE:
503
0
      if ((error = cliprdr_process_filecontents_response(cliprdr, s, dataLen, msgFlags)))
504
0
        WLog_ERR(TAG,
505
0
                 "cliprdr_process_filecontents_response failed with error %" PRIu32 "!",
506
0
                 error);
507
508
0
      break;
509
510
0
    case CB_LOCK_CLIPDATA:
511
0
      if ((error = cliprdr_process_lock_clipdata(cliprdr, s, dataLen, msgFlags)))
512
0
        WLog_ERR(TAG, "cliprdr_process_lock_clipdata failed with error %" PRIu32 "!",
513
0
                 error);
514
515
0
      break;
516
517
0
    case CB_UNLOCK_CLIPDATA:
518
0
      if ((error = cliprdr_process_unlock_clipdata(cliprdr, s, dataLen, msgFlags)))
519
0
        WLog_ERR(TAG, "cliprdr_process_unlock_clipdata failed with error %" PRIu32 "!",
520
0
                 error);
521
522
0
      break;
523
524
0
    default:
525
0
      error = CHANNEL_RC_BAD_PROC;
526
0
      WLog_ERR(TAG, "unknown msgType %" PRIu16 "", msgType);
527
0
      break;
528
0
  }
529
530
0
  Stream_Free(s, TRUE);
531
0
  return error;
532
0
}
533
534
/**
535
 * Callback Interface
536
 */
537
538
/**
539
 * Function description
540
 *
541
 * @return 0 on success, otherwise a Win32 error code
542
 */
543
static UINT cliprdr_client_capabilities(CliprdrClientContext* context,
544
                                        const CLIPRDR_CAPABILITIES* capabilities)
545
0
{
546
0
  wStream* s = NULL;
547
0
  UINT32 flags = 0;
548
0
  const CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet = NULL;
549
0
  cliprdrPlugin* cliprdr = NULL;
550
551
0
  WINPR_ASSERT(context);
552
553
0
  cliprdr = (cliprdrPlugin*)context->handle;
554
0
  WINPR_ASSERT(cliprdr);
555
556
0
  s = cliprdr_packet_new(CB_CLIP_CAPS, 0, 4 + CB_CAPSTYPE_GENERAL_LEN);
557
558
0
  if (!s)
559
0
  {
560
0
    WLog_ERR(TAG, "cliprdr_packet_new failed!");
561
0
    return ERROR_INTERNAL_ERROR;
562
0
  }
563
564
0
  Stream_Write_UINT16(s, 1); /* cCapabilitiesSets */
565
0
  Stream_Write_UINT16(s, 0); /* pad1 */
566
0
  generalCapabilitySet = (const CLIPRDR_GENERAL_CAPABILITY_SET*)capabilities->capabilitySets;
567
0
  Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetType);   /* capabilitySetType */
568
0
  Stream_Write_UINT16(s, generalCapabilitySet->capabilitySetLength); /* lengthCapability */
569
0
  Stream_Write_UINT32(s, generalCapabilitySet->version);             /* version */
570
0
  flags = generalCapabilitySet->generalFlags;
571
572
  /* Client capabilities are sent in response to server capabilities.
573
   * -> Do not request features the server does not support.
574
   * -> Update clipboard context feature state to what was agreed upon.
575
   */
576
0
  if (!cliprdr->useLongFormatNames)
577
0
    flags &= ~CB_USE_LONG_FORMAT_NAMES;
578
0
  if (!cliprdr->streamFileClipEnabled)
579
0
    flags &= ~CB_STREAM_FILECLIP_ENABLED;
580
0
  if (!cliprdr->fileClipNoFilePaths)
581
0
    flags &= ~CB_FILECLIP_NO_FILE_PATHS;
582
0
  if (!cliprdr->canLockClipData)
583
0
    flags &= ~CB_CAN_LOCK_CLIPDATA;
584
0
  if (!cliprdr->hasHugeFileSupport)
585
0
    flags &= ~CB_HUGE_FILE_SUPPORT_ENABLED;
586
587
0
  cliprdr->useLongFormatNames = (flags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : FALSE;
588
0
  cliprdr->streamFileClipEnabled = (flags & CB_STREAM_FILECLIP_ENABLED) ? TRUE : FALSE;
589
0
  cliprdr->fileClipNoFilePaths = (flags & CB_FILECLIP_NO_FILE_PATHS) ? TRUE : FALSE;
590
0
  cliprdr->canLockClipData = (flags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE;
591
0
  cliprdr->hasHugeFileSupport = (flags & CB_HUGE_FILE_SUPPORT_ENABLED) ? TRUE : FALSE;
592
593
0
  Stream_Write_UINT32(s, flags); /* generalFlags */
594
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientCapabilities");
595
596
0
  cliprdr->initialFormatListSent = FALSE;
597
598
0
  return cliprdr_packet_send(cliprdr, s);
599
0
}
600
601
/**
602
 * Function description
603
 *
604
 * @return 0 on success, otherwise a Win32 error code
605
 */
606
static UINT cliprdr_temp_directory(CliprdrClientContext* context,
607
                                   const CLIPRDR_TEMP_DIRECTORY* tempDirectory)
608
0
{
609
0
  wStream* s = NULL;
610
0
  cliprdrPlugin* cliprdr = NULL;
611
612
0
  WINPR_ASSERT(context);
613
0
  WINPR_ASSERT(tempDirectory);
614
615
0
  cliprdr = (cliprdrPlugin*)context->handle;
616
0
  WINPR_ASSERT(cliprdr);
617
618
0
  const size_t tmpDirCharLen = sizeof(tempDirectory->szTempDir) / sizeof(WCHAR);
619
0
  s = cliprdr_packet_new(CB_TEMP_DIRECTORY, 0, tmpDirCharLen * sizeof(WCHAR));
620
621
0
  if (!s)
622
0
  {
623
0
    WLog_ERR(TAG, "cliprdr_packet_new failed!");
624
0
    return ERROR_INTERNAL_ERROR;
625
0
  }
626
627
0
  if (Stream_Write_UTF16_String_From_UTF8(s, tmpDirCharLen - 1, tempDirectory->szTempDir,
628
0
                                          ARRAYSIZE(tempDirectory->szTempDir), TRUE) < 0)
629
0
  {
630
0
    Stream_Free(s, TRUE);
631
0
    return ERROR_INTERNAL_ERROR;
632
0
  }
633
  /* Path must be 260 UTF16 characters with '\0' termination.
634
   * ensure this here */
635
0
  Stream_Write_UINT16(s, 0);
636
637
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "TempDirectory: %s", tempDirectory->szTempDir);
638
0
  return cliprdr_packet_send(cliprdr, s);
639
0
}
640
641
/**
642
 * Function description
643
 *
644
 * @return 0 on success, otherwise a Win32 error code
645
 */
646
static UINT cliprdr_client_format_list(CliprdrClientContext* context,
647
                                       const CLIPRDR_FORMAT_LIST* formatList)
648
0
{
649
0
  wStream* s = NULL;
650
0
  cliprdrPlugin* cliprdr = NULL;
651
652
0
  WINPR_ASSERT(context);
653
0
  WINPR_ASSERT(formatList);
654
655
0
  cliprdr = (cliprdrPlugin*)context->handle;
656
0
  WINPR_ASSERT(cliprdr);
657
658
0
  {
659
0
    const UINT32 mask = CB_RESPONSE_OK | CB_RESPONSE_FAIL;
660
0
    if ((formatList->common.msgFlags & mask) != 0)
661
0
      WLog_WARN(TAG,
662
0
                "Sending clipboard request with invalid flags msgFlags = 0x%08" PRIx32
663
0
                ". Correct in your client!",
664
0
                formatList->common.msgFlags & mask);
665
0
  }
666
667
0
  const UINT32 mask =
668
0
      freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
669
0
  CLIPRDR_FORMAT_LIST filterList = cliprdr_filter_format_list(
670
0
      formatList, mask, CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES);
671
672
  /* Allow initial format list from monitor ready, but ignore later attempts */
673
0
  if ((filterList.numFormats == 0) && cliprdr->initialFormatListSent)
674
0
  {
675
0
    cliprdr_free_format_list(&filterList);
676
0
    return CHANNEL_RC_OK;
677
0
  }
678
0
  cliprdr->initialFormatListSent = TRUE;
679
680
0
  s = cliprdr_packet_format_list_new(&filterList, cliprdr->useLongFormatNames, FALSE);
681
0
  cliprdr_free_format_list(&filterList);
682
683
0
  if (!s)
684
0
  {
685
0
    WLog_ERR(TAG, "cliprdr_packet_format_list_new failed!");
686
0
    return ERROR_INTERNAL_ERROR;
687
0
  }
688
689
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatList: numFormats: %" PRIu32 "",
690
0
             formatList->numFormats);
691
0
  return cliprdr_packet_send(cliprdr, s);
692
0
}
693
694
/**
695
 * Function description
696
 *
697
 * @return 0 on success, otherwise a Win32 error code
698
 */
699
static UINT
700
cliprdr_client_format_list_response(CliprdrClientContext* context,
701
                                    const CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse)
702
0
{
703
0
  wStream* s = NULL;
704
0
  cliprdrPlugin* cliprdr = NULL;
705
706
0
  WINPR_ASSERT(context);
707
0
  WINPR_ASSERT(formatListResponse);
708
709
0
  cliprdr = (cliprdrPlugin*)context->handle;
710
0
  WINPR_ASSERT(cliprdr);
711
712
0
  s = cliprdr_packet_new(CB_FORMAT_LIST_RESPONSE, formatListResponse->common.msgFlags, 0);
713
714
0
  if (!s)
715
0
  {
716
0
    WLog_ERR(TAG, "cliprdr_packet_new failed!");
717
0
    return ERROR_INTERNAL_ERROR;
718
0
  }
719
720
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatListResponse");
721
0
  return cliprdr_packet_send(cliprdr, s);
722
0
}
723
724
/**
725
 * Function description
726
 *
727
 * @return 0 on success, otherwise a Win32 error code
728
 */
729
static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context,
730
                                               const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData)
731
0
{
732
0
  wStream* s = NULL;
733
0
  cliprdrPlugin* cliprdr = NULL;
734
735
0
  WINPR_ASSERT(context);
736
0
  WINPR_ASSERT(lockClipboardData);
737
738
0
  cliprdr = (cliprdrPlugin*)context->handle;
739
0
  WINPR_ASSERT(cliprdr);
740
741
0
  s = cliprdr_packet_lock_clipdata_new(lockClipboardData);
742
743
0
  if (!s)
744
0
  {
745
0
    WLog_ERR(TAG, "cliprdr_packet_lock_clipdata_new failed!");
746
0
    return ERROR_INTERNAL_ERROR;
747
0
  }
748
749
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientLockClipboardData: clipDataId: 0x%08" PRIX32 "",
750
0
             lockClipboardData->clipDataId);
751
0
  return cliprdr_packet_send(cliprdr, s);
752
0
}
753
754
/**
755
 * Function description
756
 *
757
 * @return 0 on success, otherwise a Win32 error code
758
 */
759
static UINT
760
cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context,
761
                                     const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData)
762
0
{
763
0
  wStream* s = NULL;
764
0
  cliprdrPlugin* cliprdr = NULL;
765
766
0
  WINPR_ASSERT(context);
767
0
  WINPR_ASSERT(unlockClipboardData);
768
769
0
  cliprdr = (cliprdrPlugin*)context->handle;
770
0
  WINPR_ASSERT(cliprdr);
771
772
0
  s = cliprdr_packet_unlock_clipdata_new(unlockClipboardData);
773
774
0
  if (!s)
775
0
  {
776
0
    WLog_ERR(TAG, "cliprdr_packet_unlock_clipdata_new failed!");
777
0
    return ERROR_INTERNAL_ERROR;
778
0
  }
779
780
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientUnlockClipboardData: clipDataId: 0x%08" PRIX32 "",
781
0
             unlockClipboardData->clipDataId);
782
0
  return cliprdr_packet_send(cliprdr, s);
783
0
}
784
785
/**
786
 * Function description
787
 *
788
 * @return 0 on success, otherwise a Win32 error code
789
 */
790
static UINT cliprdr_client_format_data_request(CliprdrClientContext* context,
791
                                               const CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest)
792
0
{
793
0
  wStream* s = NULL;
794
0
  cliprdrPlugin* cliprdr = NULL;
795
796
0
  WINPR_ASSERT(context);
797
0
  WINPR_ASSERT(formatDataRequest);
798
799
0
  cliprdr = (cliprdrPlugin*)context->handle;
800
0
  WINPR_ASSERT(cliprdr);
801
802
0
  const UINT32 mask =
803
0
      freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
804
0
  if ((mask & (CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES)) == 0)
805
0
  {
806
0
    WLog_WARN(TAG, "remote -> local copy disabled, ignoring request");
807
0
    return CHANNEL_RC_OK;
808
0
  }
809
0
  s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
810
811
0
  if (!s)
812
0
  {
813
0
    WLog_ERR(TAG, "cliprdr_packet_new failed!");
814
0
    return ERROR_INTERNAL_ERROR;
815
0
  }
816
817
0
  Stream_Write_UINT32(s, formatDataRequest->requestedFormatId); /* requestedFormatId (4 bytes) */
818
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataRequest");
819
0
  return cliprdr_packet_send(cliprdr, s);
820
0
}
821
822
/**
823
 * Function description
824
 *
825
 * @return 0 on success, otherwise a Win32 error code
826
 */
827
static UINT
828
cliprdr_client_format_data_response(CliprdrClientContext* context,
829
                                    const CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse)
830
0
{
831
0
  wStream* s = NULL;
832
0
  cliprdrPlugin* cliprdr = NULL;
833
834
0
  WINPR_ASSERT(context);
835
0
  WINPR_ASSERT(formatDataResponse);
836
837
0
  cliprdr = (cliprdrPlugin*)context->handle;
838
0
  WINPR_ASSERT(cliprdr);
839
840
0
  const UINT32 mask =
841
0
      freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
842
0
  WINPR_ASSERT((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) != 0);
843
844
0
  s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, formatDataResponse->common.msgFlags,
845
0
                         formatDataResponse->common.dataLen);
846
847
0
  if (!s)
848
0
  {
849
0
    WLog_ERR(TAG, "cliprdr_packet_new failed!");
850
0
    return ERROR_INTERNAL_ERROR;
851
0
  }
852
853
0
  Stream_Write(s, formatDataResponse->requestedFormatData, formatDataResponse->common.dataLen);
854
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFormatDataResponse");
855
0
  return cliprdr_packet_send(cliprdr, s);
856
0
}
857
858
/**
859
 * Function description
860
 *
861
 * @return 0 on success, otherwise a Win32 error code
862
 */
863
static UINT
864
cliprdr_client_file_contents_request(CliprdrClientContext* context,
865
                                     const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest)
866
0
{
867
0
  wStream* s = NULL;
868
0
  cliprdrPlugin* cliprdr = NULL;
869
870
0
  WINPR_ASSERT(context);
871
0
  WINPR_ASSERT(fileContentsRequest);
872
873
0
  const UINT32 mask =
874
0
      freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
875
0
  if ((mask & CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES) == 0)
876
0
  {
877
0
    WLog_WARN(TAG, "remote -> local file copy disabled, ignoring request");
878
0
    return CHANNEL_RC_OK;
879
0
  }
880
881
0
  cliprdr = (cliprdrPlugin*)context->handle;
882
0
  if (!cliprdr)
883
0
    return ERROR_INTERNAL_ERROR;
884
885
0
  if (!cliprdr->hasHugeFileSupport)
886
0
  {
887
0
    if (((UINT64)fileContentsRequest->cbRequested + fileContentsRequest->nPositionLow) >
888
0
        UINT32_MAX)
889
0
      return ERROR_INVALID_PARAMETER;
890
0
    if (fileContentsRequest->nPositionHigh != 0)
891
0
      return ERROR_INVALID_PARAMETER;
892
0
  }
893
894
0
  s = cliprdr_packet_file_contents_request_new(fileContentsRequest);
895
896
0
  if (!s)
897
0
  {
898
0
    WLog_ERR(TAG, "cliprdr_packet_file_contents_request_new failed!");
899
0
    return ERROR_INTERNAL_ERROR;
900
0
  }
901
902
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsRequest: streamId: 0x%08" PRIX32 "",
903
0
             fileContentsRequest->streamId);
904
0
  return cliprdr_packet_send(cliprdr, s);
905
0
}
906
907
/**
908
 * Function description
909
 *
910
 * @return 0 on success, otherwise a Win32 error code
911
 */
912
static UINT
913
cliprdr_client_file_contents_response(CliprdrClientContext* context,
914
                                      const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse)
915
0
{
916
0
  wStream* s = NULL;
917
0
  cliprdrPlugin* cliprdr = NULL;
918
919
0
  WINPR_ASSERT(context);
920
0
  WINPR_ASSERT(fileContentsResponse);
921
922
0
  cliprdr = (cliprdrPlugin*)context->handle;
923
0
  WINPR_ASSERT(cliprdr);
924
925
0
  const UINT32 mask =
926
0
      freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
927
0
  if ((mask & CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES) == 0)
928
0
    return cliprdr_send_error_response(cliprdr, CB_FILECONTENTS_RESPONSE);
929
930
0
  s = cliprdr_packet_file_contents_response_new(fileContentsResponse);
931
932
0
  if (!s)
933
0
  {
934
0
    WLog_ERR(TAG, "cliprdr_packet_file_contents_response_new failed!");
935
0
    return ERROR_INTERNAL_ERROR;
936
0
  }
937
938
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsResponse: streamId: 0x%08" PRIX32 "",
939
0
             fileContentsResponse->streamId);
940
0
  return cliprdr_packet_send(cliprdr, s);
941
0
}
942
943
static VOID VCAPITYPE cliprdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
944
                                                            UINT event, LPVOID pData,
945
                                                            UINT32 dataLength, UINT32 totalLength,
946
                                                            UINT32 dataFlags)
947
0
{
948
0
  UINT error = CHANNEL_RC_OK;
949
0
  cliprdrPlugin* cliprdr = (cliprdrPlugin*)lpUserParam;
950
951
0
  switch (event)
952
0
  {
953
0
    case CHANNEL_EVENT_DATA_RECEIVED:
954
0
      if (!cliprdr || (cliprdr->OpenHandle != openHandle))
955
0
      {
956
0
        WLog_ERR(TAG, "error no match");
957
0
        return;
958
0
      }
959
0
      if ((error = channel_client_post_message(cliprdr->MsgsHandle, pData, dataLength,
960
0
                                               totalLength, dataFlags)))
961
0
        WLog_ERR(TAG, "failed with error %" PRIu32 "", error);
962
963
0
      break;
964
965
0
    case CHANNEL_EVENT_WRITE_CANCELLED:
966
0
    case CHANNEL_EVENT_WRITE_COMPLETE:
967
0
    {
968
0
      wStream* s = (wStream*)pData;
969
0
      Stream_Free(s, TRUE);
970
0
    }
971
0
    break;
972
973
0
    case CHANNEL_EVENT_USER:
974
0
      break;
975
0
  }
976
977
0
  if (error && cliprdr && cliprdr->context->rdpcontext)
978
0
    setChannelError(cliprdr->context->rdpcontext, error,
979
0
                    "cliprdr_virtual_channel_open_event_ex reported an error");
980
0
}
981
982
/**
983
 * Function description
984
 *
985
 * @return 0 on success, otherwise a Win32 error code
986
 */
987
static UINT cliprdr_virtual_channel_event_connected(cliprdrPlugin* cliprdr, LPVOID pData,
988
                                                    UINT32 dataLength)
989
0
{
990
0
  DWORD status = 0;
991
0
  WINPR_ASSERT(cliprdr);
992
0
  WINPR_ASSERT(cliprdr->context);
993
994
0
  WINPR_ASSERT(cliprdr->channelEntryPoints.pVirtualChannelOpenEx);
995
0
  status = cliprdr->channelEntryPoints.pVirtualChannelOpenEx(
996
0
      cliprdr->InitHandle, &cliprdr->OpenHandle, cliprdr->channelDef.name,
997
0
      cliprdr_virtual_channel_open_event_ex);
998
0
  if (status != CHANNEL_RC_OK)
999
0
    return status;
1000
1001
0
  cliprdr->MsgsHandle = channel_client_create_handler(
1002
0
      cliprdr->context->rdpcontext, cliprdr, cliprdr_order_recv, CLIPRDR_SVC_CHANNEL_NAME);
1003
0
  if (!cliprdr->MsgsHandle)
1004
0
    return ERROR_INTERNAL_ERROR;
1005
1006
0
  return status;
1007
0
}
1008
1009
/**
1010
 * Function description
1011
 *
1012
 * @return 0 on success, otherwise a Win32 error code
1013
 */
1014
static UINT cliprdr_virtual_channel_event_disconnected(cliprdrPlugin* cliprdr)
1015
0
{
1016
0
  UINT rc = 0;
1017
1018
0
  WINPR_ASSERT(cliprdr);
1019
1020
0
  channel_client_quit_handler(cliprdr->MsgsHandle);
1021
0
  cliprdr->MsgsHandle = NULL;
1022
1023
0
  if (cliprdr->OpenHandle == 0)
1024
0
    return CHANNEL_RC_OK;
1025
1026
0
  WINPR_ASSERT(cliprdr->channelEntryPoints.pVirtualChannelCloseEx);
1027
0
  rc = cliprdr->channelEntryPoints.pVirtualChannelCloseEx(cliprdr->InitHandle,
1028
0
                                                          cliprdr->OpenHandle);
1029
1030
0
  if (CHANNEL_RC_OK != rc)
1031
0
  {
1032
0
    WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1033
0
             rc);
1034
0
    return rc;
1035
0
  }
1036
1037
0
  cliprdr->OpenHandle = 0;
1038
1039
0
  return CHANNEL_RC_OK;
1040
0
}
1041
1042
/**
1043
 * Function description
1044
 *
1045
 * @return 0 on success, otherwise a Win32 error code
1046
 */
1047
static UINT cliprdr_virtual_channel_event_terminated(cliprdrPlugin* cliprdr)
1048
0
{
1049
0
  WINPR_ASSERT(cliprdr);
1050
1051
0
  cliprdr->InitHandle = 0;
1052
0
  free(cliprdr->context);
1053
0
  free(cliprdr);
1054
0
  return CHANNEL_RC_OK;
1055
0
}
1056
1057
static VOID VCAPITYPE cliprdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
1058
                                                            UINT event, LPVOID pData,
1059
                                                            UINT dataLength)
1060
0
{
1061
0
  UINT error = CHANNEL_RC_OK;
1062
0
  cliprdrPlugin* cliprdr = (cliprdrPlugin*)lpUserParam;
1063
1064
0
  if (!cliprdr || (cliprdr->InitHandle != pInitHandle))
1065
0
  {
1066
0
    WLog_ERR(TAG, "error no match");
1067
0
    return;
1068
0
  }
1069
1070
0
  switch (event)
1071
0
  {
1072
0
    case CHANNEL_EVENT_CONNECTED:
1073
0
      if ((error = cliprdr_virtual_channel_event_connected(cliprdr, pData, dataLength)))
1074
0
        WLog_ERR(TAG,
1075
0
                 "cliprdr_virtual_channel_event_connected failed with error %" PRIu32 "!",
1076
0
                 error);
1077
1078
0
      break;
1079
1080
0
    case CHANNEL_EVENT_DISCONNECTED:
1081
0
      if ((error = cliprdr_virtual_channel_event_disconnected(cliprdr)))
1082
0
        WLog_ERR(TAG,
1083
0
                 "cliprdr_virtual_channel_event_disconnected failed with error %" PRIu32
1084
0
                 "!",
1085
0
                 error);
1086
1087
0
      break;
1088
1089
0
    case CHANNEL_EVENT_TERMINATED:
1090
0
      if ((error = cliprdr_virtual_channel_event_terminated(cliprdr)))
1091
0
        WLog_ERR(TAG,
1092
0
                 "cliprdr_virtual_channel_event_terminated failed with error %" PRIu32 "!",
1093
0
                 error);
1094
1095
0
      break;
1096
0
  }
1097
1098
0
  if (error && cliprdr->context->rdpcontext)
1099
0
    setChannelError(cliprdr->context->rdpcontext, error,
1100
0
                    "cliprdr_virtual_channel_init_event reported an error");
1101
0
}
1102
1103
/* cliprdr is always built-in */
1104
#define VirtualChannelEntryEx cliprdr_VirtualChannelEntryEx
1105
1106
FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
1107
                                                         PVOID pInitHandle))
1108
0
{
1109
0
  UINT rc = 0;
1110
0
  cliprdrPlugin* cliprdr = NULL;
1111
0
  CliprdrClientContext* context = NULL;
1112
0
  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
1113
0
  cliprdr = (cliprdrPlugin*)calloc(1, sizeof(cliprdrPlugin));
1114
1115
0
  if (!cliprdr)
1116
0
  {
1117
0
    WLog_ERR(TAG, "calloc failed!");
1118
0
    return FALSE;
1119
0
  }
1120
1121
0
  cliprdr->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP |
1122
0
                                CHANNEL_OPTION_COMPRESS_RDP | CHANNEL_OPTION_SHOW_PROTOCOL;
1123
0
  (void)sprintf_s(cliprdr->channelDef.name, ARRAYSIZE(cliprdr->channelDef.name),
1124
0
                  CLIPRDR_SVC_CHANNEL_NAME);
1125
0
  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1126
0
  WINPR_ASSERT(pEntryPointsEx);
1127
1128
0
  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1129
0
      (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1130
0
  {
1131
0
    context = (CliprdrClientContext*)calloc(1, sizeof(CliprdrClientContext));
1132
1133
0
    if (!context)
1134
0
    {
1135
0
      free(cliprdr);
1136
0
      WLog_ERR(TAG, "calloc failed!");
1137
0
      return FALSE;
1138
0
    }
1139
1140
0
    context->handle = (void*)cliprdr;
1141
0
    context->custom = NULL;
1142
0
    context->ClientCapabilities = cliprdr_client_capabilities;
1143
0
    context->TempDirectory = cliprdr_temp_directory;
1144
0
    context->ClientFormatList = cliprdr_client_format_list;
1145
0
    context->ClientFormatListResponse = cliprdr_client_format_list_response;
1146
0
    context->ClientLockClipboardData = cliprdr_client_lock_clipboard_data;
1147
0
    context->ClientUnlockClipboardData = cliprdr_client_unlock_clipboard_data;
1148
0
    context->ClientFormatDataRequest = cliprdr_client_format_data_request;
1149
0
    context->ClientFormatDataResponse = cliprdr_client_format_data_response;
1150
0
    context->ClientFileContentsRequest = cliprdr_client_file_contents_request;
1151
0
    context->ClientFileContentsResponse = cliprdr_client_file_contents_response;
1152
0
    cliprdr->context = context;
1153
0
    context->rdpcontext = pEntryPointsEx->context;
1154
0
  }
1155
1156
0
  cliprdr->log = WLog_Get(CHANNELS_TAG("channels.cliprdr.client"));
1157
0
  WLog_Print(cliprdr->log, WLOG_DEBUG, "VirtualChannelEntryEx");
1158
0
  CopyMemory(&(cliprdr->channelEntryPoints), pEntryPoints,
1159
0
             sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX));
1160
0
  cliprdr->InitHandle = pInitHandle;
1161
0
  rc = cliprdr->channelEntryPoints.pVirtualChannelInitEx(
1162
0
      cliprdr, context, pInitHandle, &cliprdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1163
0
      cliprdr_virtual_channel_init_event_ex);
1164
1165
0
  if (CHANNEL_RC_OK != rc)
1166
0
  {
1167
0
    WLog_ERR(TAG, "pVirtualChannelInit failed with %s [%08" PRIX32 "]", WTSErrorToString(rc),
1168
0
             rc);
1169
0
    free(cliprdr->context);
1170
0
    free(cliprdr);
1171
0
    return FALSE;
1172
0
  }
1173
1174
0
  cliprdr->channelEntryPoints.pInterface = context;
1175
0
  return TRUE;
1176
0
}