From 3c6df9597811c32dfd4555e69b18f5498f030dcc Mon Sep 17 00:00:00 2001 From: lysannkessler Date: Wed, 25 Jul 2012 12:29:49 +0200 Subject: [PATCH] added a setting and a command line flag to disable security layer negotiation --- include/freerdp/settings.h | 3 +- libfreerdp-core/connection.c | 55 ++++--------------------- libfreerdp-core/nego.c | 96 +++++++++++++++++++++++++++++++++++--------- libfreerdp-core/nego.h | 8 +++- libfreerdp-core/settings.c | 1 + libfreerdp-utils/args.c | 5 +++ 6 files changed, 100 insertions(+), 68 deletions(-) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 7d0a24b..6255cf2 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -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 */ diff --git a/libfreerdp-core/connection.c b/libfreerdp-core/connection.c index 1bed2cb..346dd13 100644 --- a/libfreerdp-core/connection.c +++ b/libfreerdp-core/connection.c @@ -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) != true) - { - printf("Error: protocol security negotiation failure\n"); - return false; - } - } - else + if (!nego_connect(rdp->nego)) { - // 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) { diff --git a/libfreerdp-core/nego.c b/libfreerdp-core/nego.c index 9f9f6b6..d6cb912 100644 --- a/libfreerdp-core/nego.c +++ b/libfreerdp-core/nego.c @@ -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; +} - return true; +/** + * 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 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; @@ -705,6 +753,18 @@ void nego_set_target(rdpNego* nego, char* hostname, int 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 * @param enable_rdp whether to enable normal RDP protocol (true for enabled, false for disabled) diff --git a/libfreerdp-core/nego.h b/libfreerdp-core/nego.h index 5bd7b63..e71e505 100644 --- a/libfreerdp-core/nego.h +++ b/libfreerdp-core/nego.h @@ -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); diff --git a/libfreerdp-core/settings.c b/libfreerdp-core/settings.c index 4540ed9..277ea5e 100644 --- a/libfreerdp-core/settings.c +++ b/libfreerdp-core/settings.c @@ -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; diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 1a5b391..6853d00 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -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; -- 2.7.4