added a setting and a command line flag to disable security layer negotiation
authorlysannkessler <lysann.kessler@gmail.com>
Wed, 25 Jul 2012 10:29:49 +0000 (12:29 +0200)
committerlysannkessler <lysann.kessler@gmail.com>
Wed, 25 Jul 2012 10:35:52 +0000 (12:35 +0200)
include/freerdp/settings.h
libfreerdp-core/connection.c
libfreerdp-core/nego.c
libfreerdp-core/nego.h
libfreerdp-core/settings.c
libfreerdp-utils/args.c

index 7d0a24b..6255cf2 100644 (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 */
index 1bed2cb..346dd13 100644 (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) != 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)
                {
index 9f9f6b6..d6cb912 100644 (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;
+}
 
-       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)
index 5bd7b63..e71e505 100644 (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);
index 4540ed9..277ea5e 100644 (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;
index 1a5b391..6853d00 100644 (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;