Merge pull request #4738 from akallabeth/connect_timeout_retry

Automatic timeout reconnect after callbacks
This commit is contained in:
Martin Fleisz
2018-07-10 17:31:08 +02:00
committed by GitHub
9 changed files with 384 additions and 232 deletions

View File

@@ -85,24 +85,24 @@ struct rdp_tls
};
#ifdef __cplusplus
extern "C" {
extern "C" {
#endif
FREERDP_API int tls_connect(rdpTls* tls, BIO *underlying);
FREERDP_API BOOL tls_accept(rdpTls* tls, BIO *underlying, rdpSettings *settings);
FREERDP_API int tls_connect(rdpTls* tls, BIO* underlying);
FREERDP_API BOOL tls_accept(rdpTls* tls, BIO* underlying, rdpSettings* settings);
FREERDP_API BOOL tls_send_alert(rdpTls* tls);
FREERDP_API int tls_write_all(rdpTls* tls, const BYTE* data, int length);
FREERDP_API int tls_set_alert_code(rdpTls* tls, int level, int description);
FREERDP_API BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname);
FREERDP_API BOOL tls_match_hostname(char* pattern, int pattern_length, char* hostname);
FREERDP_API int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port);
FREERDP_API void tls_print_certificate_error(char* hostname, UINT16 port,
char* fingerprint, char* hosts_file);
char* fingerprint, char* hosts_file);
FREERDP_API void tls_print_certificate_name_mismatch_error(
char* hostname, UINT16 port, char* common_name, char** alt_names,
int alt_names_count);
char* hostname, UINT16 port, char* common_name, char** alt_names,
int alt_names_count);
FREERDP_API BOOL tls_print_error(char* func, SSL* connection, int value);
@@ -110,7 +110,7 @@ FREERDP_API rdpTls* tls_new(rdpSettings* settings);
FREERDP_API void tls_free(rdpTls* tls);
#ifdef __cplusplus
}
}
#endif
#endif /* FREERDP_CRYPTO_TLS_H */

View File

@@ -868,7 +868,9 @@ struct rdp_settings
ALIGN64 char* PasswordHash; /* 24 */
ALIGN64 BOOL WaitForOutputBufferFlush; /* 25 */
ALIGN64 UINT32 MaxTimeInCheckLoop; /* 26 */
UINT64 padding0064[64 - 27]; /* 27 */
ALIGN64 char* AcceptedCert; /* 27 */
ALIGN64 UINT32 AcceptedCertLength; /* 28 */
UINT64 padding0064[64 - 29]; /* 29 */
UINT64 padding0128[128 - 64]; /* 64 */
/**
@@ -1073,7 +1075,9 @@ struct rdp_settings
ALIGN64 UINT32 TargetNetAddressCount; /* 1228 */
ALIGN64 char** TargetNetAddresses; /* 1229 */
ALIGN64 UINT32* TargetNetPorts; /* 1230 */
UINT64 padding1280[1280 - 1231]; /* 1231 */
ALIGN64 char* RedirectionAcceptedCert; /* 1231 */
ALIGN64 UINT32 RedirectionAcceptedCertLength;/* 1232 */
UINT64 padding1280[1280 - 1233]; /* 1233 */
/**
* Security
@@ -1185,7 +1189,9 @@ struct rdp_settings
ALIGN64 BOOL GatewayHttpTransport; /* 1995 */
ALIGN64 BOOL GatewayUdpTransport; /* 1996 */
ALIGN64 char* GatewayAccessToken; /* 1997 */
UINT64 padding2015[2015 - 1998]; /* 1998 */
ALIGN64 char* GatewayAcceptedCert; /* 1998 */
ALIGN64 UINT32 GatewayAcceptedCertLength; /* 1999 */
UINT64 padding2015[2015 - 2000]; /* 2000 */
/* Proxy */
ALIGN64 UINT32 ProxyType; /* 2015 */
@@ -1501,7 +1507,7 @@ FREERDP_API int freerdp_addin_set_argument(ADDIN_ARGV* args, char* argument);
FREERDP_API int freerdp_addin_replace_argument(ADDIN_ARGV* args, char* previous, char* argument);
FREERDP_API int freerdp_addin_set_argument_value(ADDIN_ARGV* args, char* option, char* value);
FREERDP_API int freerdp_addin_replace_argument_value(ADDIN_ARGV* args, char* previous, char* option,
char* value);
char* value);
FREERDP_API BOOL freerdp_device_collection_add(rdpSettings* settings, RDPDR_DEVICE* device);
FREERDP_API RDPDR_DEVICE* freerdp_device_collection_find(rdpSettings* settings, const char* name);
@@ -1511,13 +1517,13 @@ FREERDP_API void freerdp_device_collection_free(rdpSettings* settings);
FREERDP_API BOOL freerdp_static_channel_collection_add(rdpSettings* settings, ADDIN_ARGV* channel);
FREERDP_API ADDIN_ARGV* freerdp_static_channel_collection_find(rdpSettings* settings,
const char* name);
const char* name);
FREERDP_API ADDIN_ARGV* freerdp_static_channel_clone(ADDIN_ARGV* channel);
FREERDP_API void freerdp_static_channel_collection_free(rdpSettings* settings);
FREERDP_API BOOL freerdp_dynamic_channel_collection_add(rdpSettings* settings, ADDIN_ARGV* channel);
FREERDP_API ADDIN_ARGV* freerdp_dynamic_channel_collection_find(rdpSettings* settings,
const char* name);
const char* name);
FREERDP_API ADDIN_ARGV* freerdp_dynamic_channel_clone(ADDIN_ARGV* channel);
FREERDP_API void freerdp_dynamic_channel_collection_free(rdpSettings* settings);
@@ -1528,7 +1534,7 @@ FREERDP_API void freerdp_performance_flags_split(rdpSettings* settings);
FREERDP_API void freerdp_set_gateway_usage_method(rdpSettings* settings, UINT32 GatewayUsageMethod);
FREERDP_API void freerdp_update_gateway_usage_method(rdpSettings* settings, UINT32 GatewayEnabled,
UINT32 GatewayBypassLocal);
UINT32 GatewayBypassLocal);
FREERDP_API BOOL freerdp_get_param_bool(rdpSettings* settings, int id);
FREERDP_API int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param);

