libfreerdp-core: add configurable TSG/RGB fallback, fix edge cases

This commit is contained in:
Marc-André Moreau 2015-03-19 11:44:47 -04:00
parent a2ff1e8348
commit 6202f48c12
10 changed files with 158 additions and 71 deletions

View File

@ -78,6 +78,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Gateway username" },
{ "gp", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Gateway password" },
{ "gd", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Gateway domain" },
{ "gt", COMMAND_LINE_VALUE_REQUIRED, "<rpc|http|auto>", NULL, NULL, -1, NULL, "Gateway transport type" },
{ "gateway-usage-method", COMMAND_LINE_VALUE_REQUIRED, "<direct|detect>", NULL, NULL, -1, "gum", "Gateway usage method" },
{ "load-balance-info", COMMAND_LINE_VALUE_REQUIRED, "<info string>", NULL, NULL, -1, NULL, "Load balance info" },
{ "app", COMMAND_LINE_VALUE_REQUIRED, "<executable path> or <||alias>", NULL, NULL, -1, NULL, "Remote application program" },
@ -1511,6 +1512,24 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->GatewayPassword = _strdup(arg->Value);
settings->GatewayUseSameCredentials = FALSE;
}
CommandLineSwitchCase(arg, "gt")
{
if (_stricmp(arg->Value, "rpc") == 0)
{
settings->GatewayRpcTransport = TRUE;
settings->GatewayHttpTransport = FALSE;
}
else if (_stricmp(arg->Value, "http") == 0)
{
settings->GatewayRpcTransport = FALSE;
settings->GatewayHttpTransport = TRUE;
}
else if (_stricmp(arg->Value, "auto") == 0)
{
settings->GatewayRpcTransport = TRUE;
settings->GatewayHttpTransport = TRUE;
}
}
CommandLineSwitchCase(arg, "gateway-usage-method")
{
int type;

View File

@ -692,6 +692,9 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_GatewayUseSameCredentials 1991
#define FreeRDP_GatewayEnabled 1992
#define FreeRDP_GatewayBypassLocal 1993
#define FreeRDP_GatewayRpcTransport 1994
#define FreeRDP_GatewayHttpTransport 1995
#define FreeRDP_GatewayUdpTransport 1996
#define FreeRDP_RemoteApplicationMode 2112
#define FreeRDP_RemoteApplicationName 2113
#define FreeRDP_RemoteApplicationIcon 2114
@ -1129,7 +1132,10 @@ struct rdp_settings
ALIGN64 BOOL GatewayUseSameCredentials; /* 1991 */
ALIGN64 BOOL GatewayEnabled; /* 1992 */
ALIGN64 BOOL GatewayBypassLocal; /* 1993 */
UINT64 padding2048[2048 - 1994]; /* 1994 */
ALIGN64 BOOL GatewayRpcTransport; /* 1994 */
ALIGN64 BOOL GatewayHttpTransport; /* 1995 */
ALIGN64 BOOL GatewayUdpTransport; /* 1996 */
UINT64 padding2048[2048 - 1997]; /* 1997 */
UINT64 padding2112[2112 - 2048]; /* 2048 */
/**

View File

@ -936,6 +936,15 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
case FreeRDP_GatewayBypassLocal:
return settings->GatewayBypassLocal;
case FreeRDP_GatewayRpcTransport:
return settings->GatewayRpcTransport;
case FreeRDP_GatewayHttpTransport:
return settings->GatewayHttpTransport;
case FreeRDP_GatewayUdpTransport:
return settings->GatewayUdpTransport;
case FreeRDP_RemoteApplicationMode:
return settings->RemoteApplicationMode;
@ -1396,6 +1405,18 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
settings->GatewayBypassLocal = param;
break;
case FreeRDP_GatewayRpcTransport:
settings->GatewayRpcTransport = param;
break;
case FreeRDP_GatewayHttpTransport:
settings->GatewayHttpTransport = param;
break;
case FreeRDP_GatewayUdpTransport:
settings->GatewayUdpTransport = param;
break;
case FreeRDP_RemoteApplicationMode:
settings->RemoteApplicationMode = param;
break;

View File

@ -635,7 +635,7 @@ HttpResponse* http_response_recv(rdpTls* tls)
int payloadOffset;
HttpResponse* response;
size = 1024;
size = 2048;
payload = NULL;
payloadOffset = 0;

View File

@ -341,12 +341,12 @@ BOOL rdg_process_out_channel_response(rdpRdg* rdg, HttpResponse* response)
if (response->StatusCode != HTTP_STATUS_DENIED)
{
WLog_INFO(TAG, "RDG not supported");
WLog_DBG(TAG, "RDG not supported");
rdg->state = RDG_CLIENT_STATE_NOT_FOUND;
return FALSE;
}
WLog_INFO(TAG, "Out Channel authorization required");
WLog_DBG(TAG, "Out Channel authorization required");
if (ListDictionary_Contains(response->Authenticates, "NTLM"))
{
@ -398,7 +398,7 @@ BOOL rdg_process_out_channel_authorization(rdpRdg* rdg, HttpResponse* response)
return FALSE;
}
WLog_INFO(TAG, "Out Channel authorization complete");
WLog_DBG(TAG, "Out Channel authorization complete");
rdg->state = RDG_CLIENT_STATE_OUT_CHANNEL_AUTHORIZED;
return TRUE;
@ -413,7 +413,7 @@ BOOL rdg_process_in_channel_response(rdpRdg* rdg, HttpResponse* response)
BYTE* ntlmTokenData = NULL;
rdpNtlm* ntlm = rdg->ntlm;
WLog_INFO(TAG, "In Channel authorization required");
WLog_DBG(TAG, "In Channel authorization required");
if (ListDictionary_Contains(response->Authenticates, "NTLM"))
{
@ -470,7 +470,7 @@ BOOL rdg_process_in_channel_authorization(rdpRdg* rdg, HttpResponse* response)
return FALSE;
}
WLog_INFO(TAG, "In Channel authorization complete");
WLog_DBG(TAG, "In Channel authorization complete");
rdg->state = RDG_CLIENT_STATE_IN_CHANNEL_AUTHORIZED;
s = rdg_build_http_request(rdg, "RDG_IN_DATA");
@ -492,7 +492,7 @@ BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
{
HRESULT errorCode;
WLog_INFO(TAG, "Handshake response recieved");
WLog_DBG(TAG, "Handshake response recieved");
if (rdg->state != RDG_CLIENT_STATE_HANDSHAKE)
{
@ -504,7 +504,7 @@ BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
if (FAILED(errorCode))
{
WLog_INFO(TAG, "Handshake error %x", errorCode);
WLog_DBG(TAG, "Handshake error %x", errorCode);
return FALSE;
}
@ -515,7 +515,7 @@ BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
{
HRESULT errorCode;
WLog_INFO(TAG, "Tunnel response received");
WLog_DBG(TAG, "Tunnel response received");
if (rdg->state != RDG_CLIENT_STATE_TUNNEL_CREATE)
{
@ -527,7 +527,7 @@ BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
if (FAILED(errorCode))
{
WLog_INFO(TAG, "Tunnel creation error %x", errorCode);
WLog_DBG(TAG, "Tunnel creation error %x", errorCode);
return FALSE;
}
@ -538,7 +538,7 @@ BOOL rdg_process_tunnel_authorization_response(rdpRdg* rdg, wStream* s)
{
HRESULT errorCode;
WLog_INFO(TAG, "Tunnel authorization received");
WLog_DBG(TAG, "Tunnel authorization received");
if (rdg->state != RDG_CLIENT_STATE_TUNNEL_AUTHORIZE)
{
@ -550,7 +550,7 @@ BOOL rdg_process_tunnel_authorization_response(rdpRdg* rdg, wStream* s)
if (FAILED(errorCode))
{
WLog_INFO(TAG, "Tunnel authorization error %x", errorCode);
WLog_DBG(TAG, "Tunnel authorization error %x", errorCode);
return FALSE;
}
@ -561,7 +561,7 @@ BOOL rdg_process_channel_response(rdpRdg* rdg, wStream* s)
{
HRESULT errorCode;
WLog_INFO(TAG, "Channel response received");
WLog_DBG(TAG, "Channel response received");
if (rdg->state != RDG_CLIENT_STATE_CHANNEL_CREATE)
{
@ -573,7 +573,7 @@ BOOL rdg_process_channel_response(rdpRdg* rdg, wStream* s)
if (FAILED(errorCode))
{
WLog_INFO(TAG, "Channel error %x", errorCode);
WLog_DBG(TAG, "Channel error %x", errorCode);
return FALSE;
}
@ -1130,7 +1130,7 @@ BOOL rdg_process_close_packet(rdpRdg* rdg)
header->type = PKT_TYPE_CLOSE_CHANNEL_RESPONSE;
header->packetLength = sizeof(buffer);
WLog_INFO(TAG, "Channel Close requested");
WLog_DBG(TAG, "Channel Close requested");
rdg->state = RDG_CLIENT_STATE_CLOSED;
return (rdg_write_data_packet(rdg, buffer, sizeof(buffer)) > 0 ? TRUE : FALSE);
}
@ -1284,17 +1284,17 @@ static int rdg_bio_write(BIO* bio, const char* buf, int num)
int status;
rdpRdg* rdg = (rdpRdg*)bio->ptr;
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
status = rdg_write_data_packet(rdg, (BYTE*) buf, num);
if (status < 0)
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
return -1;
}
else if (status < num)
{
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
BIO_set_flags(bio, BIO_FLAGS_WRITE);
WSASetLastError(WSAEWOULDBLOCK);
}
@ -1311,17 +1311,17 @@ static int rdg_bio_read(BIO* bio, char* buf, int size)
int status;
rdpRdg* rdg = (rdpRdg*)bio->ptr;
BIO_clear_flags(bio, BIO_FLAGS_READ);
status = rdg_read_data_packet(rdg, (BYTE*) buf, size);
if (status < 0)
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
BIO_clear_flags(bio, BIO_FLAGS_READ);
return -1;
}
else if (status < size)
{
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
BIO_set_flags(bio, BIO_FLAGS_READ);
WSASetLastError(WSAEWOULDBLOCK);
}
@ -1338,7 +1338,6 @@ static int rdg_bio_puts(BIO* bio, const char* str)
return 1;
}
static int rdg_bio_gets(BIO* bio, char* str, int size)
{
return 1;

View File

@ -448,16 +448,23 @@ int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment)
int rpc_client_default_out_channel_recv(rdpRpc* rpc)
{
int status = -1;
UINT32 statusCode;
HttpResponse* response;
RpcInChannel* inChannel;
RpcOutChannel* outChannel;
HANDLE outChannelEvent = NULL;
RpcVirtualConnection* connection = rpc->VirtualConnection;
inChannel = connection->DefaultInChannel;
outChannel = connection->DefaultOutChannel;
BIO_get_event(outChannel->tls->bio, &outChannelEvent);
if (outChannel->State < CLIENT_OUT_CHANNEL_STATE_OPENED)
{
if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
return 1;
response = http_response_recv(outChannel->tls);
if (!response)
@ -512,18 +519,23 @@ int rpc_client_default_out_channel_recv(rdpRpc* rpc)
{
/* Receive OUT channel response */
if (WaitForSingleObject(outChannelEvent, 0) != WAIT_OBJECT_0)
return 1;
response = http_response_recv(outChannel->tls);
if (!response)
return -1;
if (response->StatusCode != HTTP_STATUS_OK)
statusCode = response->StatusCode;
if (statusCode != HTTP_STATUS_OK)
{
WLog_ERR(TAG, "error! Status Code: %d", response->StatusCode);
WLog_ERR(TAG, "error! Status Code: %d", statusCode);
http_response_print(response);
http_response_free(response);
if (response->StatusCode == HTTP_STATUS_DENIED)
if (statusCode == HTTP_STATUS_DENIED)
{
if (!freerdp_get_last_error(rpc->context))
freerdp_set_last_error(rpc->context, FREERDP_ERROR_AUTHENTICATION_FAILED);
@ -634,22 +646,33 @@ int rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
int status = -1;
HttpResponse* response;
RpcOutChannel* nextOutChannel;
HANDLE nextOutChannelEvent = NULL;
nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
BIO_get_event(nextOutChannel->tls->bio, &nextOutChannelEvent);
if (WaitForSingleObject(nextOutChannelEvent, 0) != WAIT_OBJECT_0)
return 1;
response = http_response_recv(nextOutChannel->tls);
if (response)
{
if (nextOutChannel->State == CLIENT_OUT_CHANNEL_STATE_SECURITY)
{
status = rpc_ncacn_http_recv_out_channel_response(rpc, nextOutChannel, response);
if (status >= 0)
{
status = rpc_ncacn_http_send_out_channel_request(rpc, nextOutChannel, TRUE);
if (status >= 0)
{
rpc_ncacn_http_ntlm_uninit(rpc, (RpcChannel*)nextOutChannel);
rpc_ncacn_http_ntlm_uninit(rpc, (RpcChannel*) nextOutChannel);
status = rts_send_OUT_R1_A3_pdu(rpc);
if (status >= 0)
{
rpc_out_channel_transition_to_state(nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
@ -678,37 +701,31 @@ int rpc_client_nondefault_out_channel_recv(rdpRpc* rpc)
int rpc_client_out_channel_recv(rdpRpc* rpc)
{
RpcOutChannel* outChannel;
RpcOutChannel* nextOutChannel;
int status;
RpcVirtualConnection* connection = rpc->VirtualConnection;
HANDLE outChannelEvent = NULL;
HANDLE nextOutChannelEvent = NULL;
outChannel = connection->DefaultOutChannel;
BIO_get_event(outChannel->tls->bio, &outChannelEvent);
if (WaitForSingleObject(outChannelEvent, 0) == WAIT_OBJECT_0)
if (connection->DefaultOutChannel)
{
return rpc_client_default_out_channel_recv(rpc);
status = rpc_client_default_out_channel_recv(rpc);
if (status < 0)
return -1;
}
nextOutChannel = connection->NonDefaultOutChannel;
if (nextOutChannel)
if (connection->NonDefaultOutChannel)
{
BIO_get_event(nextOutChannel->tls->bio, &nextOutChannelEvent);
status = rpc_client_nondefault_out_channel_recv(rpc);
if (WaitForSingleObject(nextOutChannelEvent, 0) == WAIT_OBJECT_0)
{
return rpc_client_nondefault_out_channel_recv(rpc);
}
if (status < 0)
return -1;
}
return 0;
return 1;
}
int rpc_client_in_channel_recv(rdpRpc* rpc)
{
int status = -1;
int status = 1;
HttpResponse* response;
RpcInChannel* inChannel;
RpcOutChannel* outChannel;
@ -773,6 +790,17 @@ int rpc_client_in_channel_recv(rdpRpc* rpc)
http_response_free(response);
}
else
{
response = http_response_recv(inChannel->tls);
if (!response)
return -1;
/* We can receive an unauthorized HTTP response on the IN channel */
http_response_free(response);
}
return status;
}

View File

@ -678,7 +678,7 @@ int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, BYTE* buffer, UI
offset += rts_flow_control_ack_command_read(rpc, &buffer[offset], length - offset,
&BytesReceived, &AvailableWindow, (BYTE*) &ChannelCookie) + 4;
WLog_ERR(TAG, "Receiving FlowControlAckWithDestination RTS PDU: BytesReceived: %d AvailableWindow: %d",
WLog_DBG(TAG, "Receiving FlowControlAckWithDestination RTS PDU: BytesReceived: %d AvailableWindow: %d",
BytesReceived, AvailableWindow);
rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow =

View File

@ -1720,7 +1720,7 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, int timeout)
while (tsg->state != TSG_STATE_PIPE_CREATED)
{
WaitForMultipleObjects(nCount, events, FALSE, 100);
WaitForMultipleObjects(nCount, events, FALSE, 250);
if (tsg_check_event_handles(tsg) < 0)
{
@ -1913,10 +1913,11 @@ static int transport_bio_tsg_write(BIO* bio, const char* buf, int num)
if (status < 0)
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
return -1;
}
else if (status == 0)
{
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
BIO_set_flags(bio, BIO_FLAGS_WRITE);
WSASetLastError(WSAEWOULDBLOCK);
}
else
@ -1939,10 +1940,11 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
if (status < 0)
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
return -1;
}
else if (status == 0)
{
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
BIO_set_flags(bio, BIO_FLAGS_READ);
WSASetLastError(WSAEWOULDBLOCK);
}
else

View File

@ -397,6 +397,9 @@ rdpSettings* freerdp_settings_new(DWORD flags)
settings->GatewayUseSameCredentials = FALSE;
settings->GatewayBypassLocal = FALSE;
settings->GatewayRpcTransport = TRUE;
settings->GatewayHttpTransport = TRUE;
settings->GatewayUdpTransport = TRUE;
settings->FastPathInput = TRUE;
settings->FastPathOutput = TRUE;

View File

@ -207,40 +207,49 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
if (transport->GatewayEnabled)
{
/* New RDP 8 gateway test. */
transport->rdg = rdg_new(transport);
if (!transport->rdg)
if (!status && settings->GatewayHttpTransport)
{
return FALSE;
}
status = rdg_connect(transport->rdg, hostname, port, timeout);
if (status)
{
transport->frontBio = transport->rdg->frontBio;
BIO_set_nonblock(transport->frontBio, 0);
transport->layer = TRANSPORT_LAYER_TSG;
transport->rdg = rdg_new(transport);
status = TRUE;
}
else
{
if (transport->rdg->state != RDG_CLIENT_STATE_NOT_FOUND)
{
if (!transport->rdg)
return FALSE;
}
status = rdg_connect(transport->rdg, hostname, port, timeout);
if (status)
{
transport->frontBio = transport->rdg->frontBio;
BIO_set_nonblock(transport->frontBio, 0);
transport->layer = TRANSPORT_LAYER_TSG;
status = TRUE;
}
else
{
rdg_free(transport->rdg);
transport->rdg = NULL;
}
}
if (!status && settings->GatewayRpcTransport)
{
transport->tsg = tsg_new(transport);
if (!transport->tsg)
return FALSE;
if (!tsg_connect(transport->tsg, hostname, port, timeout))
return FALSE;
status = tsg_connect(transport->tsg, hostname, port, timeout);
transport->frontBio = transport->tsg->bio;
transport->layer = TRANSPORT_LAYER_TSG;
status = TRUE;
if (status)
{
transport->frontBio = transport->tsg->bio;
transport->layer = TRANSPORT_LAYER_TSG;
status = TRUE;
}
else
{
tsg_free(transport->tsg);
transport->tsg = NULL;
}
}
}
else