libfreerdp-core: replace all OpenSSL built-in BIOs by new full duplex BIOs

This commit is contained in:
Marc-André Moreau 2014-06-01 21:37:20 -04:00
parent 1172596d59
commit 04968b18c4
7 changed files with 731 additions and 73 deletions

View File

@ -148,7 +148,7 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-registry winpr-utils winpr-interlocked winpr-dsparse winpr-sspi winpr-rpc winpr-wtsapi winpr-handle winpr-crt)
MODULES winpr-registry winpr-utils winpr-interlocked winpr-dsparse winpr-sspi winpr-rpc winpr-wtsapi winpr-handle winpr-winsock winpr-crt)
if(MONOLITHIC_BUILD)
set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)

View File

@ -319,8 +319,7 @@ int rpc_out_read(rdpRpc* rpc, BYTE* data, int length)
int status;
status = BIO_read(rpc->TlsOut->bio, data, length);
/* fprintf(stderr, "%s: length=%d => status=%d shouldRetry=%d\n", __FUNCTION__, length,
* status, BIO_should_retry(rpc->TlsOut->bio)); */
if (status > 0) {
#ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_MAKE_MEM_DEFINED(data, status);

View File

@ -30,6 +30,7 @@
#include <fcntl.h>
#include <winpr/crt.h>
#include <winpr/winsock.h>
#ifndef _WIN32
#include <netdb.h>
@ -55,9 +56,6 @@
#endif
#endif
#else
#define SHUT_RDWR SD_BOTH
#define close(_fd) closesocket(_fd)
#endif
#include <freerdp/utils/tcp.h>
@ -66,6 +64,185 @@
#include "tcp.h"
/* Simple Socket BIO */
static int transport_bio_simple_new(BIO* bio);
static int transport_bio_simple_free(BIO* bio);
long transport_bio_simple_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret)
{
return 1;
}
static int transport_bio_simple_write(BIO* bio, const char* buf, int size)
{
int error;
int status = 0;
if (!buf)
return 0;
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
status = _send((SOCKET) bio->num, buf, size, 0);
if (status <= 0)
{
error = WSAGetLastError();
if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) ||
(error == WSAEINPROGRESS) || (error == WSAEALREADY))
{
BIO_set_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY));
}
else
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
}
}
return status;
}
static int transport_bio_simple_read(BIO* bio, char* buf, int size)
{
int error;
int status = 0;
if (!buf)
return 0;
BIO_clear_flags(bio, BIO_FLAGS_READ);
status = _recv((SOCKET) bio->num, buf, size, 0);
if (status <= 0)
{
error = WSAGetLastError();
if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) ||
(error == WSAEINPROGRESS) || (error == WSAEALREADY))
{
BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
}
else
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
}
}
return status;
}
static int transport_bio_simple_puts(BIO* bio, const char* str)
{
return 1;
}
static int transport_bio_simple_gets(BIO* bio, char* str, int size)
{
return 1;
}
static long transport_bio_simple_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
int status = -1;
switch (cmd)
{
case BIO_C_SET_FD:
if (arg2)
{
transport_bio_simple_free(bio);
bio->flags = BIO_FLAGS_SHOULD_RETRY;
bio->num = *((int*) arg2);
bio->shutdown = (int) arg1;
bio->init = 1;
status = 1;
}
break;
case BIO_C_GET_FD:
if (bio->init)
{
if (arg2)
*((int*) arg2) = bio->num;
status = bio->num;
}
break;
case BIO_CTRL_GET_CLOSE:
status = bio->shutdown;
break;
case BIO_CTRL_SET_CLOSE:
bio->shutdown = (int) arg1;
status = 1;
break;
case BIO_CTRL_DUP:
status = 1;
break;
case BIO_CTRL_FLUSH:
status = 1;
break;
default:
status = 0;
break;
}
return status;
}
static int transport_bio_simple_new(BIO* bio)
{
bio->init = 0;
bio->num = 0;
bio->ptr = NULL;
bio->flags = BIO_FLAGS_SHOULD_RETRY;
return 1;
}
static int transport_bio_simple_free(BIO* bio)
{
if (!bio)
return 0;
if (bio->shutdown)
{
if (bio->init)
closesocket((SOCKET) bio->num);
bio->init = 0;
bio->flags = 0;
}
return 1;
}
static BIO_METHOD transport_bio_simple_socket_methods =
{
BIO_TYPE_SIMPLE,
"SimpleSocket",
transport_bio_simple_write,
transport_bio_simple_read,
transport_bio_simple_puts,
transport_bio_simple_gets,
transport_bio_simple_ctrl,
transport_bio_simple_new,
transport_bio_simple_free,
NULL,
};
BIO_METHOD* BIO_s_simple_socket(void)
{
return &transport_bio_simple_socket_methods;
}
/* Buffered Socket BIO */
long transport_bio_buffered_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret)
{
return 1;
@ -80,7 +257,7 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
ret = num;
tcp->writeBlocked = FALSE;
BIO_clear_retry_flags(bio);
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
/* we directly append extra bytes in the xmit buffer, this could be prevented
* but for now it makes the code more simple.
@ -99,21 +276,22 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
while (chunks[i].size)
{
status = BIO_write(bio->next_bio, chunks[i].data, chunks[i].size);
/*fprintf(stderr, "%s: i=%d/%d size=%d/%d status=%d retry=%d\n", __FUNCTION__, i, nchunks,
chunks[i].size, ringbuffer_used(&tcp->xmitBuffer), status,
BIO_should_retry(bio->next_bio)
);*/
if (status <= 0)
{
if (BIO_should_retry(bio->next_bio))
if (!BIO_should_retry(bio->next_bio))
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
ret = -1; /* fatal error */
goto out;
}
if (BIO_should_write(bio->next_bio))
{
BIO_set_flags(bio, BIO_FLAGS_WRITE);
tcp->writeBlocked = TRUE;
goto out; /* EWOULDBLOCK */
}
/* any other is an error, but we still have to commit written bytes */
ret = -1;
goto out;
}
committedBytes += status;
@ -133,17 +311,30 @@ static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
rdpTcp* tcp = (rdpTcp*) bio->ptr;
tcp->readBlocked = FALSE;
BIO_clear_retry_flags(bio);
BIO_clear_flags(bio, BIO_FLAGS_READ);
status = BIO_read(bio->next_bio, buf, size);
/*fprintf(stderr, "%s: size=%d status=%d shouldRetry=%d\n", __FUNCTION__, size, status, BIO_should_retry(bio->next_bio)); */
if (status <= 0 && BIO_should_retry(bio->next_bio))
if (status <= 0)
{
BIO_set_retry_read(bio);
tcp->readBlocked = TRUE;
if (!BIO_should_retry(bio->next_bio))
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
status = -1;
goto out;
}
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
if (BIO_should_read(bio->next_bio))
{
BIO_set_flags(bio, BIO_FLAGS_READ);
tcp->readBlocked = TRUE;
goto out;
}
}
out:
return status;
}
@ -159,18 +350,20 @@ static int transport_bio_buffered_gets(BIO* bio, char* str, int size)
static long transport_bio_buffered_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
rdpTcp *tcp = (rdpTcp *)bio->ptr;
rdpTcp* tcp = (rdpTcp*) bio->ptr;
switch (cmd)
{
case BIO_CTRL_FLUSH:
return 1;
case BIO_CTRL_WPENDING:
return ringbuffer_used(&tcp->xmitBuffer);
case BIO_CTRL_PENDING:
return 0;
default:
/*fprintf(stderr, "%s: passing to next BIO, bio=%p cmd=%d arg1=%d arg2=%p\n", __FUNCTION__, bio, cmd, arg1, arg2); */
return BIO_ctrl(bio->next_bio, cmd, arg1, arg2);
}
@ -182,8 +375,7 @@ static int transport_bio_buffered_new(BIO* bio)
bio->init = 1;
bio->num = 0;
bio->ptr = NULL;
bio->flags = 0;
bio->flags = BIO_FLAGS_SHOULD_RETRY;
return 1;
}
@ -192,7 +384,6 @@ static int transport_bio_buffered_free(BIO* bio)
return 1;
}
static BIO_METHOD transport_bio_buffered_socket_methods =
{
BIO_TYPE_BUFFERED,
@ -214,18 +405,17 @@ BIO_METHOD* BIO_s_buffered_socket(void)
BOOL transport_bio_buffered_drain(BIO *bio)
{
rdpTcp *tcp = (rdpTcp *)bio->ptr;
int status;
rdpTcp* tcp = (rdpTcp*) bio->ptr;
if (!ringbuffer_used(&tcp->xmitBuffer))
return 1;
status = transport_bio_buffered_write(bio, NULL, 0);
return status >= 0;
}
void tcp_get_ip_address(rdpTcp* tcp)
{
BYTE* ip;
@ -346,6 +536,16 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout)
return FALSE; /* timeout */
}
}
BIO_set_close(tcp->socketBio, BIO_NOCLOSE);
BIO_free(tcp->socketBio);
tcp->socketBio = BIO_new(BIO_s_simple_socket());
if (!tcp->socketBio)
return -1;
BIO_set_fd(tcp->socketBio, tcp->sockfd, BIO_CLOSE);
}
SetEventFileDescriptor(tcp->event, tcp->sockfd);
@ -504,9 +704,12 @@ int tcp_attach(rdpTcp* tcp, int sockfd)
}
else
{
tcp->socketBio = BIO_new_socket(sockfd, 1);
tcp->socketBio = BIO_new(BIO_s_simple_socket());
if (!tcp->socketBio)
return -1;
BIO_set_fd(tcp->socketBio, sockfd, BIO_CLOSE);
}
if (!tcp->bufferedBio)

