FreeRDP
Loading...
Searching...
No Matches
transport.c
1
20#include <freerdp/config.h>
21
22#include "settings.h"
23
24#include <winpr/assert.h>
25
26#include <winpr/crt.h>
27#include <winpr/synch.h>
28#include <winpr/print.h>
29#include <winpr/stream.h>
30#include <winpr/winsock.h>
31#include <winpr/crypto.h>
32
33#include <freerdp/log.h>
34#include <freerdp/error.h>
35#include <freerdp/utils/ringbuffer.h>
36
37#include <openssl/bio.h>
38#include <time.h>
39#include <errno.h>
40#include <fcntl.h>
41
42#ifndef _WIN32
43#include <netdb.h>
44#include <sys/socket.h>
45#endif /* _WIN32 */
46
47#ifdef FREERDP_HAVE_VALGRIND_MEMCHECK_H
48#include <valgrind/memcheck.h>
49#endif
50
51#include "tpkt.h"
52#include "fastpath.h"
53#include "transport.h"
54#include "rdp.h"
55#include "proxy.h"
56#include "utils.h"
57#include "state.h"
58#include "childsession.h"
59
60#include "gateway/rdg.h"
61#include "gateway/wst.h"
62#include "gateway/arm.h"
63
64#define TAG FREERDP_TAG("core.transport")
65
66#define BUFFER_SIZE 16384
67
68struct rdp_transport
69{
70 TRANSPORT_LAYER layer;
71 BIO* frontBio;
72 rdpRdg* rdg;
73 rdpTsg* tsg;
74 rdpWst* wst;
75 rdpTls* tls;
76 rdpContext* context;
77 rdpNla* nla;
78 void* ReceiveExtra;
79 wStream* ReceiveBuffer;
80 TransportRecv ReceiveCallback;
81 wStreamPool* ReceivePool;
82 HANDLE connectedEvent;
83 BOOL NlaMode;
84 BOOL RdstlsMode;
85 BOOL AadMode;
86 BOOL blocking;
87 BOOL GatewayEnabled;
88 BOOL haveReadLock;
89 CRITICAL_SECTION ReadLock;
90 BOOL haveWriteLock;
91 CRITICAL_SECTION WriteLock;
92 UINT64 written;
93 HANDLE rereadEvent;
94 BOOL haveMoreBytesToRead;
95 wLog* log;
96 rdpTransportIo io;
97 HANDLE ioEvent;
98 BOOL useIoEvent;
99 BOOL earlyUserAuth;
100};
101
102typedef struct
103{
105 void* userContextShadowPtr;
106} rdpTransportLayerInt;
107
108static const char* where2str(int where, char* ibuffer, size_t ilen)
109{
110 if (!ibuffer || (ilen < 2))
111 return nullptr;
112
113 ibuffer[0] = '[';
114 size_t len = ilen - 1;
115 char* buffer = &ibuffer[1];
116 if (where & SSL_CB_ALERT)
117 winpr_str_append("SSL_CB_ALERT", buffer, len, "|");
118 if (where & SSL_ST_ACCEPT)
119 winpr_str_append("SSL_ST_ACCEPT", buffer, len, "|");
120 if (where & SSL_ST_CONNECT)
121 winpr_str_append("SSL_ST_CONNECT", buffer, len, "|");
122 if (where & SSL_CB_HANDSHAKE_DONE)
123 winpr_str_append("SSL_CB_HANDSHAKE_DONE", buffer, len, "|");
124 if (where & SSL_CB_HANDSHAKE_START)
125 winpr_str_append("SSL_CB_HANDSHAKE_START", buffer, len, "|");
126 if (where & SSL_CB_WRITE)
127 winpr_str_append("SSL_CB_WRITE", buffer, len, "|");
128 if (where & SSL_CB_READ)
129 winpr_str_append("SSL_CB_READ", buffer, len, "|");
130 if (where & SSL_CB_EXIT)
131 winpr_str_append("SSL_CB_EXIT", buffer, len, "|");
132 if (where & SSL_CB_LOOP)
133 winpr_str_append("SSL_CB_LOOP", buffer, len, "|");
134
135 char nr[32] = WINPR_C_ARRAY_INIT;
136 (void)_snprintf(nr, sizeof(nr), "]{0x%08" PRIx32 "}", (unsigned)where);
137 winpr_str_append(nr, buffer, len, "");
138 return buffer;
139}
140
141static void transport_ssl_cb(const SSL* ssl, int where, int ret)
142{
143 if (where & SSL_CB_ALERT)
144 {
145 char buffer[128] = WINPR_C_ARRAY_INIT;
146 rdpTransport* transport = (rdpTransport*)SSL_get_app_data(ssl);
147 WINPR_ASSERT(transport);
148
149 switch (ret)
150 {
151 case (SSL3_AL_FATAL << 8) | SSL_AD_ACCESS_DENIED:
152 {
153 if (!freerdp_get_last_error(transport_get_context(transport)))
154 {
155 WLog_Print(transport->log, WLOG_ERROR, "where=%s ACCESS DENIED",
156 where2str(where, buffer, sizeof(buffer)));
157 freerdp_set_last_error_log(transport_get_context(transport),
158 FREERDP_ERROR_AUTHENTICATION_FAILED);
159 }
160 }
161 break;
162
163 case (SSL3_AL_FATAL << 8) | SSL_AD_INTERNAL_ERROR:
164 {
165 WLog_Print(transport->log, WLOG_WARN, "SSL error (where=%s, ret=%d [%s, %s])",
166 where2str(where, buffer, sizeof(buffer)), ret,
167 SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
168
169 if (transport->NlaMode)
170 {
171 if (!freerdp_get_last_error(transport_get_context(transport)))
172 {
173 UINT32 kret = 0;
174 if (transport->nla)
175 kret = nla_get_error(transport->nla);
176 if (kret == 0)
177 kret = FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED;
178 freerdp_set_last_error_log(transport_get_context(transport), kret);
179 }
180 }
181 }
182 break;
183
184 case (SSL3_AL_WARNING << 8) | SSL3_AD_CLOSE_NOTIFY:
185 WLog_Print(transport->log, WLOG_DEBUG, "SSL warning (where=%s, ret=%d [%s, %s])",
186 where2str(where, buffer, sizeof(buffer)), ret,
187 SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
188 break;
189
190 default:
191 WLog_Print(transport->log, WLOG_WARN,
192 "Unhandled SSL error (where=%s, ret=%d [%s, %s])",
193 where2str(where, buffer, sizeof(buffer)), ret,
194 SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
195 break;
196 }
197 }
198}
199
200wStream* transport_send_stream_init(WINPR_ATTR_UNUSED rdpTransport* transport, size_t size)
201{
202 WINPR_ASSERT(transport);
203
204 return Stream_New(nullptr, size);
205}
206
207BOOL transport_attach(rdpTransport* transport, int sockfd)
208{
209 if (!transport)
210 return FALSE;
211 return IFCALLRESULT(FALSE, transport->io.TransportAttach, transport, sockfd);
212}
213
214static BOOL transport_default_attach(rdpTransport* transport, int sockfd)
215{
216 BIO* socketBio = nullptr;
217 BIO* bufferedBio = nullptr;
218 const rdpSettings* settings = nullptr;
219 rdpContext* context = transport_get_context(transport);
220
221 if (sockfd < 0)
222 {
223 WLog_WARN(TAG, "Running peer without socket (sockfd=%d)", sockfd);
224 return TRUE;
225 }
226
227 settings = context->settings;
228 WINPR_ASSERT(settings);
229
230 if (sockfd >= 0)
231 {
232 if (!freerdp_tcp_set_keep_alive_mode(settings, sockfd))
233 goto fail;
234
235 socketBio = BIO_new(BIO_s_simple_socket());
236
237 if (!socketBio)
238 goto fail;
239 }
240
241 bufferedBio = BIO_new(BIO_s_buffered_socket());
242 if (!bufferedBio)
243 goto fail;
244
245 if (socketBio)
246 {
247 /* Attach the socket only when this function can no longer fail.
248 * This ensures solid ownership:
249 * - if this function fails, the caller is responsible to clean up
250 * - if this function is successful, the caller MUST NOT close the socket any more.
251 */
252 BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
253 bufferedBio = BIO_push(bufferedBio, socketBio);
254 if (!bufferedBio)
255 goto fail;
256 }
257 EnterCriticalSection(&(transport->ReadLock));
258 EnterCriticalSection(&(transport->WriteLock));
259 transport->frontBio = bufferedBio;
260 LeaveCriticalSection(&(transport->WriteLock));
261 LeaveCriticalSection(&(transport->ReadLock));
262
263 return TRUE;
264fail:
265
266 if (socketBio)
267 BIO_free_all(socketBio);
268 else
269 closesocket((SOCKET)sockfd);
270
271 return FALSE;
272}
273
274BOOL transport_connect_rdp(rdpTransport* transport)
275{
276 if (!transport)
277 return FALSE;
278
279 switch (utils_authenticate(transport_get_context(transport)->instance, AUTH_RDP, FALSE))
280 {
281 case AUTH_SKIP:
282 case AUTH_SUCCESS:
283 case AUTH_NO_CREDENTIALS:
284 return TRUE;
285 case AUTH_CANCELLED:
286 freerdp_set_last_error_if_not(transport_get_context(transport),
287 FREERDP_ERROR_CONNECT_CANCELLED);
288 return FALSE;
289 default:
290 return FALSE;
291 }
292}
293
294BOOL transport_connect_tls(rdpTransport* transport)
295{
296 const rdpSettings* settings = nullptr;
297 rdpContext* context = transport_get_context(transport);
298
299 settings = context->settings;
300 WINPR_ASSERT(settings);
301
302 /* Only prompt for password if we use TLS (NLA also calls this function) */
303 if (settings->SelectedProtocol == PROTOCOL_SSL)
304 {
305 switch (utils_authenticate(context->instance, AUTH_TLS, FALSE))
306 {
307 case AUTH_SKIP:
308 case AUTH_SUCCESS:
309 case AUTH_NO_CREDENTIALS:
310 break;
311 case AUTH_CANCELLED:
312 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
313 return FALSE;
314 default:
315 return FALSE;
316 }
317 }
318
319 return IFCALLRESULT(FALSE, transport->io.TLSConnect, transport);
320}
321
322static BOOL transport_default_connect_tls(rdpTransport* transport)
323{
324 int tlsStatus = 0;
325 rdpTls* tls = nullptr;
326 rdpContext* context = nullptr;
327 rdpSettings* settings = nullptr;
328
329 WINPR_ASSERT(transport);
330
331 context = transport_get_context(transport);
332 WINPR_ASSERT(context);
333
334 settings = context->settings;
335 WINPR_ASSERT(settings);
336
337 if (!(tls = freerdp_tls_new(context)))
338 return FALSE;
339
340 transport->tls = tls;
341
342 if (transport->GatewayEnabled)
343 transport->layer = TRANSPORT_LAYER_TSG_TLS;
344 else
345 transport->layer = TRANSPORT_LAYER_TLS;
346
347 tls->hostname = settings->ServerHostname;
348 tls->serverName = settings->UserSpecifiedServerName;
349 tls->port = WINPR_ASSERTING_INT_CAST(int32_t, MIN(UINT16_MAX, settings->ServerPort));
350
351 if (tls->port == 0)
352 tls->port = 3389;
353
354 tls->isGatewayTransport = FALSE;
355 tlsStatus = freerdp_tls_connect(tls, transport->frontBio);
356
357 if (tlsStatus < 1)
358 {
359 if (tlsStatus < 0)
360 {
361 freerdp_set_last_error_if_not(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
362 }
363 else
364 {
365 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
366 }
367
368 return FALSE;
369 }
370
371 transport->frontBio = tls->bio;
372
373 /* See libfreerdp/crypto/tls.c transport_default_connect_tls
374 *
375 * we are wrapping a SSL object in the BIO and actually want to set
376 *
377 * SSL_set_info_callback there. So ensure our callback is of appropriate
378 * type for that instead of what the function prototype suggests.
379 */
380 typedef void (*ssl_cb_t)(const SSL* ssl, int type, int val);
381 ssl_cb_t fkt = transport_ssl_cb;
382
383 BIO_info_cb* bfkt = WINPR_FUNC_PTR_CAST(fkt, BIO_info_cb*);
384 BIO_callback_ctrl(tls->bio, BIO_CTRL_SET_CALLBACK, bfkt);
385 SSL_set_app_data(tls->ssl, transport);
386
387 if (!transport->frontBio)
388 {
389 WLog_Print(transport->log, WLOG_ERROR, "unable to prepend a filtering TLS bio");
390 return FALSE;
391 }
392
393 return TRUE;
394}
395
396BOOL transport_connect_nla(rdpTransport* transport, BOOL earlyUserAuth)
397{
398 rdpContext* context = nullptr;
399 rdpSettings* settings = nullptr;
400 rdpRdp* rdp = nullptr;
401 if (!transport)
402 return FALSE;
403
404 context = transport_get_context(transport);
405 WINPR_ASSERT(context);
406
407 settings = context->settings;
408 WINPR_ASSERT(settings);
409
410 rdp = context->rdp;
411 WINPR_ASSERT(rdp);
412
413 if (!transport_connect_tls(transport))
414 return FALSE;
415
416 if (!settings->Authentication)
417 return TRUE;
418
419 nla_free(rdp->nla);
420 rdp->nla = nla_new(context, transport);
421
422 if (!rdp->nla)
423 return FALSE;
424
425 nla_set_early_user_auth(rdp->nla, earlyUserAuth);
426
427 transport_set_nla_mode(transport, TRUE);
428
429 if (settings->AuthenticationServiceClass)
430 {
431 if (!nla_set_service_principal(rdp->nla, settings->AuthenticationServiceClass,
433 return FALSE;
434 }
435
436 if (nla_client_begin(rdp->nla) < 0)
437 {
438 WLog_Print(transport->log, WLOG_ERROR, "NLA begin failed");
439
440 freerdp_set_last_error_if_not(context, FREERDP_ERROR_AUTHENTICATION_FAILED);
441
442 transport_set_nla_mode(transport, FALSE);
443 return FALSE;
444 }
445
446 return rdp_client_transition_to_state(rdp, CONNECTION_STATE_NLA);
447}
448
449BOOL transport_connect_rdstls(rdpTransport* transport)
450{
451 BOOL rc = FALSE;
452 rdpRdstls* rdstls = nullptr;
453 rdpContext* context = nullptr;
454
455 WINPR_ASSERT(transport);
456
457 context = transport_get_context(transport);
458 WINPR_ASSERT(context);
459
460 if (!transport_connect_tls(transport))
461 goto fail;
462
463 rdstls = rdstls_new(context, transport);
464 if (!rdstls)
465 goto fail;
466
467 transport_set_rdstls_mode(transport, TRUE);
468
469 if (rdstls_authenticate(rdstls) < 0)
470 {
471 WLog_Print(transport->log, WLOG_ERROR, "RDSTLS authentication failed");
472 freerdp_set_last_error_if_not(context, FREERDP_ERROR_AUTHENTICATION_FAILED);
473 goto fail;
474 }
475
476 transport_set_rdstls_mode(transport, FALSE);
477 rc = TRUE;
478fail:
479 rdstls_free(rdstls);
480 return rc;
481}
482
483BOOL transport_connect_aad(rdpTransport* transport)
484{
485 rdpContext* context = nullptr;
486 rdpSettings* settings = nullptr;
487 rdpRdp* rdp = nullptr;
488 if (!transport)
489 return FALSE;
490
491 context = transport_get_context(transport);
492 WINPR_ASSERT(context);
493
494 settings = context->settings;
495 WINPR_ASSERT(settings);
496
497 rdp = context->rdp;
498 WINPR_ASSERT(rdp);
499
500 if (!transport_connect_tls(transport))
501 return FALSE;
502
503 if (!settings->Authentication)
504 return TRUE;
505
506 if (!rdp->aad)
507 return FALSE;
508
509 transport_set_aad_mode(transport, TRUE);
510
511 if (aad_client_begin(rdp->aad) < 0)
512 {
513 WLog_Print(transport->log, WLOG_ERROR, "AAD begin failed");
514
515 freerdp_set_last_error_if_not(context, FREERDP_ERROR_AUTHENTICATION_FAILED);
516
517 transport_set_aad_mode(transport, FALSE);
518 return FALSE;
519 }
520
521 return rdp_client_transition_to_state(rdp, CONNECTION_STATE_AAD);
522}
523
524static BOOL transport_can_retry(const rdpContext* context, BOOL status)
525{
526 switch (freerdp_get_last_error(context))
527 {
528 case FREERDP_ERROR_CONNECT_TARGET_BOOTING:
529 return FALSE;
530 default:
531 return !status;
532 }
533}
534
535BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, DWORD timeout)
536{
537 BOOL status = FALSE;
538 rdpSettings* settings = nullptr;
539 rdpContext* context = transport_get_context(transport);
540 BOOL rpcFallback = 0;
541
542 WINPR_ASSERT(context);
543 WINPR_ASSERT(hostname);
544
545 settings = context->settings;
546 WINPR_ASSERT(settings);
547
548 rpcFallback = !settings->GatewayHttpTransport;
549
550 if (transport->GatewayEnabled)
551 {
552 if (settings->GatewayUrl)
553 {
554 WINPR_ASSERT(!transport->wst);
555 transport->wst = wst_new(context);
556
557 if (!transport->wst)
558 return FALSE;
559
560 status = wst_connect(transport->wst, timeout);
561
562 if (status)
563 {
564 transport->frontBio = wst_get_front_bio_and_take_ownership(transport->wst);
565 WINPR_ASSERT(transport->frontBio);
566 BIO_set_nonblock(transport->frontBio, 0);
567 transport->layer = TRANSPORT_LAYER_TSG;
568 status = TRUE;
569 }
570 else
571 {
572 wst_free(transport->wst);
573 transport->wst = nullptr;
574 }
575 }
576 if (transport_can_retry(transport->context, status) && settings->GatewayHttpTransport)
577 {
578 WINPR_ASSERT(!transport->rdg);
579 transport->rdg = rdg_new(context);
580
581 if (!transport->rdg)
582 return FALSE;
583
584 status = rdg_connect(transport->rdg, timeout, &rpcFallback);
585
586 if (status)
587 {
588 transport->frontBio = rdg_get_front_bio_and_take_ownership(transport->rdg);
589 WINPR_ASSERT(transport->frontBio);
590 BIO_set_nonblock(transport->frontBio, 0);
591 transport->layer = TRANSPORT_LAYER_TSG;
592 status = TRUE;
593 }
594 else
595 {
596 rdg_free(transport->rdg);
597 transport->rdg = nullptr;
598 }
599 }
600
601 if (transport_can_retry(transport->context, status) && settings->GatewayRpcTransport &&
602 rpcFallback)
603 {
604 WINPR_ASSERT(!transport->tsg);
605 transport->tsg = tsg_new(transport);
606
607 if (!transport->tsg)
608 return FALSE;
609
610 /* Reset error condition from RDG */
611 freerdp_set_last_error_log(context, FREERDP_ERROR_SUCCESS);
612 status = tsg_connect(transport->tsg, hostname, port, timeout);
613
614 if (status)
615 {
616 transport->frontBio = tsg_get_bio(transport->tsg);
617 transport->layer = TRANSPORT_LAYER_TSG;
618 status = TRUE;
619 }
620 else
621 {
622 tsg_free(transport->tsg);
623 transport->tsg = nullptr;
624 }
625 }
626 }
627 else
628 {
629 UINT16 peerPort = 0;
630 const char* proxyHostname = nullptr;
631 const char* proxyUsername = nullptr;
632 const char* proxyPassword = nullptr;
633 BOOL isProxyConnection =
634 proxy_prepare(settings, &proxyHostname, &peerPort, &proxyUsername, &proxyPassword);
635
636 rdpTransportLayer* layer = nullptr;
637 if (isProxyConnection)
638 layer = transport_connect_layer(transport, proxyHostname, peerPort, timeout);
639 else
640 layer = transport_connect_layer(transport, hostname, port, timeout);
641
642 if (!layer)
643 return FALSE;
644
645 if (!transport_attach_layer(transport, layer))
646 {
647 transport_layer_free(layer);
648 return FALSE;
649 }
650
651 if (isProxyConnection)
652 {
653 if (!proxy_connect(context, transport->frontBio, proxyUsername, proxyPassword, hostname,
654 port))
655 return FALSE;
656 }
657
658 status = TRUE;
659 }
660
661 return status;
662}
663
664BOOL transport_connect_childsession(rdpTransport* transport)
665{
666 WINPR_ASSERT(transport);
667
668 transport->frontBio = createChildSessionBio();
669 if (!transport->frontBio)
670 return FALSE;
671
672 transport->layer = TRANSPORT_LAYER_TSG;
673 return TRUE;
674}
675
676BOOL transport_accept_rdp(rdpTransport* transport)
677{
678 return transport != nullptr;
679 /* RDP encryption */
680}
681
682BOOL transport_accept_tls(rdpTransport* transport)
683{
684 if (!transport)
685 return FALSE;
686 return IFCALLRESULT(FALSE, transport->io.TLSAccept, transport);
687}
688
689static BOOL transport_default_accept_tls(rdpTransport* transport)
690{
691 rdpContext* context = transport_get_context(transport);
692 rdpSettings* settings = nullptr;
693
694 WINPR_ASSERT(context);
695
696 settings = context->settings;
697 WINPR_ASSERT(settings);
698
699 if (!transport->tls)
700 transport->tls = freerdp_tls_new(context);
701
702 transport->layer = TRANSPORT_LAYER_TLS;
703
704 if (!freerdp_tls_accept(transport->tls, transport->frontBio, settings))
705 return FALSE;
706
707 transport->frontBio = transport->tls->bio;
708 return TRUE;
709}
710
711BOOL transport_accept_nla(rdpTransport* transport)
712{
713 rdpContext* context = transport_get_context(transport);
714 rdpSettings* settings = nullptr;
715
716 WINPR_ASSERT(context);
717
718 settings = context->settings;
719 WINPR_ASSERT(settings);
720
721 if (!IFCALLRESULT(FALSE, transport->io.TLSAccept, transport))
722 return FALSE;
723
724 /* Network Level Authentication */
725
726 if (!settings->Authentication)
727 return TRUE;
728
729 if (!transport->nla)
730 {
731 transport->nla = nla_new(context, transport);
732 transport_set_nla_mode(transport, TRUE);
733 }
734
735 if (nla_authenticate(transport->nla) < 0)
736 {
737 WLog_Print(transport->log, WLOG_ERROR, "client authentication failure");
738 transport_set_nla_mode(transport, FALSE);
739 nla_free(transport->nla);
740 transport->nla = nullptr;
741 freerdp_tls_set_alert_code(transport->tls, TLS_ALERT_LEVEL_FATAL,
742 TLS_ALERT_DESCRIPTION_ACCESS_DENIED);
743 freerdp_tls_send_alert(transport->tls);
744 return FALSE;
745 }
746
747 /* don't free nla module yet, we need to copy the credentials from it first */
748 transport_set_nla_mode(transport, FALSE);
749 return TRUE;
750}
751
752BOOL transport_accept_rdstls(rdpTransport* transport)
753{
754 BOOL rc = FALSE;
755 rdpRdstls* rdstls = nullptr;
756 rdpContext* context = nullptr;
757
758 WINPR_ASSERT(transport);
759
760 context = transport_get_context(transport);
761 WINPR_ASSERT(context);
762
763 if (!IFCALLRESULT(FALSE, transport->io.TLSAccept, transport))
764 goto fail;
765
766 rdstls = rdstls_new(context, transport);
767 if (!rdstls)
768 goto fail;
769
770 transport_set_rdstls_mode(transport, TRUE);
771
772 if (rdstls_authenticate(rdstls) < 0)
773 {
774 WLog_Print(transport->log, WLOG_ERROR, "client authentication failure");
775 freerdp_tls_set_alert_code(transport->tls, TLS_ALERT_LEVEL_FATAL,
776 TLS_ALERT_DESCRIPTION_ACCESS_DENIED);
777 freerdp_tls_send_alert(transport->tls);
778 goto fail;
779 }
780
781 transport_set_rdstls_mode(transport, FALSE);
782 rc = TRUE;
783fail:
784 rdstls_free(rdstls);
785 return rc;
786}
787
788#define WLog_ERR_BIO(transport, biofunc, bio) \
789 transport_bio_error_log(transport, biofunc, bio, __FILE__, __func__, __LINE__)
790
791static void transport_bio_error_log(rdpTransport* transport, LPCSTR biofunc,
792 WINPR_ATTR_UNUSED BIO* bio, LPCSTR file, LPCSTR func,
793 DWORD line)
794{
795 unsigned long sslerr = 0;
796 int saveerrno = 0;
797 DWORD level = 0;
798
799 WINPR_ASSERT(transport);
800
801 saveerrno = errno;
802 level = WLOG_ERROR;
803
804 if (!WLog_IsLevelActive(transport->log, level))
805 return;
806
807 if (ERR_peek_error() == 0)
808 {
809 char ebuffer[256] = WINPR_C_ARRAY_INIT;
810
811 if (saveerrno == 0)
812 WLog_PrintTextMessage(transport->log, level, line, file, func, "%s retries exceeded",
813 biofunc);
814 else
815 WLog_PrintTextMessage(transport->log, level, line, file, func,
816 "%s returned a system error %d: %s", biofunc, saveerrno,
817 winpr_strerror(saveerrno, ebuffer, sizeof(ebuffer)));
818 return;
819 }
820
821 while ((sslerr = ERR_get_error()))
822 {
823 char buf[120] = WINPR_C_ARRAY_INIT;
824
825 ERR_error_string_n(sslerr, buf, 120);
826 WLog_PrintTextMessage(transport->log, level, line, file, func, "%s returned an error: %s",
827 biofunc, buf);
828 }
829}
830
831static SSIZE_T transport_read_layer(rdpTransport* transport, BYTE* data, size_t bytes)
832{
833 SSIZE_T read = 0;
834 rdpRdp* rdp = nullptr;
835 rdpContext* context = nullptr;
836
837 WINPR_ASSERT(transport);
838
839 context = transport_get_context(transport);
840 WINPR_ASSERT(context);
841
842 rdp = context->rdp;
843 WINPR_ASSERT(rdp);
844
845 if (!transport->frontBio || (bytes > SSIZE_MAX))
846 {
847 transport->layer = TRANSPORT_LAYER_CLOSED;
848 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
849 return -1;
850 }
851
852 while (read < (SSIZE_T)bytes)
853 {
854 const SSIZE_T tr = (SSIZE_T)bytes - read;
855 int r = (int)((tr > INT_MAX) ? INT_MAX : tr);
856 ERR_clear_error();
857 int status = BIO_read(transport->frontBio, data + read, r);
858
859 if (freerdp_shall_disconnect_context(context))
860 return -1;
861
862 if (status <= 0)
863 {
864 if (!transport->frontBio || !BIO_should_retry(transport->frontBio))
865 {
866 /* something unexpected happened, let's close */
867 if (!transport->frontBio)
868 {
869 WLog_Print(transport->log, WLOG_ERROR, "BIO_read: transport->frontBio null");
870 return -1;
871 }
872
873 WLog_ERR_BIO(transport, "BIO_read", transport->frontBio);
874 transport->layer = TRANSPORT_LAYER_CLOSED;
875 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
876 return -1;
877 }
878
879 /* non blocking will survive a partial read */
880 if (!transport->blocking)
881 return read;
882
883 /* blocking means that we can't continue until we have read the number of requested
884 * bytes */
885 if (BIO_wait_read(transport->frontBio, 100) < 0)
886 {
887 WLog_ERR_BIO(transport, "BIO_wait_read", transport->frontBio);
888 return -1;
889 }
890
891 continue;
892 }
893
894#ifdef FREERDP_HAVE_VALGRIND_MEMCHECK_H
895 VALGRIND_MAKE_MEM_DEFINED(data + read, bytes - read);
896#endif
897 read += status;
898 rdp->inBytes += WINPR_ASSERTING_INT_CAST(uint64_t, status);
899 }
900
901 return read;
902}
903
918static SSIZE_T transport_read_layer_bytes(rdpTransport* transport, wStream* s, size_t toRead)
919{
920 SSIZE_T status = 0;
921 if (!transport)
922 return -1;
923
924 if (toRead > SSIZE_MAX)
925 return 0;
926
927 status = IFCALLRESULT(-1, transport->io.ReadBytes, transport, Stream_Pointer(s), toRead);
928
929 if (status <= 0)
930 return status;
931
932 Stream_Seek(s, (size_t)status);
933 return status == (SSIZE_T)toRead ? 1 : 0;
934}
935
948int transport_read_pdu(rdpTransport* transport, wStream* s)
949{
950 if (!transport)
951 return -1;
952 return IFCALLRESULT(-1, transport->io.ReadPdu, transport, s);
953}
954
955static SSIZE_T parse_nla_mode_pdu(rdpTransport* transport, wStream* stream)
956{
957 SSIZE_T pduLength = 0;
958 wStream sbuffer = WINPR_C_ARRAY_INIT;
959 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
960 /*
961 * In case NlaMode is set TSRequest package(s) are expected
962 * 0x30 = DER encoded data with these bits set:
963 * bit 6 P/C constructed
964 * bit 5 tag number - sequence
965 */
966 UINT8 typeEncoding = 0;
967 if (Stream_GetRemainingLength(s) < 1)
968 return 0;
969 Stream_Read_UINT8(s, typeEncoding);
970 if (typeEncoding == 0x30)
971 {
972 /* TSRequest (NLA) */
973 UINT8 lengthEncoding = 0;
974 if (Stream_GetRemainingLength(s) < 1)
975 return 0;
976 Stream_Read_UINT8(s, lengthEncoding);
977 if (lengthEncoding & 0x80)
978 {
979 if ((lengthEncoding & ~(0x80)) == 1)
980 {
981 UINT8 length = 0;
982 if (Stream_GetRemainingLength(s) < 1)
983 return 0;
984 Stream_Read_UINT8(s, length);
985 pduLength = length;
986 pduLength += 3;
987 }
988 else if ((lengthEncoding & ~(0x80)) == 2)
989 {
990 /* check for header bytes already read in previous calls */
991 UINT16 length = 0;
992 if (Stream_GetRemainingLength(s) < 2)
993 return 0;
994 Stream_Read_UINT16_BE(s, length);
995 pduLength = length;
996 pduLength += 4;
997 }
998 else
999 {
1000 WLog_Print(transport->log, WLOG_ERROR, "Error reading TSRequest!");
1001 return -1;
1002 }
1003 }
1004 else
1005 {
1006 pduLength = lengthEncoding;
1007 pduLength += 2;
1008 }
1009 }
1010
1011 return pduLength;
1012}
1013
1014static SSIZE_T parse_default_mode_pdu(rdpTransport* transport, wStream* stream)
1015{
1016 SSIZE_T pduLength = 0;
1017 wStream sbuffer = WINPR_C_ARRAY_INIT;
1018 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
1019
1020 UINT8 version = 0;
1021 if (Stream_GetRemainingLength(s) < 1)
1022 return 0;
1023 Stream_Read_UINT8(s, version);
1024 if (version == 0x03)
1025 {
1026 /* TPKT header */
1027 UINT16 length = 0;
1028 if (Stream_GetRemainingLength(s) < 3)
1029 return 0;
1030 Stream_Seek(s, 1);
1031 Stream_Read_UINT16_BE(s, length);
1032 pduLength = length;
1033
1034 /* min and max values according to ITU-T Rec. T.123 (01/2007) section 8 */
1035 if ((pduLength < 7) || (pduLength > 0xFFFF))
1036 {
1037 WLog_Print(transport->log, WLOG_ERROR, "tpkt - invalid pduLength: %" PRIdz, pduLength);
1038 return -1;
1039 }
1040 }
1041 else
1042 {
1043 /* Fast-Path Header */
1044 UINT8 length1 = 0;
1045 if (Stream_GetRemainingLength(s) < 1)
1046 return 0;
1047 Stream_Read_UINT8(s, length1);
1048 if (length1 & 0x80)
1049 {
1050 UINT8 length2 = 0;
1051 if (Stream_GetRemainingLength(s) < 1)
1052 return 0;
1053 Stream_Read_UINT8(s, length2);
1054 pduLength = ((length1 & 0x7F) << 8) | length2;
1055 }
1056 else
1057 pduLength = length1;
1058
1059 /*
1060 * fast-path has 7 bits for length so the maximum size, including headers is 0x8000
1061 * The theoretical minimum fast-path PDU consists only of two header bytes plus one
1062 * byte for data (e.g. fast-path input synchronize pdu)
1063 */
1064 if (pduLength < 3 || pduLength > 0x8000)
1065 {
1066 WLog_Print(transport->log, WLOG_ERROR, "fast path - invalid pduLength: %" PRIdz,
1067 pduLength);
1068 return -1;
1069 }
1070 }
1071
1072 return pduLength;
1073}
1074
1075SSIZE_T transport_parse_pdu(rdpTransport* transport, wStream* s, BOOL* incomplete)
1076{
1077 SSIZE_T pduLength = 0;
1078
1079 if (!transport)
1080 return -1;
1081
1082 if (!s)
1083 return -1;
1084
1085 if (incomplete)
1086 *incomplete = TRUE;
1087
1088 Stream_SealLength(s);
1089 if (transport->NlaMode)
1090 pduLength = parse_nla_mode_pdu(transport, s);
1091 else if (transport->RdstlsMode)
1092 pduLength = rdstls_parse_pdu(transport->log, s);
1093 else
1094 pduLength = parse_default_mode_pdu(transport, s);
1095
1096 if (pduLength <= 0)
1097 return pduLength;
1098
1099 const size_t len = Stream_Length(s);
1100 if (len > WINPR_ASSERTING_INT_CAST(size_t, pduLength))
1101 return -1;
1102
1103 if (incomplete)
1104 *incomplete = len < WINPR_ASSERTING_INT_CAST(size_t, pduLength);
1105
1106 return pduLength;
1107}
1108
1109static int transport_default_read_pdu(rdpTransport* transport, wStream* s)
1110{
1111 BOOL incomplete = 0;
1112 SSIZE_T status = 0;
1113 size_t pduLength = 0;
1114 size_t position = 0;
1115
1116 WINPR_ASSERT(transport);
1117 WINPR_ASSERT(s);
1118
1119 /* RDS AAD Auth PDUs have no length indicator. We need to determine the end of the PDU by
1120 * reading in one byte at a time until we encounter the terminating null byte */
1121 if (transport->AadMode)
1122 {
1123 BYTE c = '\0';
1124 do
1125 {
1126 const SSIZE_T rc = transport_read_layer(transport, &c, 1);
1127 if (rc != 1)
1128 return (rc == 0) ? 0 : -1;
1129 if (!Stream_EnsureRemainingCapacity(s, 1))
1130 return -1;
1131 Stream_Write_UINT8(s, c);
1132 } while (c != '\0');
1133 }
1134 else if (transport->earlyUserAuth)
1135 {
1136 if (!Stream_EnsureCapacity(s, 4))
1137 return -1;
1138 const SSIZE_T rc = transport_read_layer_bytes(transport, s, 4);
1139 if (rc != 1)
1140 return (rc == 0) ? 0 : -1;
1141 }
1142 else
1143 {
1144 /* Read in pdu length */
1145 status = transport_parse_pdu(transport, s, &incomplete);
1146 while ((status == 0) && incomplete)
1147 {
1148 if (!Stream_EnsureRemainingCapacity(s, 1))
1149 return -1;
1150 SSIZE_T rc = transport_read_layer_bytes(transport, s, 1);
1151 if (rc > INT32_MAX)
1152 return INT32_MAX;
1153 if (rc != 1)
1154 return (int)rc;
1155 status = transport_parse_pdu(transport, s, &incomplete);
1156 }
1157
1158 if (status < 0)
1159 return -1;
1160
1161 pduLength = (size_t)status;
1162
1163 /* Read in rest of the PDU */
1164 if (!Stream_EnsureCapacity(s, pduLength))
1165 return -1;
1166
1167 position = Stream_GetPosition(s);
1168 if (position > pduLength)
1169 return -1;
1170 else if (position < pduLength)
1171 {
1172 status = transport_read_layer_bytes(transport, s, pduLength - position);
1173 if (status != 1)
1174 {
1175 if ((status < INT32_MIN) || (status > INT32_MAX))
1176 return -1;
1177 return (int)status;
1178 }
1179 }
1180
1181 if (Stream_GetPosition(s) >= pduLength)
1182 WLog_Packet(transport->log, WLOG_TRACE, Stream_Buffer(s), pduLength,
1183 WLOG_PACKET_INBOUND);
1184 }
1185
1186 Stream_SealLength(s);
1187 Stream_ResetPosition(s);
1188 const size_t len = Stream_Length(s);
1189 if (len > INT32_MAX)
1190 return -1;
1191 return (int)len;
1192}
1193
1194int transport_write(rdpTransport* transport, wStream* s)
1195{
1196 if (!transport)
1197 return -1;
1198
1199 return IFCALLRESULT(-1, transport->io.WritePdu, transport, s);
1200}
1201
1202static int transport_default_write(rdpTransport* transport, wStream* s)
1203{
1204 int status = -1;
1205 rdpContext* context = transport_get_context(transport);
1206
1207 WINPR_ASSERT(transport);
1208 WINPR_ASSERT(context);
1209
1210 if (!s)
1211 return -1;
1212
1213 Stream_AddRef(s);
1214
1215 rdpRdp* rdp = context->rdp;
1216 if (!rdp)
1217 goto fail;
1218
1219 EnterCriticalSection(&(transport->WriteLock));
1220 if (!transport->frontBio)
1221 goto out_cleanup;
1222
1223 {
1224 size_t length = Stream_GetPosition(s);
1225 size_t writtenlength = length;
1226 Stream_ResetPosition(s);
1227
1228 if (length > 0)
1229 {
1230 rdp->outBytes += length;
1231 WLog_Packet(transport->log, WLOG_TRACE, Stream_Buffer(s), length, WLOG_PACKET_OUTBOUND);
1232 }
1233
1234 while (length > 0)
1235 {
1236 ERR_clear_error();
1237 const int towrite = (length > INT32_MAX) ? INT32_MAX : (int)length;
1238 status = BIO_write(transport->frontBio, Stream_ConstPointer(s), towrite);
1239
1240 if (status <= 0)
1241 {
1242 /* the buffered BIO that is at the end of the chain always says OK for writing,
1243 * so a retry means that for any reason we need to read. The most probable
1244 * is a SSL or TSG BIO in the chain.
1245 */
1246 if (!BIO_should_retry(transport->frontBio))
1247 {
1248 WLog_ERR_BIO(transport, "BIO_should_retry", transport->frontBio);
1249 goto out_cleanup;
1250 }
1251
1252 /* non-blocking can live with blocked IOs */
1253 if (!transport->blocking)
1254 {
1255 WLog_ERR_BIO(transport, "BIO_write", transport->frontBio);
1256 goto out_cleanup;
1257 }
1258
1259 if (BIO_wait_write(transport->frontBio, 100) < 0)
1260 {
1261 WLog_ERR_BIO(transport, "BIO_wait_write", transport->frontBio);
1262 status = -1;
1263 goto out_cleanup;
1264 }
1265
1266 continue;
1267 }
1268
1269 WINPR_ASSERT(context->settings);
1270 if (transport->blocking || context->settings->WaitForOutputBufferFlush)
1271 {
1272 while (BIO_write_blocked(transport->frontBio))
1273 {
1274 if (BIO_wait_write(transport->frontBio, 100) < 0)
1275 {
1276 WLog_Print(transport->log, WLOG_ERROR, "error when selecting for write");
1277 status = -1;
1278 goto out_cleanup;
1279 }
1280
1281 if (BIO_flush(transport->frontBio) < 1)
1282 {
1283 WLog_Print(transport->log, WLOG_ERROR, "error when flushing outputBuffer");
1284 status = -1;
1285 goto out_cleanup;
1286 }
1287 }
1288 }
1289
1290 const size_t ustatus = (size_t)status;
1291 if (ustatus > length)
1292 {
1293 status = -1;
1294 goto out_cleanup;
1295 }
1296
1297 length -= ustatus;
1298 Stream_Seek(s, ustatus);
1299 }
1300
1301 transport->written += writtenlength;
1302 }
1303out_cleanup:
1304
1305 if (status < 0)
1306 {
1307 /* A write error indicates that the peer has dropped the connection */
1308 transport->layer = TRANSPORT_LAYER_CLOSED;
1309 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
1310 }
1311
1312 LeaveCriticalSection(&(transport->WriteLock));
1313fail:
1314 Stream_Release(s);
1315 return status;
1316}
1317
1318BOOL transport_get_public_key(rdpTransport* transport, const BYTE** data, DWORD* length)
1319{
1320 return IFCALLRESULT(FALSE, transport->io.GetPublicKey, transport, data, length);
1321}
1322
1323static BOOL transport_default_get_public_key(rdpTransport* transport, const BYTE** data,
1324 DWORD* length)
1325{
1326 rdpTls* tls = transport_get_tls(transport);
1327 if (!tls)
1328 return FALSE;
1329
1330 *data = tls->PublicKey;
1331 *length = tls->PublicKeyLength;
1332
1333 return TRUE;
1334}
1335
1336DWORD transport_get_event_handles(rdpTransport* transport, HANDLE* events, DWORD count)
1337{
1338 DWORD nCount = 0; /* always the reread Event */
1339
1340 WINPR_ASSERT(transport);
1341 WINPR_ASSERT(events);
1342 WINPR_ASSERT(count > 0);
1343
1344 if (events)
1345 {
1346 if (count < 1)
1347 {
1348 WLog_Print(transport->log, WLOG_ERROR, "provided handles array is too small");
1349 return 0;
1350 }
1351
1352 events[nCount++] = transport->rereadEvent;
1353
1354 if (transport->useIoEvent)
1355 {
1356 if (count < 2)
1357 return 0;
1358 events[nCount++] = transport->ioEvent;
1359 }
1360 }
1361
1362 if (!transport->GatewayEnabled)
1363 {
1364 if (events)
1365 {
1366 if (nCount >= count)
1367 {
1368 WLog_Print(transport->log, WLOG_ERROR,
1369 "provided handles array is too small (count=%" PRIu32 " nCount=%" PRIu32
1370 ")",
1371 count, nCount);
1372 return 0;
1373 }
1374
1375 if (transport->frontBio)
1376 {
1377 if (BIO_get_event(transport->frontBio, &events[nCount]) != 1)
1378 {
1379 WLog_Print(transport->log, WLOG_ERROR, "error getting the frontBio handle");
1380 return 0;
1381 }
1382 nCount++;
1383 }
1384 }
1385 }
1386 else
1387 {
1388 if (transport->rdg)
1389 {
1390 const DWORD tmp =
1391 rdg_get_event_handles(transport->rdg, &events[nCount], count - nCount);
1392
1393 if (tmp == 0)
1394 return 0;
1395
1396 nCount += tmp;
1397 }
1398 else if (transport->tsg)
1399 {
1400 const DWORD tmp =
1401 tsg_get_event_handles(transport->tsg, &events[nCount], count - nCount);
1402
1403 if (tmp == 0)
1404 return 0;
1405
1406 nCount += tmp;
1407 }
1408 else if (transport->wst)
1409 {
1410 const DWORD tmp =
1411 wst_get_event_handles(transport->wst, &events[nCount], count - nCount);
1412
1413 if (tmp == 0)
1414 return 0;
1415
1416 nCount += tmp;
1417 }
1418 }
1419
1420 return nCount;
1421}
1422
1423#if defined(WITH_FREERDP_DEPRECATED)
1424void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount)
1425{
1426 DWORD nCount = 0;
1427 HANDLE events[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
1428
1429 WINPR_ASSERT(transport);
1430 WINPR_ASSERT(rfds);
1431 WINPR_ASSERT(rcount);
1432
1433 nCount = transport_get_event_handles(transport, events, ARRAYSIZE(events));
1434 *rcount = nCount + 1;
1435
1436 for (DWORD index = 0; index < nCount; index++)
1437 {
1438 rfds[index] = GetEventWaitObject(events[index]);
1439 }
1440
1441 rfds[nCount] = GetEventWaitObject(transport->rereadEvent);
1442}
1443#endif
1444
1445BOOL transport_is_write_blocked(rdpTransport* transport)
1446{
1447 WINPR_ASSERT(transport);
1448 WINPR_ASSERT(transport->frontBio);
1449 return BIO_write_blocked(transport->frontBio) != 0;
1450}
1451
1452int transport_drain_output_buffer(rdpTransport* transport)
1453{
1454 BOOL status = FALSE;
1455
1456 WINPR_ASSERT(transport);
1457 WINPR_ASSERT(transport->frontBio);
1458 if (BIO_write_blocked(transport->frontBio))
1459 {
1460 if (BIO_flush(transport->frontBio) < 1)
1461 return -1;
1462
1463 const long rc = BIO_write_blocked(transport->frontBio);
1464 status = (rc != 0);
1465 }
1466
1467 return status;
1468}
1469
1470int transport_check_fds(rdpTransport* transport)
1471{
1472 int status = 0;
1473 state_run_t recv_status = STATE_RUN_FAILED;
1474 wStream* received = nullptr;
1475 rdpContext* context = transport_get_context(transport);
1476
1477 WINPR_ASSERT(context);
1478
1479 if (transport->layer == TRANSPORT_LAYER_CLOSED)
1480 {
1481 WLog_Print(transport->log, WLOG_DEBUG, "transport_check_fds: transport layer closed");
1482 freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
1483 return -1;
1484 }
1485
1495 if ((status = transport_read_pdu(transport, transport->ReceiveBuffer)) <= 0)
1496 {
1497 if (status < 0)
1498 WLog_Print(transport->log, WLOG_DEBUG, "transport_check_fds: transport_read_pdu() - %i",
1499 status);
1500 if (transport->haveMoreBytesToRead)
1501 {
1502 transport->haveMoreBytesToRead = FALSE;
1503 (void)ResetEvent(transport->rereadEvent);
1504 }
1505 return status;
1506 }
1507
1508 received = transport->ReceiveBuffer;
1509 transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0);
1510 if (!transport->ReceiveBuffer)
1511 {
1512 Stream_Release(received);
1513 return -1;
1514 }
1515
1522 WINPR_ASSERT(transport->ReceiveCallback);
1523 recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra);
1524 Stream_Release(received);
1525
1526 if (state_run_failed(recv_status))
1527 {
1528 char buffer[64] = WINPR_C_ARRAY_INIT;
1529 WLog_Print(transport->log, WLOG_ERROR,
1530 "transport_check_fds: transport->ReceiveCallback() - %s",
1531 state_run_result_string(recv_status, buffer, ARRAYSIZE(buffer)));
1532 return -1;
1533 }
1534
1535 /* Run this again to be sure we consumed all input data.
1536 * This will be repeated until a (not fully) received packet is in buffer
1537 */
1538 if (!transport->haveMoreBytesToRead)
1539 {
1540 transport->haveMoreBytesToRead = TRUE;
1541 (void)SetEvent(transport->rereadEvent);
1542 }
1543 return recv_status;
1544}
1545
1546BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking)
1547{
1548 WINPR_ASSERT(transport);
1549
1550 return IFCALLRESULT(FALSE, transport->io.SetBlockingMode, transport, blocking);
1551}
1552
1553static BOOL transport_default_set_blocking_mode(rdpTransport* transport, BOOL blocking)
1554{
1555 WINPR_ASSERT(transport);
1556
1557 transport->blocking = blocking;
1558
1559 if (transport->frontBio)
1560 {
1561 if (!BIO_set_nonblock(transport->frontBio, !(blocking)))
1562 return FALSE;
1563 }
1564
1565 return TRUE;
1566}
1567
1568rdpTransportLayer* transport_connect_layer(rdpTransport* transport, const char* hostname, int port,
1569 DWORD timeout)
1570{
1571 WINPR_ASSERT(transport);
1572
1573 return IFCALLRESULT(nullptr, transport->io.ConnectLayer, transport, hostname, port, timeout);
1574}
1575
1576static rdpTransportLayer* transport_default_connect_layer(rdpTransport* transport,
1577 const char* hostname, int port,
1578 DWORD timeout)
1579{
1580 rdpContext* context = transport_get_context(transport);
1581 WINPR_ASSERT(context);
1582
1583 return freerdp_tcp_connect_layer(context, hostname, port, timeout);
1584}
1585
1586BOOL transport_attach_layer(rdpTransport* transport, rdpTransportLayer* layer)
1587{
1588 WINPR_ASSERT(transport);
1589 WINPR_ASSERT(layer);
1590
1591 return IFCALLRESULT(FALSE, transport->io.AttachLayer, transport, layer);
1592}
1593
1594static BOOL transport_default_attach_layer(rdpTransport* transport, rdpTransportLayer* layer)
1595{
1596 BIO* layerBio = BIO_new(BIO_s_transport_layer());
1597 if (!layerBio)
1598 goto fail;
1599
1600 {
1601 BIO* bufferedBio = BIO_new(BIO_s_buffered_socket());
1602 if (!bufferedBio)
1603 goto fail;
1604
1605 bufferedBio = BIO_push(bufferedBio, layerBio);
1606 if (!bufferedBio)
1607 goto fail;
1608
1609 /* BIO takes over the layer reference at this point. */
1610 BIO_set_data(layerBio, layer);
1611
1612 transport->frontBio = bufferedBio;
1613 }
1614 return TRUE;
1615
1616fail:
1617 if (layerBio)
1618 BIO_free_all(layerBio);
1619
1620 return FALSE;
1621}
1622
1623void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled)
1624{
1625 WINPR_ASSERT(transport);
1626 transport->GatewayEnabled = GatewayEnabled;
1627}
1628
1629void transport_set_nla_mode(rdpTransport* transport, BOOL NlaMode)
1630{
1631 WINPR_ASSERT(transport);
1632 transport->NlaMode = NlaMode;
1633}
1634
1635void transport_set_rdstls_mode(rdpTransport* transport, BOOL RdstlsMode)
1636{
1637 WINPR_ASSERT(transport);
1638 transport->RdstlsMode = RdstlsMode;
1639}
1640
1641void transport_set_aad_mode(rdpTransport* transport, BOOL AadMode)
1642{
1643 WINPR_ASSERT(transport);
1644 transport->AadMode = AadMode;
1645}
1646
1647BOOL transport_disconnect(rdpTransport* transport)
1648{
1649 if (!transport)
1650 return FALSE;
1651 return IFCALLRESULT(FALSE, transport->io.TransportDisconnect, transport);
1652}
1653
1654static BOOL transport_default_disconnect(rdpTransport* transport)
1655{
1656 BOOL status = TRUE;
1657
1658 if (!transport)
1659 return FALSE;
1660
1661 EnterCriticalSection(&(transport->ReadLock));
1662 EnterCriticalSection(&(transport->WriteLock));
1663 if (transport->tls)
1664 {
1665 freerdp_tls_free(transport->tls);
1666 transport->tls = nullptr;
1667 }
1668 else
1669 {
1670 if (transport->frontBio)
1671 BIO_free_all(transport->frontBio);
1672 }
1673
1674 if (transport->tsg)
1675 {
1676 tsg_free(transport->tsg);
1677 transport->tsg = nullptr;
1678 }
1679
1680 if (transport->rdg)
1681 {
1682 rdg_free(transport->rdg);
1683 transport->rdg = nullptr;
1684 }
1685
1686 if (transport->wst)
1687 {
1688 wst_free(transport->wst);
1689 transport->wst = nullptr;
1690 }
1691
1692 transport->frontBio = nullptr;
1693 transport->layer = TRANSPORT_LAYER_TCP;
1694 transport->earlyUserAuth = FALSE;
1695 LeaveCriticalSection(&(transport->WriteLock));
1696 LeaveCriticalSection(&(transport->ReadLock));
1697 return status;
1698}
1699
1700rdpTransport* transport_new(rdpContext* context)
1701{
1702 rdpTransport* transport = (rdpTransport*)calloc(1, sizeof(rdpTransport));
1703
1704 WINPR_ASSERT(context);
1705 if (!transport)
1706 return nullptr;
1707
1708 transport->log = WLog_Create(TAG, WLog_GetRoot());
1709
1710 if (!transport->log)
1711 goto fail;
1712
1713 transport->context = context;
1714 transport->haveReadLock = InitializeCriticalSectionAndSpinCount(&(transport->ReadLock), 4000);
1715 transport->haveWriteLock = InitializeCriticalSectionAndSpinCount(&(transport->WriteLock), 4000);
1716 if (!transport->haveReadLock || !transport->haveWriteLock)
1717 goto fail;
1718
1719 transport->ReceivePool = StreamPool_New(TRUE, BUFFER_SIZE);
1720
1721 if (!transport->ReceivePool)
1722 goto fail;
1723
1724 /* receive buffer for non-blocking read. */
1725 transport->ReceiveBuffer = StreamPool_Take(transport->ReceivePool, 0);
1726
1727 if (!transport->ReceiveBuffer)
1728 goto fail;
1729
1730 transport->connectedEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
1731
1732 if (!transport->connectedEvent || transport->connectedEvent == INVALID_HANDLE_VALUE)
1733 goto fail;
1734
1735 transport->rereadEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
1736
1737 if (!transport->rereadEvent || transport->rereadEvent == INVALID_HANDLE_VALUE)
1738 goto fail;
1739
1740 transport->ioEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
1741
1742 if (!transport->ioEvent || transport->ioEvent == INVALID_HANDLE_VALUE)
1743 goto fail;
1744
1745 transport->haveMoreBytesToRead = FALSE;
1746 transport->blocking = TRUE;
1747 transport->GatewayEnabled = FALSE;
1748 transport->layer = TRANSPORT_LAYER_TCP;
1749
1750 // transport->io.DataHandler = transport_data_handler;
1751 transport->io.TCPConnect = freerdp_tcp_default_connect;
1752 transport->io.TLSConnect = transport_default_connect_tls;
1753 transport->io.TLSAccept = transport_default_accept_tls;
1754 transport->io.TransportAttach = transport_default_attach;
1755 transport->io.TransportDisconnect = transport_default_disconnect;
1756 transport->io.ReadPdu = transport_default_read_pdu;
1757 transport->io.WritePdu = transport_default_write;
1758 transport->io.ReadBytes = transport_read_layer;
1759 transport->io.GetPublicKey = transport_default_get_public_key;
1760 transport->io.SetBlockingMode = transport_default_set_blocking_mode;
1761 transport->io.ConnectLayer = transport_default_connect_layer;
1762 transport->io.AttachLayer = transport_default_attach_layer;
1763
1764 return transport;
1765fail:
1766 WINPR_PRAGMA_DIAG_PUSH
1767 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1768 transport_free(transport);
1769 WINPR_PRAGMA_DIAG_POP
1770 return nullptr;
1771}
1772
1773void transport_free(rdpTransport* transport)
1774{
1775 if (!transport)
1776 return;
1777
1778 transport_disconnect(transport);
1779
1780 if (transport->haveReadLock)
1781 EnterCriticalSection(&(transport->ReadLock));
1782
1783 if (transport->ReceiveBuffer)
1784 Stream_Release(transport->ReceiveBuffer);
1785
1786 if (transport->haveReadLock)
1787 LeaveCriticalSection(&(transport->ReadLock));
1788
1789 if (transport->ReceivePool)
1790 (void)StreamPool_WaitForReturn(transport->ReceivePool, INFINITE);
1791
1792 if (transport->haveReadLock)
1793 EnterCriticalSection(&(transport->ReadLock));
1794
1795 if (transport->haveWriteLock)
1796 EnterCriticalSection(&(transport->WriteLock));
1797
1798 nla_free(transport->nla);
1799 StreamPool_Free(transport->ReceivePool);
1800 (void)CloseHandle(transport->connectedEvent);
1801 (void)CloseHandle(transport->rereadEvent);
1802 (void)CloseHandle(transport->ioEvent);
1803
1804 if (transport->haveReadLock)
1805 LeaveCriticalSection(&(transport->ReadLock));
1806 DeleteCriticalSection(&(transport->ReadLock));
1807
1808 if (transport->haveWriteLock)
1809 LeaveCriticalSection(&(transport->WriteLock));
1810 DeleteCriticalSection(&(transport->WriteLock));
1811 WLog_Discard(transport->log);
1812 free(transport);
1813}
1814
1815BOOL transport_set_io_callbacks(rdpTransport* transport, const rdpTransportIo* io_callbacks)
1816{
1817 if (!transport || !io_callbacks)
1818 return FALSE;
1819
1820 transport->io = *io_callbacks;
1821 return TRUE;
1822}
1823
1824const rdpTransportIo* transport_get_io_callbacks(const rdpTransport* transport)
1825{
1826 if (!transport)
1827 return nullptr;
1828 return &transport->io;
1829}
1830
1831rdpContext* transport_get_context(rdpTransport* transport)
1832{
1833 WINPR_ASSERT(transport);
1834 return transport->context;
1835}
1836
1837rdpTransport* freerdp_get_transport(rdpContext* context)
1838{
1839 WINPR_ASSERT(context);
1840 WINPR_ASSERT(context->rdp);
1841 return context->rdp->transport;
1842}
1843
1844BOOL transport_set_nla(rdpTransport* transport, rdpNla* nla)
1845{
1846 WINPR_ASSERT(transport);
1847 nla_free(transport->nla);
1848 transport->nla = nla;
1849 return TRUE;
1850}
1851
1852rdpNla* transport_get_nla(rdpTransport* transport)
1853{
1854 WINPR_ASSERT(transport);
1855 return transport->nla;
1856}
1857
1858BOOL transport_set_tls(rdpTransport* transport, rdpTls* tls)
1859{
1860 WINPR_ASSERT(transport);
1861 freerdp_tls_free(transport->tls);
1862 transport->tls = tls;
1863 return TRUE;
1864}
1865
1866rdpTls* transport_get_tls(rdpTransport* transport)
1867{
1868 WINPR_ASSERT(transport);
1869 return transport->tls;
1870}
1871
1872BOOL transport_set_tsg(rdpTransport* transport, rdpTsg* tsg)
1873{
1874 WINPR_ASSERT(transport);
1875 tsg_free(transport->tsg);
1876 transport->tsg = tsg;
1877 return TRUE;
1878}
1879
1880rdpTsg* transport_get_tsg(rdpTransport* transport)
1881{
1882 WINPR_ASSERT(transport);
1883 return transport->tsg;
1884}
1885
1886wStream* transport_take_from_pool(rdpTransport* transport, size_t size)
1887{
1888 WINPR_ASSERT(transport);
1889 if (!transport->frontBio)
1890 return nullptr;
1891 return StreamPool_Take(transport->ReceivePool, size);
1892}
1893
1894UINT64 transport_get_bytes_sent(rdpTransport* transport, BOOL resetCount)
1895{
1896 UINT64 rc = 0;
1897 WINPR_ASSERT(transport);
1898 rc = transport->written;
1899 if (resetCount)
1900 transport->written = 0;
1901 return rc;
1902}
1903
1904TRANSPORT_LAYER transport_get_layer(rdpTransport* transport)
1905{
1906 WINPR_ASSERT(transport);
1907 return transport->layer;
1908}
1909
1910BOOL transport_set_layer(rdpTransport* transport, TRANSPORT_LAYER layer)
1911{
1912 WINPR_ASSERT(transport);
1913 transport->layer = layer;
1914 return TRUE;
1915}
1916
1917BOOL transport_set_connected_event(rdpTransport* transport)
1918{
1919 WINPR_ASSERT(transport);
1920 return SetEvent(transport->connectedEvent);
1921}
1922
1923BOOL transport_set_recv_callbacks(rdpTransport* transport, TransportRecv recv, void* extra)
1924{
1925 WINPR_ASSERT(transport);
1926 transport->ReceiveCallback = recv;
1927 transport->ReceiveExtra = extra;
1928 return TRUE;
1929}
1930
1931BOOL transport_get_blocking(const rdpTransport* transport)
1932{
1933 WINPR_ASSERT(transport);
1934 return transport->blocking;
1935}
1936
1937BOOL transport_set_blocking(rdpTransport* transport, BOOL blocking)
1938{
1939 WINPR_ASSERT(transport);
1940 transport->blocking = blocking;
1941 return TRUE;
1942}
1943
1944BOOL transport_have_more_bytes_to_read(rdpTransport* transport)
1945{
1946 WINPR_ASSERT(transport);
1947 return transport->haveMoreBytesToRead;
1948}
1949
1950int transport_tcp_connect(rdpTransport* transport, const char* hostname, int port, DWORD timeout)
1951{
1952 rdpContext* context = transport_get_context(transport);
1953 WINPR_ASSERT(context);
1954 WINPR_ASSERT(context->settings);
1955 return IFCALLRESULT(-1, transport->io.TCPConnect, context, context->settings, hostname, port,
1956 timeout);
1957}
1958
1959HANDLE transport_get_front_bio(rdpTransport* transport)
1960{
1961 HANDLE hEvent = nullptr;
1962 WINPR_ASSERT(transport);
1963 WINPR_ASSERT(transport->frontBio);
1964
1965 BIO_get_event(transport->frontBio, &hEvent);
1966 return hEvent;
1967}
1968
1969BOOL transport_io_callback_set_event(rdpTransport* transport, BOOL set)
1970{
1971 WINPR_ASSERT(transport);
1972 transport->useIoEvent = TRUE;
1973 if (!set)
1974 return ResetEvent(transport->ioEvent);
1975 return SetEvent(transport->ioEvent);
1976}
1977
1978void transport_set_early_user_auth_mode(rdpTransport* transport, BOOL EUAMode)
1979{
1980 WINPR_ASSERT(transport);
1981 transport->earlyUserAuth = EUAMode;
1982 WLog_Print(transport->log, WLOG_DEBUG, "Early User Auth Mode: %s", EUAMode ? "on" : "off");
1983}
1984
1985rdpTransportLayer* transport_layer_new(WINPR_ATTR_UNUSED rdpTransport* transport,
1986 size_t contextSize)
1987{
1988 rdpTransportLayerInt* layer = (rdpTransportLayerInt*)calloc(1, sizeof(rdpTransportLayerInt));
1989 if (!layer)
1990 return nullptr;
1991
1992 if (contextSize)
1993 {
1994 layer->userContextShadowPtr = calloc(1, contextSize);
1995 if (!layer->userContextShadowPtr)
1996 {
1997 free(layer);
1998 return nullptr;
1999 }
2000 }
2001 layer->pub.userContext = layer->userContextShadowPtr;
2002
2003 return &layer->pub;
2004}
2005
2006void transport_layer_free(rdpTransportLayer* layer)
2007{
2008 rdpTransportLayerInt* intern = (rdpTransportLayerInt*)layer;
2009 if (!layer)
2010 return;
2011
2012 if (intern->pub.Close)
2013 intern->pub.Close(intern->pub.userContext);
2014 free(intern->userContextShadowPtr);
2015 free(intern);
2016}
2017
2018static int transport_layer_bio_write(BIO* bio, const char* buf, int size)
2019{
2020 if (!buf || !size)
2021 return 0;
2022 if (size < 0)
2023 return -1;
2024
2025 WINPR_ASSERT(bio);
2026
2027 rdpTransportLayer* layer = (rdpTransportLayer*)BIO_get_data(bio);
2028 if (!layer)
2029 return -1;
2030
2031 BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
2032
2033 errno = 0;
2034 const int status = IFCALLRESULT(-1, layer->Write, layer->userContext, buf, size);
2035
2036 if (status >= 0 && status < size)
2037 BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY));
2038
2039 switch (errno)
2040 {
2041 case EAGAIN:
2042 BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY));
2043 break;
2044 default:
2045 break;
2046 }
2047
2048 return status;
2049}
2050
2051static int transport_layer_bio_read(BIO* bio, char* buf, int size)
2052{
2053 if (!buf || !size)
2054 return 0;
2055 if (size < 0)
2056 return -1;
2057
2058 WINPR_ASSERT(bio);
2059
2060 rdpTransportLayer* layer = (rdpTransportLayer*)BIO_get_data(bio);
2061 if (!layer)
2062 return -1;
2063
2064 BIO_clear_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
2065 errno = 0;
2066 const int status = IFCALLRESULT(-1, layer->Read, layer->userContext, buf, size);
2067
2068 switch (errno)
2069 {
2070 case EAGAIN:
2071 BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
2072 break;
2073 default:
2074 break;
2075 }
2076
2077 return status;
2078}
2079
2080static int transport_layer_bio_puts(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED const char* str)
2081{
2082 return -2;
2083}
2084
2085static int transport_layer_bio_gets(WINPR_ATTR_UNUSED BIO* bio, WINPR_ATTR_UNUSED char* str,
2086 WINPR_ATTR_UNUSED int size)
2087{
2088 return 1;
2089}
2090
2091static long transport_layer_bio_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
2092{
2093 WINPR_ASSERT(bio);
2094
2095 rdpTransportLayer* layer = (rdpTransportLayer*)BIO_get_data(bio);
2096 if (!layer)
2097 return -1;
2098
2099 int status = -1;
2100 switch (cmd)
2101 {
2102 case BIO_C_GET_EVENT:
2103 *((HANDLE*)arg2) = IFCALLRESULT(nullptr, layer->GetEvent, layer->userContext);
2104 status = 1;
2105 break;
2106
2107 case BIO_C_SET_NONBLOCK:
2108 status = 1;
2109 break;
2110
2111 case BIO_C_WAIT_READ:
2112 {
2113 int timeout = (int)arg1;
2114 BOOL r = IFCALLRESULT(FALSE, layer->Wait, layer->userContext, FALSE,
2115 WINPR_ASSERTING_INT_CAST(uint32_t, timeout));
2116 /* Convert timeout to error return */
2117 if (!r)
2118 {
2119 errno = ETIMEDOUT;
2120 status = 0;
2121 }
2122 else
2123 status = 1;
2124 break;
2125 }
2126
2127 case BIO_C_WAIT_WRITE:
2128 {
2129 int timeout = (int)arg1;
2130 BOOL r = IFCALLRESULT(FALSE, layer->Wait, layer->userContext, TRUE,
2131 WINPR_ASSERTING_INT_CAST(uint32_t, timeout));
2132 /* Convert timeout to error return */
2133 if (!r)
2134 {
2135 errno = ETIMEDOUT;
2136 status = 0;
2137 }
2138 else
2139 status = 1;
2140 break;
2141 }
2142
2143 case BIO_CTRL_GET_CLOSE:
2144 status = BIO_get_shutdown(bio);
2145 break;
2146
2147 case BIO_CTRL_SET_CLOSE:
2148 BIO_set_shutdown(bio, (int)arg1);
2149 status = 1;
2150 break;
2151
2152 case BIO_CTRL_FLUSH:
2153 case BIO_CTRL_DUP:
2154 status = 1;
2155 break;
2156
2157 default:
2158 status = 0;
2159 break;
2160 }
2161
2162 return status;
2163}
2164
2165static int transport_layer_bio_new(BIO* bio)
2166{
2167 WINPR_ASSERT(bio);
2168
2169 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
2170 BIO_set_init(bio, 1);
2171 return 1;
2172}
2173
2174static int transport_layer_bio_free(BIO* bio)
2175{
2176 if (!bio)
2177 return 0;
2178
2179 rdpTransportLayer* layer = (rdpTransportLayer*)BIO_get_data(bio);
2180 if (layer)
2181 transport_layer_free(layer);
2182
2183 BIO_set_data(bio, nullptr);
2184 BIO_set_init(bio, 0);
2185 BIO_set_flags(bio, 0);
2186
2187 return 1;
2188}
2189
2190BIO_METHOD* BIO_s_transport_layer(void)
2191{
2192 static BIO_METHOD* bio_methods = nullptr;
2193
2194 if (bio_methods == nullptr)
2195 {
2196 if (!(bio_methods = BIO_meth_new(BIO_TYPE_SIMPLE, "TransportLayer")))
2197 return nullptr;
2198
2199 BIO_meth_set_write(bio_methods, transport_layer_bio_write);
2200 BIO_meth_set_read(bio_methods, transport_layer_bio_read);
2201 BIO_meth_set_puts(bio_methods, transport_layer_bio_puts);
2202 BIO_meth_set_gets(bio_methods, transport_layer_bio_gets);
2203 BIO_meth_set_ctrl(bio_methods, transport_layer_bio_ctrl);
2204 BIO_meth_set_create(bio_methods, transport_layer_bio_new);
2205 BIO_meth_set_destroy(bio_methods, transport_layer_bio_free);
2206 }
2207
2208 return bio_methods;
2209}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_server_name(const rdpSettings *settings)
A helper function to return the correct server name.