View File

@@ -167,6 +167,8 @@
* and server-side applications).
*/
static int rdp_client_connect_finalize(rdpRdp* rdp);
/**
* Establish RDP Connection based on the settings given in the 'rdp' parameter.
* @msdn{cc240452}
@@ -351,6 +353,35 @@ BOOL rdp_client_disconnect_and_clear(rdpRdp* rdp)
return TRUE;
}
static BOOL rdp_client_reconnect_channels(rdpRdp* rdp)
{
BOOL status;
rdpContext* context;
rdpChannels* channels;
if (!rdp || !rdp->context || !rdp->context->channels)
return FALSE;
context = rdp->context;
channels = context->channels;
if (context->instance->ConnectionCallbackState == CLIENT_STATE_INITIAL)
return FALSE;
if (context->instance->ConnectionCallbackState == CLIENT_STATE_PRECONNECT_PASSED)
{
if (!IFCALLRESULT(FALSE, context->instance->PostConnect, context->instance))
return FALSE;
context->instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
}
if (context->instance->ConnectionCallbackState == CLIENT_STATE_POSTCONNECT_PASSED)
status = (freerdp_channels_post_connect(context->channels, context->instance) == CHANNEL_RC_OK);
return status;
}
BOOL rdp_client_redirect(rdpRdp* rdp)
{
BOOL status;
@@ -424,8 +455,8 @@ BOOL rdp_client_redirect(rdpRdp* rdp)
status = rdp_client_connect(rdp);
if (status && (context->instance->ConnectionCallbackState == CLIENT_STATE_POSTCONNECT_PASSED))
status = (freerdp_channels_post_connect(context->channels, context->instance) == CHANNEL_RC_OK);
if (status)
status = rdp_client_reconnect_channels(rdp);
return status;
}
@@ -447,13 +478,13 @@ BOOL rdp_client_reconnect(rdpRdp* rdp)
status = rdp_client_connect(rdp);
if (status && (context->instance->ConnectionCallbackState == CLIENT_STATE_POSTCONNECT_PASSED))
status = (freerdp_channels_post_connect(channels, context->instance) == CHANNEL_RC_OK);
if (status)
status = rdp_client_reconnect_channels(rdp);
return status;
}
static BYTE fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
static const BYTE fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
static BOOL rdp_client_establish_keys(rdpRdp* rdp)
{

View File

@@ -53,8 +53,7 @@ enum CLIENT_CONNECTION_STATE
{
CLIENT_STATE_INITIAL,
CLIENT_STATE_PRECONNECT_PASSED,
CLIENT_STATE_POSTCONNECT_PASSED,
CLIENT_STATE_POSTDISCONNECT_PASSED
CLIENT_STATE_POSTCONNECT_PASSED
};
FREERDP_LOCAL BOOL rdp_client_connect(rdpRdp* rdp);
@@ -67,7 +66,6 @@ FREERDP_LOCAL BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp,
FREERDP_LOCAL BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s);
FREERDP_LOCAL int rdp_client_connect_license(rdpRdp* rdp, wStream* s);
FREERDP_LOCAL int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s);
FREERDP_LOCAL int rdp_client_connect_finalize(rdpRdp* rdp);
FREERDP_LOCAL int rdp_client_transition_to_state(rdpRdp* rdp, int state);
FREERDP_LOCAL BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s);

View File

@@ -197,82 +197,82 @@ BOOL freerdp_connect(freerdp* instance)
goto freerdp_connect_finally;
}
if (!status)
goto freerdp_connect_finally;
if (instance->settings->DumpRemoteFx)
{
instance->update->pcap_rfx = pcap_open(instance->settings->DumpRemoteFxFile,
TRUE);
if (instance->update->pcap_rfx)
instance->update->dump_rfx = TRUE;
}
if (status)
{
UINT status2;
if (instance->settings->DumpRemoteFx)
{
instance->update->pcap_rfx = pcap_open(instance->settings->DumpRemoteFxFile,
TRUE);
if (instance->update->pcap_rfx)
instance->update->dump_rfx = TRUE;
}
IFCALLRET(instance->PostConnect, status, instance);
instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
if (status)
status2 = freerdp_channels_post_connect(instance->context->channels, instance);
}
else
{
if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
status = freerdp_reconnect(instance);
}
if (!status || (status2 != CHANNEL_RC_OK)
|| !update_post_connect(instance->update))
{
WLog_ERR(TAG, "freerdp_post_connect failed");
if (!status || (status2 != CHANNEL_RC_OK)
|| !update_post_connect(instance->update))
{
WLog_ERR(TAG, "freerdp_post_connect failed");
if (!freerdp_get_last_error(rdp->context))
freerdp_set_last_error(instance->context, FREERDP_ERROR_POST_CONNECT_FAILED);
if (!freerdp_get_last_error(rdp->context))
freerdp_set_last_error(instance->context, FREERDP_ERROR_POST_CONNECT_FAILED);
status = FALSE;
status = FALSE;
goto freerdp_connect_finally;
}
if (instance->settings->PlayRemoteFx)
{
wStream* s;
rdpUpdate* update;
pcap_record record;
update = instance->update;
update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE);
status = FALSE;
if (!update->pcap_rfx)
goto freerdp_connect_finally;
else
update->play_rfx = TRUE;
status = TRUE;
while (pcap_has_next_record(update->pcap_rfx) && status)
{
pcap_get_next_record_header(update->pcap_rfx, &record);
if (!(s = StreamPool_Take(rdp->transport->ReceivePool, record.length)))
break;
record.data = Stream_Buffer(s);
pcap_get_next_record_content(update->pcap_rfx, &record);
Stream_SetLength(s, record.length);
Stream_SetPosition(s, 0);
if (!update->BeginPaint(update->context))
status = FALSE;
else if (update_recv_surfcmds(update, s) < 0)
status = FALSE;
else if (!update->EndPaint(update->context))
status = FALSE;
Stream_Release(s);
}
if (instance->settings->PlayRemoteFx)
{
wStream* s;
rdpUpdate* update;
pcap_record record;
update = instance->update;
update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE);
status = FALSE;
if (!update->pcap_rfx)
goto freerdp_connect_finally;
else
update->play_rfx = TRUE;
status = TRUE;
while (pcap_has_next_record(update->pcap_rfx) && status)
{
pcap_get_next_record_header(update->pcap_rfx, &record);
if (!(s = StreamPool_Take(rdp->transport->ReceivePool, record.length)))
break;
record.data = Stream_Buffer(s);
pcap_get_next_record_content(update->pcap_rfx, &record);
Stream_SetLength(s, record.length);
Stream_SetPosition(s, 0);
if (!update->BeginPaint(update->context))
status = FALSE;
else if (update_recv_surfcmds(update, s) < 0)
status = FALSE;
else if (!update->EndPaint(update->context))
status = FALSE;
Stream_Release(s);
}
pcap_close(update->pcap_rfx);
update->pcap_rfx = NULL;
goto freerdp_connect_finally;
}
pcap_close(update->pcap_rfx);
update->pcap_rfx = NULL;
goto freerdp_connect_finally;
}
if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
@@ -397,12 +397,22 @@ BOOL freerdp_check_event_handles(rdpContext* context)
status = checkChannelErrorEvent(context);
if (!status)
{
if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
WLog_ERR(TAG, "checkChannelErrorEvent() failed - %"PRIi32"", status);
return FALSE;
}
if (context->settings->AsyncInput)
{
status = freerdp_message_queue_process_pending_messages(
int rc = freerdp_message_queue_process_pending_messages(
context->instance, FREERDP_INPUT_MESSAGE_QUEUE);
if (rc < 0)
return FALSE;
else
status = TRUE;
}
return status;
@@ -504,7 +514,6 @@ BOOL freerdp_disconnect(freerdp* instance)
}
IFCALL(instance->PostDisconnect, instance);
instance->ConnectionCallbackState = CLIENT_STATE_POSTDISCONNECT_PASSED;
if (instance->update->pcap_rfx)
{

View File

@@ -63,6 +63,12 @@ static const char PROTOCOL_SECURITY_STRINGS[9][4] =
static BOOL nego_transport_connect(rdpNego* nego);
static BOOL nego_transport_disconnect(rdpNego* nego);
static BOOL nego_security_connect(rdpNego* nego);
static BOOL nego_send_preconnection_pdu(rdpNego* nego);
static BOOL nego_recv_response(rdpNego* nego);
static void nego_send(rdpNego* nego);
static void nego_process_negotiation_request(rdpNego* nego, wStream* s);
static void nego_process_negotiation_response(rdpNego* nego, wStream* s);
static void nego_process_negotiation_failure(rdpNego* nego, wStream* s);
/**
* Negotiate protocol security and connect.
@@ -103,7 +109,6 @@ BOOL nego_connect(rdpNego* nego)
{
WLog_DBG(TAG, "Security Layer Negotiation is disabled");
/* attempt only the highest enabled protocol (see nego_attempt_*) */
nego->EnabledProtocols[PROTOCOL_NLA] = FALSE;
nego->EnabledProtocols[PROTOCOL_TLS] = FALSE;
nego->EnabledProtocols[PROTOCOL_RDP] = FALSE;
@@ -152,13 +157,13 @@ BOOL nego_connect(rdpNego* nego)
do
{
WLog_DBG(TAG, "state: %s", NEGO_STATE_STRINGS[nego->state]);
nego_send(nego);
if (nego->state == NEGO_STATE_FAIL)
{
if (freerdp_get_last_error(nego->transport->context) == FREERDP_ERROR_SUCCESS)
WLog_ERR(TAG, "Protocol Security Negotiation Failure");
nego->state = NEGO_STATE_FINAL;
return FALSE;
}
@@ -167,7 +172,6 @@ BOOL nego_connect(rdpNego* nego)
}
WLog_DBG(TAG, "Negotiated %s security", PROTOCOL_SECURITY_STRINGS[nego->SelectedProtocol]);
/* update settings with negotiated protocol security */
settings->RequestedProtocols = nego->RequestedProtocols;
settings->SelectedProtocol = nego->SelectedProtocol;
@@ -183,14 +187,16 @@ BOOL nego_connect(rdpNego* nego)
* Advertise all supported encryption methods if the client
* implementation did not set any security methods
*/
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT | ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT |
ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
}
}
/* finally connect security layer (if not already done) */
if (!nego_security_connect(nego))
{
WLog_DBG(TAG, "Failed to connect with %s security", PROTOCOL_SECURITY_STRINGS[nego->SelectedProtocol]);
WLog_DBG(TAG, "Failed to connect with %s security",
PROTOCOL_SECURITY_STRINGS[nego->SelectedProtocol]);
return FALSE;
}
@@ -242,7 +248,7 @@ BOOL nego_security_connect(rdpNego* nego)
* @return
*/
BOOL nego_tcp_connect(rdpNego* nego)
static BOOL nego_tcp_connect(rdpNego* nego)
{
if (!nego->TcpConnected)
{
@@ -280,7 +286,8 @@ BOOL nego_tcp_connect(rdpNego* nego)
BOOL nego_transport_connect(rdpNego* nego)
{
nego_tcp_connect(nego);
if (!nego_tcp_connect(nego))
return FALSE;
if (nego->TcpConnected && !nego->NegotiateSecurityLayer)
return nego_security_connect(nego);
@@ -301,7 +308,6 @@ BOOL nego_transport_disconnect(rdpNego* nego)
nego->TcpConnected = FALSE;
nego->SecurityConnected = FALSE;
return TRUE;
}
@@ -317,7 +323,6 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego)
UINT32 cbSize;
UINT16 cchPCB = 0;
WCHAR* wszPCB = NULL;
WLog_DBG(TAG, "Sending preconnection PDU");
if (!nego_tcp_connect(nego))
@@ -334,6 +339,7 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego)
}
s = Stream_New(NULL, cbSize);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
@@ -361,7 +367,6 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego)
}
Stream_Free(s, TRUE);
return TRUE;
}
@@ -370,10 +375,9 @@ BOOL nego_send_preconnection_pdu(rdpNego* nego)
* @param nego
*/
void nego_attempt_ext(rdpNego* nego)
static void nego_attempt_ext(rdpNego* nego)
{
nego->RequestedProtocols = PROTOCOL_NLA | PROTOCOL_TLS | PROTOCOL_EXT;
WLog_DBG(TAG, "Attempting NLA extended security");
if (!nego_transport_connect(nego))
@@ -416,10 +420,9 @@ void nego_attempt_ext(rdpNego* nego)
* @param nego
*/
void nego_attempt_nla(rdpNego* nego)
static void nego_attempt_nla(rdpNego* nego)
{
nego->RequestedProtocols = PROTOCOL_NLA | PROTOCOL_TLS;
WLog_DBG(TAG, "Attempting NLA security");
if (!nego_transport_connect(nego))
@@ -460,10 +463,9 @@ void nego_attempt_nla(rdpNego* nego)
* @param nego
*/
void nego_attempt_tls(rdpNego* nego)
static void nego_attempt_tls(rdpNego* nego)
{
nego->RequestedProtocols = PROTOCOL_TLS;
WLog_DBG(TAG, "Attempting TLS security");
if (!nego_transport_connect(nego))
@@ -500,10 +502,9 @@ void nego_attempt_tls(rdpNego* nego)
* @param nego
*/
void nego_attempt_rdp(rdpNego* nego)
static void nego_attempt_rdp(rdpNego* nego)
{
nego->RequestedProtocols = PROTOCOL_RDP;
WLog_DBG(TAG, "Attempting RDP security");
if (!nego_transport_connect(nego))
@@ -534,7 +535,6 @@ BOOL nego_recv_response(rdpNego* nego)
{
int status;
wStream* s;
s = Stream_New(NULL, 1024);
if (!s)
@@ -552,7 +552,6 @@ BOOL nego_recv_response(rdpNego* nego)
}
status = nego_recv(nego->transport, s, nego);
Stream_Free(s, TRUE);
if (status < 0)
@@ -588,14 +587,12 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra)
if (li > 6)
{
/* rdpNegData (optional) */
Stream_Read_UINT8(s, type); /* Type */
switch (type)
{
case TYPE_RDP_NEG_RSP:
nego_process_negotiation_response(nego, s);
WLog_DBG(TAG, "selected_protocol: %"PRIu32"", nego->SelectedProtocol);
/* enhanced security selected ? */
@@ -603,12 +600,13 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra)
if (nego->SelectedProtocol)
{
if ((nego->SelectedProtocol == PROTOCOL_NLA) &&
(!nego->EnabledProtocols[PROTOCOL_NLA]))
(!nego->EnabledProtocols[PROTOCOL_NLA]))
{
nego->state = NEGO_STATE_FAIL;
}
if ((nego->SelectedProtocol == PROTOCOL_TLS) &&
(!nego->EnabledProtocols[PROTOCOL_TLS]))
(!nego->EnabledProtocols[PROTOCOL_TLS]))
{
nego->state = NEGO_STATE_FAIL;
}
@@ -617,6 +615,7 @@ int nego_recv(rdpTransport* transport, wStream* s, void* extra)
{
nego->state = NEGO_STATE_FAIL;
}
break;
case TYPE_RDP_NEG_FAILURE:
@@ -663,13 +662,11 @@ static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s)
* string terminated by a 0x0D0A two-byte sequence:
* Cookie:[space]mstshash=[ANSISTRING][\x0D\x0A]
*/
BYTE *str = NULL;
BYTE* str = NULL;
UINT16 crlf = 0;
size_t pos, len;
BOOL result = FALSE;
BOOL isToken = FALSE;
str = Stream_Pointer(s);
pos = Stream_GetPosition(s);
@@ -693,8 +690,10 @@ static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s)
while (Stream_GetRemainingLength(s) >= 2)
{
Stream_Read_UINT16(s, crlf);
if (crlf == 0x0A0D)
break;
Stream_Rewind(s, 1);
}
@@ -703,6 +702,7 @@ static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s)
Stream_Rewind(s, 2);
len = Stream_GetPosition(s) - pos;
Stream_Write_UINT16(s, 0);
if (strlen((char*)str) == len)
{
if (isToken)
@@ -716,12 +716,12 @@ static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s)
{
Stream_SetPosition(s, pos);
WLog_ERR(TAG, "invalid %s received",
isToken ? "routing token" : "cookie");
isToken ? "routing token" : "cookie");
}
else
{
WLog_DBG(TAG, "received %s [%s]",
isToken ? "routing token" : "cookie", str);
isToken ? "routing token" : "cookie", str);
}
return result;
@@ -760,7 +760,6 @@ BOOL nego_read_request(rdpNego* nego, wStream* s)
if (Stream_GetRemainingLength(s) >= 8)
{
/* rdpNegData (optional) */
Stream_Read_UINT8(s, type); /* Type */
if (type != TYPE_RDP_NEG_REQ)
@@ -808,8 +807,8 @@ BOOL nego_send_negotiation_request(rdpNego* nego)
size_t bm, em;
BYTE flags = 0;
int cookie_length;
s = Stream_New(NULL, 512);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
@@ -827,8 +826,8 @@ BOOL nego_send_negotiation_request(rdpNego* nego)
/* Ensure Routing Token is correctly terminated - may already be present in string */
if ((nego->RoutingTokenLength > 2) &&
(nego->RoutingToken[nego->RoutingTokenLength - 2] == 0x0D) &&
(nego->RoutingToken[nego->RoutingTokenLength - 1] == 0x0A))
(nego->RoutingToken[nego->RoutingTokenLength - 2] == 0x0D) &&
(nego->RoutingToken[nego->RoutingTokenLength - 1] == 0x0A))
{
WLog_DBG(TAG, "Routing token looks correctly terminated - use verbatim");
length += nego->RoutingTokenLength;
@@ -860,7 +859,6 @@ BOOL nego_send_negotiation_request(rdpNego* nego)
if ((nego->RequestedProtocols > PROTOCOL_RDP) || (nego->sendNegoData))
{
/* RDP_NEG_DATA must be present for TLS and NLA */
if (nego->RestrictedAdminModeRequired)
flags |= RESTRICTED_ADMIN_MODE_REQUIRED;
@@ -876,7 +874,6 @@ BOOL nego_send_negotiation_request(rdpNego* nego)
tpkt_write_header(s, length);
tpdu_write_connection_request(s, length - 5);
Stream_SetPosition(s, em);
Stream_SealLength(s);
if (transport_write(nego->transport, s) < 0)
@@ -886,7 +883,6 @@ BOOL nego_send_negotiation_request(rdpNego* nego)
}
Stream_Free(s, TRUE);
return TRUE;
}
@@ -900,13 +896,10 @@ void nego_process_negotiation_request(rdpNego* nego, wStream* s)
{
BYTE flags;
UINT16 length;
Stream_Read_UINT8(s, flags);
Stream_Read_UINT16(s, length);
Stream_Read_UINT32(s, nego->RequestedProtocols);
WLog_DBG(TAG, "RDP_NEG_REQ: RequestedProtocol: 0x%08"PRIX32"", nego->RequestedProtocols);
nego->state = NEGO_STATE_FINAL;
}
@@ -919,7 +912,6 @@ void nego_process_negotiation_request(rdpNego* nego, wStream* s)
void nego_process_negotiation_response(rdpNego* nego, wStream* s)
{
UINT16 length;
WLog_DBG(TAG, "RDP_NEG_RSP");
if (Stream_GetRemainingLength(s) < 7)
@@ -932,7 +924,6 @@ void nego_process_negotiation_response(rdpNego* nego, wStream* s)
Stream_Read_UINT8(s, nego->flags);
Stream_Read_UINT16(s, length);
Stream_Read_UINT32(s, nego->SelectedProtocol);
nego->state = NEGO_STATE_FINAL;
}
@@ -947,9 +938,7 @@ void nego_process_negotiation_failure(rdpNego* nego, wStream* s)
BYTE flags;
UINT16 length;
UINT32 failureCode;
WLog_DBG(TAG, "RDP_NEG_FAILURE");
Stream_Read_UINT8(s, flags);
Stream_Read_UINT16(s, length);
Stream_Read_UINT32(s, failureCode);
@@ -999,11 +988,10 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
wStream* s;
BYTE flags;
rdpSettings* settings;
status = TRUE;
settings = nego->transport->settings;
s = Stream_New(NULL, 512);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
@@ -1018,11 +1006,9 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
{
UINT32 errorCode = (nego->SelectedProtocol & ~PROTOCOL_FAILED_NEGO);
flags = 0;
Stream_Write_UINT8(s, TYPE_RDP_NEG_FAILURE);
Stream_Write_UINT8(s, flags); /* flags */
Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */
Stream_Write_UINT32(s, errorCode);
length += 8;
status = FALSE;
@@ -1047,7 +1033,6 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
tpkt_write_header(s, length);
tpdu_write_connection_confirm(s, length - 5);
Stream_SetPosition(s, em);
Stream_SealLength(s);
if (transport_write(nego->transport, s) < 0)
@@ -1148,9 +1133,7 @@ rdpNego* nego_new(rdpTransport* transport)
return NULL;
nego->transport = transport;
nego_init(nego);
return nego;
}
@@ -1276,8 +1259,10 @@ BOOL nego_set_routing_token(rdpNego* nego, BYTE* RoutingToken, DWORD RoutingToke
free(nego->RoutingToken);
nego->RoutingTokenLength = RoutingTokenLength;
nego->RoutingToken = (BYTE*) malloc(nego->RoutingTokenLength);
if (!nego->RoutingToken)
return FALSE;
CopyMemory(nego->RoutingToken, RoutingToken, nego->RoutingTokenLength);
return TRUE;
}
@@ -1300,8 +1285,10 @@ BOOL nego_set_cookie(rdpNego* nego, char* cookie)
return TRUE;
nego->cookie = _strdup(cookie);
if (!nego->cookie)
return FALSE;
return TRUE;
}