View File

@ -38,7 +38,8 @@
#define MSG_NOSIGNAL 0
#endif
#define BIO_TYPE_BUFFERED 66
#define BIO_TYPE_SIMPLE 66
#define BIO_TYPE_BUFFERED 67
typedef struct rdp_tcp rdpTcp;

View File

@ -133,17 +133,20 @@ static int transport_bio_tsg_write(BIO* bio, const char* buf, int num)
tsg = (rdpTsg*) bio->ptr;
BIO_clear_retry_flags(bio);
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
status = tsg_write(tsg, (BYTE*) buf, num);
if (status == 0)
BIO_set_retry_write(bio);
if (status < 0)
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
}
else
{
BIO_set_flags(bio, BIO_FLAGS_WRITE);
}
if (status > 0)
return status;
return -1;
return status >= 0 ? status : -1;
}
static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
@ -153,18 +156,17 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
tsg = (rdpTsg*) bio->ptr;
BIO_clear_flags(bio, BIO_FLAGS_READ);
status = tsg_read(bio->ptr, (BYTE*) buf, size);
BIO_clear_retry_flags(bio);
if (status == 0)
if (status < 0)
{
BIO_set_retry_read(bio);
status = -1;
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
}
else if (status == -1)
else
{
status = 0;
BIO_set_flags(bio, BIO_FLAGS_READ);
}
return status >= 0 ? status : -1;
@ -195,8 +197,7 @@ static int transport_bio_tsg_new(BIO* bio)
bio->init = 1;
bio->num = 0;
bio->ptr = NULL;
bio->flags = 0;
bio->flags = BIO_FLAGS_SHOULD_RETRY;
return 1;
}
@ -226,8 +227,6 @@ BIO_METHOD* BIO_s_tsg(void)
return &transport_bio_tsg_methods;
}
BOOL transport_connect_tls(rdpTransport* transport)
{
rdpSettings *settings = transport->settings;
@ -708,7 +707,6 @@ static int transport_wait_for_write(rdpTransport* transport)
return select(tcpOut->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
}
int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
{
int read = 0;
@ -724,13 +722,7 @@ int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
{
status = BIO_read(transport->frontBio, data + read, bytes - read);
if (!status)
{
transport->layer = TRANSPORT_LAYER_CLOSED;
return -1;
}
if (status < 0)
if (status <= 0)
{
if (!transport->frontBio || !BIO_should_retry(transport->frontBio))
{
@ -763,8 +755,6 @@ int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
return read;
}
int transport_read(rdpTransport* transport, wStream* s)
{
int status;

View File

@ -33,6 +33,445 @@
#include <freerdp/crypto/tls.h>
#include "../core/tcp.h"
struct _BIO_RDP_TLS
{
SSL* ssl;
};
typedef struct _BIO_RDP_TLS BIO_RDP_TLS;
long bio_rdp_tls_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret)
{
return 1;
}
static int bio_rdp_tls_write(BIO* bio, const char* buf, int size)
{
int status;
BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr;
if (!buf || !tls)
return 0;
BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL);
status = SSL_write(tls->ssl, buf, size);
if (status <= 0)
{
switch (SSL_get_error(tls->ssl, status))
{
case SSL_ERROR_NONE:
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
break;
case SSL_ERROR_WANT_WRITE:
BIO_set_flags(bio, BIO_FLAGS_WRITE);
break;
case SSL_ERROR_WANT_READ:
BIO_set_flags(bio, BIO_FLAGS_READ);
break;
case SSL_ERROR_WANT_X509_LOOKUP:
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
bio->retry_reason = BIO_RR_SSL_X509_LOOKUP;
break;
case SSL_ERROR_WANT_CONNECT:
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
bio->retry_reason = BIO_RR_CONNECT;
break;
case SSL_ERROR_SYSCALL:
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
break;
case SSL_ERROR_SSL:
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
break;
}
}
return status;
}
static int bio_rdp_tls_read(BIO* bio, char* buf, int size)
{
int status;
BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr;
if (!buf || !tls)
return 0;
BIO_clear_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_READ | BIO_FLAGS_IO_SPECIAL);
status = SSL_read(tls->ssl, buf, size);
if (status <= 0)
{
switch (SSL_get_error(tls->ssl, status))
{
case SSL_ERROR_NONE:
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
break;
case SSL_ERROR_WANT_READ:
BIO_set_flags(bio, BIO_FLAGS_READ);
break;
case SSL_ERROR_WANT_WRITE:
BIO_set_flags(bio, BIO_FLAGS_WRITE);
break;
case SSL_ERROR_WANT_X509_LOOKUP:
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
bio->retry_reason = BIO_RR_SSL_X509_LOOKUP;
break;
case SSL_ERROR_WANT_ACCEPT:
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
bio->retry_reason = BIO_RR_ACCEPT;
break;
case SSL_ERROR_WANT_CONNECT:
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL);
bio->retry_reason = BIO_RR_CONNECT;
break;
case SSL_ERROR_SSL:
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
break;
case SSL_ERROR_ZERO_RETURN:
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
break;
case SSL_ERROR_SYSCALL:
status = 0;
break;
}
}
return status;
}
static int bio_rdp_tls_puts(BIO* bio, const char* str)
{
int size;
int status;
if (!str)
return 0;
size = strlen(str);
status = BIO_write(bio, str, size);
return status;
}
static int bio_rdp_tls_gets(BIO* bio, char* str, int size)
{
return 1;
}
static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr)
{
BIO* rbio;
int status = -1;
BIO_RDP_TLS* tls = (BIO_RDP_TLS*) bio->ptr;
if (!tls)
return 0;
if (!tls->ssl && (cmd != BIO_C_SET_SSL))
return 0;
switch (cmd)
{
case BIO_CTRL_RESET:
SSL_shutdown(tls->ssl);
if (tls->ssl->handshake_func == tls->ssl->method->ssl_connect)
SSL_set_connect_state(tls->ssl);
else if (tls->ssl->handshake_func == tls->ssl->method->ssl_accept)
SSL_set_accept_state(tls->ssl);
SSL_clear(tls->ssl);
if (bio->next_bio)
status = BIO_ctrl(bio->next_bio, cmd, num, ptr);
else if (tls->ssl->rbio)
status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
else
status = 1;
break;
case BIO_C_GET_FD:
status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
break;
case BIO_CTRL_INFO:
status = 0;
break;
case BIO_CTRL_SET_CALLBACK:
status = 0;
break;
case BIO_CTRL_GET_CALLBACK:
*((ULONG_PTR*) ptr) = (ULONG_PTR) SSL_get_info_callback(tls->ssl);
status = 1;
break;
case BIO_C_SSL_MODE:
if (num)
SSL_set_connect_state(tls->ssl);
else
SSL_set_accept_state(tls->ssl);
status = 1;
break;
case BIO_CTRL_GET_CLOSE:
status = bio->shutdown;
break;
case BIO_CTRL_SET_CLOSE:
bio->shutdown = (int) num;
status = 1;
break;
case BIO_CTRL_WPENDING:
status = BIO_ctrl(tls->ssl->wbio, cmd, num, ptr);
break;
case BIO_CTRL_PENDING:
status = SSL_pending(tls->ssl);
if (status == 0)
status = BIO_pending(tls->ssl->rbio);
break;
case BIO_CTRL_FLUSH:
BIO_clear_retry_flags(bio);
status = BIO_ctrl(tls->ssl->wbio, cmd, num, ptr);
BIO_copy_next_retry(bio);
status = 1;
break;
case BIO_CTRL_PUSH:
if (bio->next_bio && (bio->next_bio != tls->ssl->rbio))
{
SSL_set_bio(tls->ssl, bio->next_bio, bio->next_bio);
CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO);
}
status = 1;
break;
case BIO_CTRL_POP:
if (bio == ptr)
{
if (tls->ssl->rbio != tls->ssl->wbio)
BIO_free_all(tls->ssl->wbio);
if (bio->next_bio)
CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO);
tls->ssl->wbio = tls->ssl->rbio = NULL;
}
status = 1;
break;
case BIO_C_GET_SSL:
if (ptr)
{
*((SSL**) ptr) = tls->ssl;
status = 1;
}
break;
case BIO_C_SET_SSL:
bio->shutdown = (int) num;
if (ptr)
tls->ssl = (SSL*) ptr;
rbio = SSL_get_rbio(tls->ssl);
if (rbio)
{
if (bio->next_bio)
BIO_push(rbio, bio->next_bio);
bio->next_bio = rbio;
CRYPTO_add(&(rbio->references), 1, CRYPTO_LOCK_BIO);
}
bio->init = 1;
status = 1;
break;
case BIO_C_DO_STATE_MACHINE:
BIO_clear_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL);
bio->retry_reason = 0;
status = SSL_do_handshake(tls->ssl);
if (status <= 0)
{
switch (SSL_get_error(tls->ssl, status))
{
case SSL_ERROR_WANT_READ:
BIO_set_flags(bio, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY);
break;
case SSL_ERROR_WANT_WRITE:
BIO_set_flags(bio, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY);
break;
case SSL_ERROR_WANT_CONNECT:
BIO_set_flags(bio, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY);
bio->retry_reason = bio->next_bio->retry_reason;
break;
default:
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
break;
}
}
break;
default:
status = BIO_ctrl(tls->ssl->rbio, cmd, num, ptr);
break;
}
return status;
}
static int bio_rdp_tls_new(BIO* bio)
{
BIO_RDP_TLS* tls;
bio->init = 0;
bio->num = 0;
bio->flags = BIO_FLAGS_SHOULD_RETRY;
bio->next_bio = NULL;
tls = calloc(1, sizeof(BIO_RDP_TLS));
if (!tls)
return 0;
bio->ptr = (void*) tls;
return 1;
}
static int bio_rdp_tls_free(BIO* bio)
{
BIO_RDP_TLS* tls;
if (!bio)
return 0;
tls = (BIO_RDP_TLS*) bio->ptr;
if (!tls)
return 0;
if (bio->shutdown)
{
if (bio->init && tls->ssl)
{
SSL_shutdown(tls->ssl);
SSL_free(tls->ssl);
}
bio->init = 0;
bio->flags = 0;
}
free(tls);
return 1;
}
static long bio_rdp_tls_callback_ctrl(BIO* bio, int cmd, bio_info_cb* fp)
{
int status = 0;
BIO_RDP_TLS* tls;
if (!bio)
return 0;
tls = (BIO_RDP_TLS*) bio->ptr;
if (!tls)
return 0;
switch (cmd)
{
case BIO_CTRL_SET_CALLBACK:
SSL_set_info_callback(tls->ssl, (void (*)(const SSL *, int, int)) fp);
status = 1;
break;
default:
status = BIO_callback_ctrl(tls->ssl->rbio, cmd, fp);
break;
}
return status;
}
#define BIO_TYPE_RDP_TLS 68
static BIO_METHOD bio_rdp_tls_methods =
{
BIO_TYPE_RDP_TLS,
"RdpTls",
bio_rdp_tls_write,
bio_rdp_tls_read,
bio_rdp_tls_puts,
bio_rdp_tls_gets,
bio_rdp_tls_ctrl,
bio_rdp_tls_new,
bio_rdp_tls_free,
bio_rdp_tls_callback_ctrl,
};
BIO_METHOD* BIO_s_rdp_tls(void)
{
return &bio_rdp_tls_methods;
}
BIO* BIO_new_rdp_tls(SSL_CTX* ctx, int client)
{
BIO* bio;
SSL* ssl;
bio = BIO_new(BIO_s_rdp_tls());
if (!bio)
return NULL;
ssl = SSL_new(ctx);
if (!ssl)
{
BIO_free(bio);
return NULL;
}
if (client)
SSL_set_connect_state(ssl);
else
SSL_set_accept_state(ssl);
BIO_set_ssl(bio, ssl, BIO_CLOSE);
return bio;
}
static CryptoCert tls_get_certificate(rdpTls* tls, BOOL peer)
{
CryptoCert cert;
@ -127,7 +566,8 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt
SSL_CTX_set_options(tls->ctx, options);
SSL_CTX_set_read_ahead(tls->ctx, 1);
tls->bio = BIO_new_ssl(tls->ctx, clientMode);
tls->bio = BIO_new_rdp_tls(tls->ctx, clientMode);
if (BIO_get_ssl(tls->bio, &tls->ssl) < 0)
{
fprintf(stderr, "%s: unable to retrieve the SSL of the connection\n", __FUNCTION__);
@ -135,6 +575,7 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt
}
BIO_push(tls->bio, underlying);
return TRUE;
}
@ -150,8 +591,10 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
int fd;
status = BIO_do_handshake(tls->bio);
if (status == 1)
break;
if (!BIO_should_retry(tls->bio))
return -1;
@ -160,6 +603,7 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
FD_ZERO(&rset);
fd = BIO_get_fd(tls->bio, NULL);
if (fd < 0)
{
fprintf(stderr, "%s: unable to retrieve BIO fd\n", __FUNCTION__);
@ -171,6 +615,7 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
tv.tv_usec = 10 * 1000; /* 10ms */
status = select(fd + 1, &rset, NULL, NULL, &tv);
if (status < 0)
{
fprintf(stderr, "%s: error during select()\n", __FUNCTION__);
@ -383,7 +828,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
fd_set rset, wset;
fd_set *rsetPtr, *wsetPtr;
struct timeval tv;
BIO *bio = tls->bio;
BIO* bio = tls->bio;
DataChunk chunks[2];
BIO* bufferedBio = findBufferedBio(bio);
@ -399,7 +844,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
do
{
status = BIO_write(bio, data, length);
/*fprintf(stderr, "%s: BIO_write(len=%d) = %d (retry=%d)\n", __FUNCTION__, length, status, BIO_should_retry(bio));*/
if (status > 0)
break;
@ -408,6 +853,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
/* we try to handle SSL want_read and want_write nicely */
rsetPtr = wsetPtr = 0;
if (tcp->writeBlocked)
{
wsetPtr = &wset;
@ -431,6 +877,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
tv.tv_usec = 100 * 1000;
status = select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
if (status < 0)
return -1;
}
@ -447,6 +894,7 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
while (chunks[i].size)
{
status = BIO_write(tcp->socketBio, chunks[i].data, chunks[i].size);
if (status > 0)
{
chunks[i].size -= status;
@ -457,12 +905,14 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
if (!BIO_should_retry(tcp->socketBio))
goto out_fail;
FD_ZERO(&rset);
FD_SET(tcp->sockfd, &rset);
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
status = select(tcp->sockfd + 1, &rset, NULL, NULL, &tv);
if (status < 0)
goto out_fail;
}
@ -478,8 +928,6 @@ out_fail:
return -1;
}
int tls_set_alert_code(rdpTls* tls, int level, int description)
{
tls->alertLevel = level;

View File

@ -255,6 +255,10 @@ PCSTR inet_ntop(INT Family, PVOID pAddr, PSTR pStringBuf, size_t StringBufSize)
#include <netinet/tcp.h>
#include <net/if.h>
#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif
int WSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData)
{
ZeroMemory(lpWSAData, sizeof(WSADATA));
@ -423,6 +427,17 @@ int WSAGetLastError(void)
iError = WSAEREMOTE;
break;
/* Special cases */
#if (EAGAIN != EWOULDBLOCK)
case EAGAIN:
iError = WSAEWOULDBLOCK;
break;
#endif
case EPROTO:
iError = WSAECONNRESET;
break;
}
/**
@ -445,7 +460,7 @@ int WSAGetLastError(void)
* WSAEREFUSED
*/
return 0;
return iError;
}
SOCKET _accept(SOCKET s, struct sockaddr* addr, int* addrlen)
@ -607,6 +622,8 @@ int _send(SOCKET s, const char* buf, int len, int flags)
int status;
int fd = (int) s;
flags |= MSG_NOSIGNAL;
status = (int) send(fd, (void*) buf, (size_t) len, flags);
return status;