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