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 */
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)
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)
{
#include "nego.h"
+#include "transport.h"
+
static const char* const NEGO_STATE_STRINGS[] =
{
"NEGO_STATE_INITIAL",
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
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
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;
}
/**
* @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;
}
DEBUG_NEGO("Attempting NLA security");
- if (!nego_tcp_connect(nego))
+ if (!nego_transport_connect(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
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;
DEBUG_NEGO("Attempting TLS security");
- if (!nego_tcp_connect(nego))
+ if (!nego_transport_connect(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
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;
DEBUG_NEGO("Attempting RDP security");
- if (!nego_tcp_connect(nego))
+ if (!nego_transport_connect(nego))
{
nego->state = NEGO_STATE_FAIL;
return;
}
/**
+ * 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)
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);
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);
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;
" --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"
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;