View File

@@ -120,22 +120,10 @@ typedef struct rdp_nego rdpNego;
FREERDP_LOCAL BOOL nego_connect(rdpNego* nego);
FREERDP_LOCAL BOOL nego_disconnect(rdpNego* nego);
FREERDP_LOCAL BOOL nego_send_preconnection_pdu(rdpNego* nego);
FREERDP_LOCAL void nego_attempt_ext(rdpNego* nego);
FREERDP_LOCAL void nego_attempt_nla(rdpNego* nego);
FREERDP_LOCAL void nego_attempt_tls(rdpNego* nego);
FREERDP_LOCAL void nego_attempt_rdp(rdpNego* nego);
FREERDP_LOCAL void nego_send(rdpNego* nego);
FREERDP_LOCAL int nego_recv(rdpTransport* transport, wStream* s, void* extra);
FREERDP_LOCAL BOOL nego_recv_response(rdpNego* nego);
FREERDP_LOCAL BOOL nego_read_request(rdpNego* nego, wStream* s);
FREERDP_LOCAL BOOL nego_send_negotiation_request(rdpNego* nego);
FREERDP_LOCAL void nego_process_negotiation_request(rdpNego* nego, wStream* s);
FREERDP_LOCAL void nego_process_negotiation_response(rdpNego* nego, wStream* s);
FREERDP_LOCAL void nego_process_negotiation_failure(rdpNego* nego, wStream* s);
FREERDP_LOCAL BOOL nego_send_negotiation_response(rdpNego* nego);
FREERDP_LOCAL rdpNego* nego_new(rdpTransport* transport);

