added a setting and a command line flag to disable security layer negotiation

This commit is contained in:
lysannkessler
2012-07-25 12:29:49 +02:00
parent 664c870de8
commit 3c6df95978
6 changed files with 100 additions and 68 deletions

View File

@@ -269,7 +269,8 @@ struct rdp_settings
ALIGN64 uint32 encryption_level; /* 28 */
ALIGN64 boolean authentication; /* 29 */
ALIGN64 uint32 negotiationFlags; /* 30 */
ALIGN64 uint64 paddingB[48 - 31]; /* 31 */
ALIGN64 boolean security_layer_negotiation; /* 31 */
ALIGN64 uint64 paddingB[48 - 32]; /* 32 */
/* Connection Settings */
ALIGN64 uint32 port; /* 48 */

View File

@@ -83,15 +83,12 @@ boolean rdp_send_pcb(rdpNego* nego) {
boolean rdp_client_connect(rdpRdp* rdp)
{
boolean negotiateSecurityLayer = false; // XXX: should be an option in the final version, with default value=true
boolean status;
uint32 selectedProtocol;
rdpSettings* settings = rdp->settings;
nego_init(rdp->nego);
nego_set_target(rdp->nego, settings->hostname, settings->port);
nego_set_cookie(rdp->nego, settings->username);
nego_set_negotiation_enabled(rdp->nego, settings->security_layer_negotiation);
nego_enable_rdp(rdp->nego, settings->rdp_security);
if (!settings->ts_gateway)
@@ -102,62 +99,26 @@ boolean rdp_client_connect(rdpRdp* rdp)
rdp_send_pcb(rdp->nego); // XXX: different name?!
if(negotiateSecurityLayer)
if (!nego_connect(rdp->nego))
{
if (nego_connect(rdp->nego) != true)
{
printf("Error: protocol security negotiation failure\n");
return false;
}
}
else
{
// set some predefined protocols if negotiateSecurityLayer is false
// XXX: should take settings->rdp_security into account. Right now we pretend NLA has been selected.
rdp->nego->state = NEGO_STATE_FINAL;
rdp->nego->transport->settings->requested_protocols = rdp->nego->requested_protocols = PROTOCOL_NLA | PROTOCOL_TLS;
rdp->nego->transport->settings->selected_protocol = rdp->nego->selected_protocol = PROTOCOL_NLA;
rdp->nego->transport->settings->negotiationFlags = rdp->nego->flags;
printf("Error: protocol security negotiation failure\n");
return false;
}
selectedProtocol = rdp->nego->selected_protocol;
if (!nego_security_connect(rdp->nego))
return false;
if ((selectedProtocol & PROTOCOL_TLS) || (selectedProtocol == PROTOCOL_RDP))
if ((rdp->nego->selected_protocol & PROTOCOL_TLS) || (rdp->nego->selected_protocol == PROTOCOL_RDP))
{
if ((settings->username != NULL) && ((settings->password != NULL) || (settings->password_cookie != NULL && settings->password_cookie->length > 0)))
settings->autologon = true;
}
status = false;
if (selectedProtocol & PROTOCOL_NLA)
status = transport_connect_nla(rdp->transport);
else if (selectedProtocol & PROTOCOL_TLS)
status = transport_connect_tls(rdp->transport);
else if (selectedProtocol == PROTOCOL_RDP) /* 0 */
status = transport_connect_rdp(rdp->transport);
if (status != true)
return false;
if(!negotiateSecurityLayer)
{
// XXX: the whole negotioation thing should be called differently.
// this is more like a hack in order to allow connection requests after establishing a secure connection.
rdp->nego->state = NEGO_STATE_INITIAL;
rdp->nego->transport = rdp->transport;
rdp->nego->transport->settings->requested_protocols = PROTOCOL_RDP; // removes requested_protocols section
if (nego_connect(rdp->nego) != true)
{
printf("Error: X.224 connection request failure\n");
return false;
}
}
rdp_set_blocking_mode(rdp, false);
rdp->state = CONNECTION_STATE_NEGO;
rdp->finalize_sc_pdus = 0;
if (mcs_send_connect_initial(rdp->mcs) != true)
if (!mcs_send_connect_initial(rdp->mcs))
{
if (!connectErrorCode)
{

View File

@@ -27,6 +27,8 @@
#include "nego.h"
#include "transport.h"
static const char* const NEGO_STATE_STRINGS[] =
{
"NEGO_STATE_INITIAL",
@@ -61,7 +63,24 @@ boolean nego_connect(rdpNego* nego)
else if (nego->enabled_protocols[PROTOCOL_RDP] > 0)
nego->state = NEGO_STATE_RDP;
else
{
DEBUG_NEGO("No security protocol is enabled");
nego->state = NEGO_STATE_FAIL;
}
if (!nego->security_layer_negotiation_enabled)
{
DEBUG_NEGO("Security Layer Negotiation is disabled");
nego->enabled_protocols[PROTOCOL_NLA] = 0;
nego->enabled_protocols[PROTOCOL_TLS] = 0;
nego->enabled_protocols[PROTOCOL_RDP] = 0;
if(nego->state == NEGO_STATE_NLA)
nego->enabled_protocols[PROTOCOL_NLA] = 1;
else if (nego->state == NEGO_STATE_TLS)
nego->enabled_protocols[PROTOCOL_TLS] = 1;
else if (nego->state == NEGO_STATE_RDP)
nego->enabled_protocols[PROTOCOL_RDP] = 1;
}
}
do
@@ -96,6 +115,25 @@ boolean nego_connect(rdpNego* nego)
return true;
}
/* connect to selected security layer */
boolean nego_security_connect(rdpNego* nego)
{
if(!nego->tcp_connected)
{
nego->security_connected = false;
}
else if (!nego->security_connected)
{
if (nego->enabled_protocols[PROTOCOL_NLA] > 0)
nego->security_connected = transport_connect_nla(nego->transport);
else if (nego->enabled_protocols[PROTOCOL_TLS] > 0)
nego->security_connected = transport_connect_tls(nego->transport);
else if (nego->enabled_protocols[PROTOCOL_RDP] > 0)
nego->security_connected = transport_connect_rdp(nego->transport);
}
return nego->security_connected;
}
/**
* Connect TCP layer.
* @param nego
@@ -104,21 +142,30 @@ boolean nego_connect(rdpNego* nego)
boolean nego_tcp_connect(rdpNego* nego)
{
if (nego->tcp_connected == 0)
if (!nego->tcp_connected)
{
if (transport_connect(nego->transport, nego->hostname, nego->port) == false)
{
nego->tcp_connected = 0;
return false;
}
else
{
nego->tcp_connected = 1;
return true;
}
nego->tcp_connected = transport_connect(nego->transport, nego->hostname, nego->port);
}
return nego->tcp_connected;
}
/**
* Connect TCP layer. For direct approach, connect security layer as well.
* @param nego
* @return
*/
boolean nego_transport_connect(rdpNego* nego)
{
nego_tcp_connect(nego);
if (nego->tcp_connected && !nego->security_layer_negotiation_enabled)
{
nego_security_connect(nego);
return nego->security_connected;
}
return true;
return nego->tcp_connected;
}
/**
@@ -127,12 +174,13 @@ boolean nego_tcp_connect(rdpNego* nego)
* @return
*/
int nego_tcp_disconnect(rdpNego* nego)
int nego_transport_disconnect(rdpNego* nego)
{
if (nego->tcp_connected)
transport_disconnect(nego->transport);
nego->tcp_connected = 0;
nego->security_connected = 0;
return 1;
}
@@ -147,7 +195,7 @@ void nego_attempt_nla(rdpNego* nego)
DEBUG_NEGO("Attempting NLA security");
if (!nego_tcp_connect(nego))
if (!nego_transport_connect(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
@@ -168,7 +216,7 @@ void nego_attempt_nla(rdpNego* nego)
DEBUG_NEGO("state: %s", NEGO_STATE_STRINGS[nego->state]);
if (nego->state != NEGO_STATE_FINAL)
{
nego_tcp_disconnect(nego);
nego_transport_disconnect(nego);
if (nego->enabled_protocols[PROTOCOL_TLS] > 0)
nego->state = NEGO_STATE_TLS;
@@ -190,7 +238,7 @@ void nego_attempt_tls(rdpNego* nego)
DEBUG_NEGO("Attempting TLS security");
if (!nego_tcp_connect(nego))
if (!nego_transport_connect(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
@@ -210,7 +258,7 @@ void nego_attempt_tls(rdpNego* nego)
if (nego->state != NEGO_STATE_FINAL)
{
nego_tcp_disconnect(nego);
nego_transport_disconnect(nego);
if (nego->enabled_protocols[PROTOCOL_RDP] > 0)
nego->state = NEGO_STATE_RDP;
@@ -230,7 +278,7 @@ void nego_attempt_rdp(rdpNego* nego)
DEBUG_NEGO("Attempting RDP security");
if (!nego_tcp_connect(nego))
if (!nego_transport_connect(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
@@ -704,6 +752,18 @@ void nego_set_target(rdpNego* nego, char* hostname, int port)
nego->port = port;
}
/**
* Enable security layer negotiation.
* @param nego pointer to the negotiation structure
* @param enable_rdp whether to enable security layer negotiation (true for enabled, false for disabled)
*/
void nego_set_negotiation_enabled(rdpNego* nego, boolean security_layer_negotiation_enabled)
{
DEBUG_NEGO("Enabling security layer negotiation: %s", security_layer_negotiation_enabled ? "true" : "false");
nego->security_layer_negotiation_enabled = security_layer_negotiation_enabled;
}
/**
* Enable RDP security protocol.
* @param nego pointer to the negotiation structure

View File

@@ -75,17 +75,20 @@ struct rdp_nego
char* hostname;
char* cookie;
NEGO_STATE state;
int tcp_connected;
boolean tcp_connected;
boolean security_connected;
rdpBlob* routing_token;
uint32 selected_protocol;
uint32 requested_protocols;
boolean security_layer_negotiation_enabled;
uint8 enabled_protocols[3];
rdpTransport* transport;
};
typedef struct rdp_nego rdpNego;
boolean nego_connect(rdpNego* nego);
boolean nego_tcp_connect(rdpNego* nego); // XXX: this is here for rdp_send_pcb. maybe there is a way around exporting it...
boolean nego_tcp_connect(rdpNego* nego);
boolean nego_security_connect(rdpNego* nego);
void nego_attempt_nla(rdpNego* nego);
void nego_attempt_tls(rdpNego* nego);
@@ -106,6 +109,7 @@ rdpNego* nego_new(struct rdp_transport * transport);
void nego_free(rdpNego* nego);
void nego_init(rdpNego* nego);
void nego_set_target(rdpNego* nego, char* hostname, int port);
void nego_set_negotiation_enabled(rdpNego* nego, boolean security_layer_negotiation_enabled);
void nego_enable_rdp(rdpNego* nego, boolean enable_rdp);
void nego_enable_nla(rdpNego* nego, boolean enable_nla);
void nego_enable_tls(rdpNego* nego, boolean enable_tls);

View File

@@ -97,6 +97,7 @@ rdpSettings* settings_new(void* instance)
settings->nla_security = true;
settings->tls_security = true;
settings->rdp_security = true;
settings->security_layer_negotiation = true;
settings->client_build = 2600;
settings->kbd_type = 4; /* @msdn{cc240510} 'IBM enhanced (101- or 102-key) keyboard' */
settings->kbd_subtype = 0;

View File

@@ -122,6 +122,7 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
" --disable-full-window-drag: disables full window drag\n"
" --disable-menu-animations: disables menu animations\n"
" --disable-theming: disables theming\n"
" --disable-security-layer-negotiation: disable negotiation of security layer and force highest enabled layer\n"
" --no-rdp: disable Standard RDP encryption\n"
" --no-tls: disable TLS encryption\n"
" --no-nla: disable network level authentication\n"
@@ -579,6 +580,10 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv,
return FREERDP_ARGS_PARSE_FAILURE;
}
}
else if (strcmp("--disable-security-layer-negotiation", argv[index]) == 0)
{
settings->security_layer_negotiation = false;
}
else if (strcmp("--tsg", argv[index]) == 0)
{
settings->ts_gateway = true;