View File

@@ -66,7 +66,7 @@ static const char client_dll[] = "C:\\Windows\\System32\\mstscax.dll";
#define GLYPH_CACHE_KEY CLIENT_KEY "\\GlyphCache"
#define POINTER_CACHE_KEY CLIENT_KEY "\\PointerCache"
void settings_client_load_hkey_local_machine(rdpSettings* settings)
static void settings_client_load_hkey_local_machine(rdpSettings* settings)
{
HKEY hKey;
LONG status;
@@ -218,7 +218,7 @@ void settings_client_load_hkey_local_machine(rdpSettings* settings)
}
}
void settings_server_load_hkey_local_machine(rdpSettings* settings)
static void settings_server_load_hkey_local_machine(rdpSettings* settings)
{
HKEY hKey;
LONG status;
@@ -242,7 +242,7 @@ void settings_server_load_hkey_local_machine(rdpSettings* settings)
RegCloseKey(hKey);
}
void settings_load_hkey_local_machine(rdpSettings* settings)
static void settings_load_hkey_local_machine(rdpSettings* settings)
{
if (settings->ServerMode)
settings_server_load_hkey_local_machine(settings);
@@ -250,7 +250,7 @@ void settings_load_hkey_local_machine(rdpSettings* settings)
settings_client_load_hkey_local_machine(settings);
}
BOOL settings_get_computer_name(rdpSettings* settings)
static BOOL settings_get_computer_name(rdpSettings* settings)
{
DWORD nSize = 0;
CHAR* computerName;
@@ -653,6 +653,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
CHECKED_STRDUP(Password); /* 22 */
CHECKED_STRDUP(Domain); /* 23 */
CHECKED_STRDUP(PasswordHash); /* 24 */
CHECKED_STRDUP(AcceptedCert); /* 27 */
_settings->ClientHostname = NULL; /* 134 */
_settings->ClientProductId = NULL; /* 135 */
CHECKED_STRDUP(AlternateShell); /* 640 */
@@ -668,6 +669,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
CHECKED_STRDUP(AllowedTlsCiphers); /* 1101 */
CHECKED_STRDUP(NtlmSamFile); /* 1103 */
CHECKED_STRDUP(PreconnectionBlob); /* 1155 */
CHECKED_STRDUP(RedirectionAcceptedCert); /* 1231 */
CHECKED_STRDUP(KerberosKdc); /* 1344 */
CHECKED_STRDUP(KerberosRealm); /* 1345 */
CHECKED_STRDUP(CertificateName); /* 1409 */
@@ -692,6 +694,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
CHECKED_STRDUP(GatewayPassword); /* 1988 */
CHECKED_STRDUP(GatewayDomain); /* 1989 */
CHECKED_STRDUP(GatewayAccessToken); /* 1997 */
CHECKED_STRDUP(GatewayAcceptedCert); /* 1998 */
CHECKED_STRDUP(ProxyHostname); /* 2016 */
CHECKED_STRDUP(RemoteApplicationName); /* 2113 */
CHECKED_STRDUP(RemoteApplicationIcon); /* 2114 */
@@ -772,7 +775,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
if (_settings->ChannelDefArraySize > 0)
{
_settings->ChannelDefArray = (CHANNEL_DEF*) calloc(settings->ChannelDefArraySize,
sizeof(CHANNEL_DEF));
sizeof(CHANNEL_DEF));
if (!_settings->ChannelDefArray)
goto out_fail;
@@ -789,7 +792,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
if (_settings->MonitorDefArraySize > 0)
{
_settings->MonitorDefArray = (rdpMonitor*) calloc(settings->MonitorDefArraySize,
sizeof(rdpMonitor));
sizeof(rdpMonitor));
if (!_settings->MonitorDefArray)
goto out_fail;
@@ -1032,6 +1035,7 @@ void freerdp_settings_free(rdpSettings* settings)
free(settings->Password);
free(settings->Domain);
free(settings->PasswordHash);
free(settings->AcceptedCert);
free(settings->AlternateShell);
free(settings->ShellWorkingDirectory);
free(settings->ComputerName);
@@ -1076,6 +1080,7 @@ void freerdp_settings_free(rdpSettings* settings)
free(settings->RedirectionDomain);
free(settings->RedirectionPassword);
free(settings->RedirectionTsvUrl);
free(settings->RedirectionAcceptedCert);
free(settings->RemoteAssistanceSessionId);
free(settings->RemoteAssistancePassword);
free(settings->RemoteAssistancePassStub);
@@ -1086,6 +1091,7 @@ void freerdp_settings_free(rdpSettings* settings)
free(settings->GatewayPassword);
free(settings->GatewayDomain);
free(settings->GatewayAccessToken);
free(settings->GatewayAcceptedCert);
free(settings->CertificateName);
free(settings->DynamicDSTTimeZoneKeyName);
free(settings->PreconnectionBlob);

View File

@@ -1109,6 +1109,175 @@ BOOL tls_match_hostname(char* pattern, int pattern_length, char* hostname)
return FALSE;
}
static BOOL is_accepted(rdpTls* tls, const BYTE* pem, size_t length)
{
rdpSettings* settings = tls->settings;
char* AccpetedKey;
UINT32 AcceptedKeyLength;
if (tls->isGatewayTransport)
{
AccpetedKey = settings->GatewayAcceptedCert;
AcceptedKeyLength = settings->GatewayAcceptedCertLength;
}
else if (settings->RedirectionFlags != 0)
{
AccpetedKey = settings->RedirectionAcceptedCert;
AcceptedKeyLength = settings->RedirectionAcceptedCertLength;
}
else
{
AccpetedKey = settings->AcceptedCert;
AcceptedKeyLength = settings->AcceptedCertLength;
}
if (AcceptedKeyLength > 0)
{
if (AcceptedKeyLength == length)
{
if (memcmp(AccpetedKey, pem, AcceptedKeyLength) == 0)
return TRUE;
}
}
if (tls->isGatewayTransport)
{
free(settings->GatewayAcceptedCert);
settings->GatewayAcceptedCert = NULL;
settings->GatewayAcceptedCertLength = 0;
}
else if (settings->RedirectionFlags != 0)
{
free(settings->RedirectionAcceptedCert);
settings->RedirectionAcceptedCert = NULL;
settings->RedirectionAcceptedCertLength = 0;
}
else
{
free(settings->AcceptedCert);
settings->AcceptedCert = NULL;
settings->AcceptedCertLength = 0;
}
return FALSE;
}
static BOOL accept_cert(rdpTls* tls, const BYTE* pem, size_t length)
{
rdpSettings* settings = tls->settings;
if (tls->isGatewayTransport)
{
settings->GatewayAcceptedCert = pem;
settings->GatewayAcceptedCertLength = length;
}
else if (settings->RedirectionFlags != 0)
{
settings->RedirectionAcceptedCert = pem;
settings->RedirectionAcceptedCertLength = length;
}
else
{
settings->AcceptedCert = pem;
settings->AcceptedCertLength = length;
}
return TRUE;
}
static BOOL tls_extract_pem(CryptoCert cert, BYTE** PublicKey, DWORD* PublicKeyLength)
{
BIO* bio;
int status;
size_t offset;
int length = 0;
BOOL rc = FALSE;
BYTE* pemCert = NULL;
if (!PublicKey || !PublicKeyLength)
return FALSE;
*PublicKey = NULL;
*PublicKeyLength = 0;
/**
* Don't manage certificates internally, leave it up entirely to the external client implementation
*/
bio = BIO_new(BIO_s_mem());
if (!bio)
{
WLog_ERR(TAG, "BIO_new() failure");
return FALSE;
}
status = PEM_write_bio_X509(bio, cert->px509);
if (status < 0)
{
WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
goto fail;
}
offset = 0;
length = 2048;
pemCert = (BYTE*) malloc(length + 1);
if (!pemCert)
{
WLog_ERR(TAG, "error allocating pemCert");
goto fail;
}
status = BIO_read(bio, pemCert, length);
if (status < 0)
{
WLog_ERR(TAG, "failed to read certificate");
goto fail;
}
offset += status;
while (offset >= length)
{
int new_len;
BYTE* new_cert;
new_len = length * 2;
new_cert = (BYTE*) realloc(pemCert, new_len + 1);
if (!new_cert)
goto fail;
length = new_len;
pemCert = new_cert;
status = BIO_read(bio, &pemCert[offset], length);
if (status < 0)
break;
offset += status;
}
if (status < 0)
{
WLog_ERR(TAG, "failed to read certificate");
goto fail;
}
length = offset;
pemCert[length] = '\0';
*PublicKey = pemCert;
*PublicKeyLength = length;
rc = TRUE;
fail:
if (!rc)
free(pemCert);
BIO_free(bio);
return rc;
}
int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
int port)
{
@@ -1123,83 +1292,23 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
BOOL hostname_match = FALSE;
BOOL verification_status = FALSE;
rdpCertificateData* certificate_data;
freerdp* instance = (freerdp*) tls->settings->instance;
DWORD length;
BYTE* pemCert;
if (!tls_extract_pem(cert, &pemCert, &length))
return -1;
/* Check, if we already accepted this key. */
if (is_accepted(tls, pemCert, length))
{
free(pemCert);
return 1;
}
if (tls->settings->ExternalCertificateManagement)
{
BIO* bio;
int status;
int length;
int offset;
BYTE* pemCert;
freerdp* instance = (freerdp*) tls->settings->instance;
/**
* Don't manage certificates internally, leave it up entirely to the external client implementation
*/
bio = BIO_new(BIO_s_mem());
if (!bio)
{
WLog_ERR(TAG, "BIO_new() failure");
return -1;
}
status = PEM_write_bio_X509(bio, cert->px509);
if (status < 0)
{
WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status);
return -1;
}
offset = 0;
length = 2048;
pemCert = (BYTE*) malloc(length + 1);
if (!pemCert)
{
WLog_ERR(TAG, "error allocating pemCert");
return -1;
}
status = BIO_read(bio, pemCert, length);
if (status < 0)
{
WLog_ERR(TAG, "failed to read certificate");
return -1;
}
offset += status;
while (offset >= length)
{
int new_len;
BYTE* new_cert;
new_len = length * 2;
new_cert = (BYTE*) realloc(pemCert, new_len + 1);
if (!new_cert)
return -1;
length = new_len;
pemCert = new_cert;
status = BIO_read(bio, &pemCert[offset], length);
if (status < 0)
break;
offset += status;
}
if (status < 0)
{
WLog_ERR(TAG, "failed to read certificate");
return -1;
}
length = offset;
pemCert[length] = '\0';
status = -1;
int status = -1;
if (instance->VerifyX509Certificate)
status = instance->VerifyX509Certificate(instance, pemCert, length, hostname,
@@ -1207,8 +1316,12 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
else
WLog_ERR(TAG, "No VerifyX509Certificate callback registered!");
free(pemCert);
BIO_free(bio);
if (status > 0)
{
accept_cert(tls, pemCert, length);
}
else
free(pemCert);
if (status < 0)
{
@@ -1222,10 +1335,16 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
/* ignore certificate verification if user explicitly required it (discouraged) */
if (tls->settings->IgnoreCertificate)
{
free(pemCert);
return 1; /* success! */
}
if (!tls->isGatewayTransport && tls->settings->AuthenticationLevel == 0)
{
free(pemCert);
return 1; /* success! */
}
/* if user explicitly specified a certificate name, use it instead of the hostname */
if (!tls->isGatewayTransport && tls->settings->CertificateName)
@@ -1273,7 +1392,6 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
char* issuer;
char* subject;
char* fingerprint;
freerdp* instance = (freerdp*) tls->settings->instance;
DWORD accept_certificate = 0;
issuer = crypto_cert_issuer(cert->px509);
subject = crypto_cert_subject(cert->px509);
@@ -1384,6 +1502,15 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname,
crypto_cert_subject_alt_name_free(alt_names_count, alt_names_lengths,
alt_names);
if (verification_status > 0)
{
accept_cert(tls, pemCert, length);
}
else
{
free(pemCert);
}
return (verification_status == 0) ? 0 : 1;
}