diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index aea34c94e..9cb250e82 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -197,6 +197,7 @@ static BOOL rdp_client_reset_codecs(rdpContext* context) BOOL rdp_client_connect(rdpRdp* rdp) { + UINT32 SelectedProtocol; BOOL status; rdpSettings* settings = rdp->settings; /* make sure SSL is initialize for earlier enough for crypto, by taking advantage of winpr SSL FIPS flag for openssl initialization */ @@ -306,7 +307,9 @@ BOOL rdp_client_connect(rdpRdp* rdp) return FALSE; } - if ((rdp->nego->SelectedProtocol & PROTOCOL_TLS) || (rdp->nego->SelectedProtocol == PROTOCOL_RDP)) + SelectedProtocol = nego_get_selected_protocol(rdp->nego); + + if ((SelectedProtocol & PROTOCOL_TLS) || (SelectedProtocol == PROTOCOL_RDP)) { if ((settings->Username != NULL) && ((settings->Password != NULL) || (settings->RedirectionPassword != NULL && settings->RedirectionPasswordLength > 0))) @@ -1169,6 +1172,8 @@ int rdp_client_transition_to_state(rdpRdp* rdp, int state) BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) { + UINT32 SelectedProtocol = 0; + UINT32 RequestedProtocols; BOOL status; rdpSettings* settings = rdp->settings; rdpNego* nego = rdp->nego; @@ -1177,26 +1182,26 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) if (!nego_read_request(nego, s)) return FALSE; - nego->SelectedProtocol = 0; + RequestedProtocols = nego_get_requested_protocols(nego); WLog_INFO(TAG, "Client Security: NLA:%d TLS:%d RDP:%d", - (nego->RequestedProtocols & PROTOCOL_NLA) ? 1 : 0, - (nego->RequestedProtocols & PROTOCOL_TLS) ? 1 : 0, - (nego->RequestedProtocols == PROTOCOL_RDP) ? 1 : 0 + (RequestedProtocols & PROTOCOL_NLA) ? 1 : 0, + (RequestedProtocols & PROTOCOL_TLS) ? 1 : 0, + (RequestedProtocols == PROTOCOL_RDP) ? 1 : 0 ); WLog_INFO(TAG, "Server Security: NLA:%"PRId32" TLS:%"PRId32" RDP:%"PRId32"", settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity); - if ((settings->NlaSecurity) && (nego->RequestedProtocols & PROTOCOL_NLA)) + if ((settings->NlaSecurity) && (RequestedProtocols & PROTOCOL_NLA)) { - nego->SelectedProtocol = PROTOCOL_NLA; + SelectedProtocol = PROTOCOL_NLA; } - else if ((settings->TlsSecurity) && (nego->RequestedProtocols & PROTOCOL_TLS)) + else if ((settings->TlsSecurity) && (RequestedProtocols & PROTOCOL_TLS)) { - nego->SelectedProtocol = PROTOCOL_TLS; + SelectedProtocol = PROTOCOL_TLS; } - else if ((settings->RdpSecurity) && (nego->RequestedProtocols == PROTOCOL_RDP)) + else if ((settings->RdpSecurity) && (RequestedProtocols == PROTOCOL_RDP)) { - nego->SelectedProtocol = PROTOCOL_RDP; + SelectedProtocol = PROTOCOL_RDP; } else { @@ -1204,49 +1209,53 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) * when here client and server aren't compatible, we select the right * error message to return to the client in the nego failure packet */ - nego->SelectedProtocol = PROTOCOL_FAILED_NEGO; + SelectedProtocol = PROTOCOL_FAILED_NEGO; if (settings->RdpSecurity) { WLog_ERR(TAG, "server supports only Standard RDP Security"); - nego->SelectedProtocol |= SSL_NOT_ALLOWED_BY_SERVER; + SelectedProtocol |= SSL_NOT_ALLOWED_BY_SERVER; } else { if (settings->NlaSecurity && !settings->TlsSecurity) { WLog_WARN(TAG, "server supports only NLA Security"); - nego->SelectedProtocol |= HYBRID_REQUIRED_BY_SERVER; + SelectedProtocol |= HYBRID_REQUIRED_BY_SERVER; } else { WLog_WARN(TAG, "server supports only a SSL based Security (TLS or NLA)"); - nego->SelectedProtocol |= SSL_REQUIRED_BY_SERVER; + SelectedProtocol |= SSL_REQUIRED_BY_SERVER; } } WLog_ERR(TAG, "Protocol security negotiation failure"); } - if (!(nego->SelectedProtocol & PROTOCOL_FAILED_NEGO)) + if (!(SelectedProtocol & PROTOCOL_FAILED_NEGO)) { WLog_INFO(TAG, "Negotiated Security: NLA:%d TLS:%d RDP:%d", - (nego->SelectedProtocol & PROTOCOL_NLA) ? 1 : 0, - (nego->SelectedProtocol & PROTOCOL_TLS) ? 1 : 0, - (nego->SelectedProtocol == PROTOCOL_RDP) ? 1 : 0 + (SelectedProtocol & PROTOCOL_NLA) ? 1 : 0, + (SelectedProtocol & PROTOCOL_TLS) ? 1 : 0, + (SelectedProtocol == PROTOCOL_RDP) ? 1 : 0 ); } + if (!nego_set_selected_protocol(nego, SelectedProtocol)) + return FALSE; + if (!nego_send_negotiation_response(nego)) return FALSE; + SelectedProtocol = nego_get_selected_protocol(nego); status = FALSE; - if (nego->SelectedProtocol & PROTOCOL_NLA) + if (SelectedProtocol & PROTOCOL_NLA) status = transport_accept_nla(rdp->transport); - else if (nego->SelectedProtocol & PROTOCOL_TLS) + else if (SelectedProtocol & PROTOCOL_TLS) status = transport_accept_tls(rdp->transport); - else if (nego->SelectedProtocol == PROTOCOL_RDP) /* 0 */ + else if (SelectedProtocol == PROTOCOL_RDP) /* 0 */ status = transport_accept_rdp(rdp->transport); if (!status) diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 3676a7898..ece8a4bfb 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -36,6 +36,35 @@ #define TAG FREERDP_TAG("core.nego") +struct rdp_nego +{ + int port; + UINT32 flags; + char* hostname; + char* cookie; + BYTE* RoutingToken; + DWORD RoutingTokenLength; + BOOL SendPreconnectionPdu; + UINT32 PreconnectionId; + char* PreconnectionBlob; + + NEGO_STATE state; + BOOL TcpConnected; + BOOL SecurityConnected; + UINT32 CookieMaxLength; + + BOOL sendNegoData; + UINT32 SelectedProtocol; + UINT32 RequestedProtocols; + BOOL NegotiateSecurityLayer; + BYTE EnabledProtocols[16]; + BOOL RestrictedAdminModeRequired; + BOOL GatewayEnabled; + BOOL GatewayBypassLocal; + + rdpTransport* transport; +}; + static const char* const NEGO_STATE_STRINGS[] = { "NEGO_STATE_INITIAL", @@ -1339,3 +1368,72 @@ void nego_set_preconnection_blob(rdpNego* nego, char* PreconnectionBlob) { nego->PreconnectionBlob = PreconnectionBlob; } + +UINT32 nego_get_selected_protocol(rdpNego* nego) +{ + if (!nego) + return 0; + + return nego->SelectedProtocol; +} + +BOOL nego_set_selected_protocol(rdpNego* nego, UINT32 SelectedProtocol) +{ + if (!nego) + return FALSE; + + nego->SelectedProtocol = SelectedProtocol; + return TRUE; +} + +UINT32 nego_get_requested_protocols(rdpNego* nego) +{ + if (!nego) + return 0; + + return nego->RequestedProtocols; +} + + +BOOL nego_set_requested_protocols(rdpNego* nego, UINT32 RequestedProtocols) +{ + if (!nego) + return FALSE; + + nego->RequestedProtocols = RequestedProtocols; + return TRUE; +} + +NEGO_STATE nego_get_state(rdpNego* nego) +{ + if (!nego) + return NEGO_STATE_FAIL; + + return nego->state; +} + +BOOL nego_set_state(rdpNego* nego, NEGO_STATE state) +{ + if (!nego) + return FALSE; + + nego->state = state; + return TRUE; +} + +SEC_WINNT_AUTH_IDENTITY* nego_get_identity(rdpNego* nego) +{ + if (!nego) + return NULL; + + return nego->transport->nla->identity; +} + +void nego_free_nla(rdpNego* nego) +{ + if (!nego || !nego->transport) + return; + + nla_free(nego->transport->nla); + nego->transport->nla = NULL; +} diff --git a/libfreerdp/core/nego.h b/libfreerdp/core/nego.h index ebfbd2729..1ae06535e 100644 --- a/libfreerdp/core/nego.h +++ b/libfreerdp/core/nego.h @@ -90,34 +90,6 @@ enum RDP_NEG_MSG #define REDIRECTED_AUTHENTICATION_MODE_REQUIRED 0x02 #define CORRELATION_INFO_PRESENT 0x08 -struct rdp_nego -{ - int port; - UINT32 flags; - char* hostname; - char* cookie; - BYTE* RoutingToken; - DWORD RoutingTokenLength; - BOOL SendPreconnectionPdu; - UINT32 PreconnectionId; - char* PreconnectionBlob; - - NEGO_STATE state; - BOOL TcpConnected; - BOOL SecurityConnected; - UINT32 CookieMaxLength; - - BOOL sendNegoData; - UINT32 SelectedProtocol; - UINT32 RequestedProtocols; - BOOL NegotiateSecurityLayer; - BYTE EnabledProtocols[16]; - BOOL RestrictedAdminModeRequired; - BOOL GatewayEnabled; - BOOL GatewayBypassLocal; - - rdpTransport* transport; -}; typedef struct rdp_nego rdpNego; FREERDP_LOCAL BOOL nego_connect(rdpNego* nego); @@ -157,4 +129,17 @@ FREERDP_LOCAL void nego_set_preconnection_id(rdpNego* nego, FREERDP_LOCAL void nego_set_preconnection_blob(rdpNego* nego, char* PreconnectionBlob); +FREERDP_LOCAL UINT32 nego_get_selected_protocol(rdpNego* nego); +FREERDP_LOCAL BOOL nego_set_selected_protocol(rdpNego* nego, UINT32 SelectedProtocol); + +FREERDP_LOCAL UINT32 nego_get_requested_protocols(rdpNego* nego); +FREERDP_LOCAL BOOL nego_set_requested_protocols(rdpNego* nego, UINT32 RequestedProtocols); + +FREERDP_LOCAL BOOL nego_set_state(rdpNego* nego, NEGO_STATE state); +FREERDP_LOCAL NEGO_STATE nego_get_state(rdpNego* nego); + +FREERDP_LOCAL SEC_WINNT_AUTH_IDENTITY* nego_get_identity(rdpNego* nego); + +FREERDP_LOCAL void nego_free_nla(rdpNego* nego); + #endif /* FREERDP_LIB_CORE_NEGO_H */ diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index 15cef3b65..7bde75b39 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -464,6 +464,7 @@ static int peer_recv_pdu(freerdp_peer* client, wStream* s) static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) { + UINT32 SelectedProtocol; freerdp_peer* client = (freerdp_peer*) extra; rdpRdp* rdp = client->context->rdp; @@ -476,16 +477,17 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) return -1; } - client->settings->NlaSecurity = (rdp->nego->SelectedProtocol & PROTOCOL_NLA) ? TRUE : FALSE; - client->settings->TlsSecurity = (rdp->nego->SelectedProtocol & PROTOCOL_TLS) ? TRUE : FALSE; - client->settings->RdpSecurity = (rdp->nego->SelectedProtocol == PROTOCOL_RDP) ? TRUE : FALSE; + SelectedProtocol = nego_get_selected_protocol(rdp->nego); + client->settings->NlaSecurity = (SelectedProtocol & PROTOCOL_NLA) ? TRUE : FALSE; + client->settings->TlsSecurity = (SelectedProtocol & PROTOCOL_TLS) ? TRUE : FALSE; + client->settings->RdpSecurity = (SelectedProtocol == PROTOCOL_RDP) ? TRUE : FALSE; - if (rdp->nego->SelectedProtocol & PROTOCOL_NLA) + if (SelectedProtocol & PROTOCOL_NLA) { - sspi_CopyAuthIdentity(&client->identity, rdp->nego->transport->nla->identity); + SEC_WINNT_AUTH_IDENTITY* identity = nego_get_identity(rdp->nego); + sspi_CopyAuthIdentity(&client->identity, identity); IFCALLRET(client->Logon, client->authenticated, client, &client->identity, TRUE); - nla_free(rdp->nego->transport->nla); - rdp->nego->transport->nla = NULL; + nego_free_nla(rdp->nego); } else { @@ -497,7 +499,8 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) case CONNECTION_STATE_NEGO: if (!rdp_server_accept_mcs_connect_initial(rdp, s)) { - WLog_ERR(TAG, "peer_recv_callback: CONNECTION_STATE_NEGO - rdp_server_accept_mcs_connect_initial() fail"); + WLog_ERR(TAG, + "peer_recv_callback: CONNECTION_STATE_NEGO - rdp_server_accept_mcs_connect_initial() fail"); return -1; } @@ -642,10 +645,13 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) static BOOL freerdp_peer_close(freerdp_peer* client) { + UINT32 SelectedProtocol; /** if negotiation has failed, we're not MCS connected. So don't * send anything else, or some mstsc will consider that as an error */ - if (client->context->rdp->nego->SelectedProtocol & PROTOCOL_FAILED_NEGO) + SelectedProtocol = nego_get_selected_protocol(client->context->rdp->nego); + + if (SelectedProtocol & PROTOCOL_FAILED_NEGO) return TRUE; /** diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 9baeb0cfa..07492ac3b 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -1400,7 +1400,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) { nego_recv(rdp->transport, s, (void*) rdp->nego); - if (rdp->nego->state != NEGO_STATE_FINAL) + if (nego_get_state(rdp->nego) != NEGO_STATE_FINAL) { WLog_ERR(TAG, "rdp_recv_callback: CONNECTION_STATE_NLA - nego_recv() fail"); return -1; @@ -1415,8 +1415,12 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (rdp->settings->VmConnectMode) { - rdp->nego->state = NEGO_STATE_NLA; - rdp->nego->RequestedProtocols = PROTOCOL_NLA | PROTOCOL_TLS; + if (!nego_set_state(rdp->nego, NEGO_STATE_NLA)) + return -1; + + if (!nego_set_requested_protocols(rdp->nego, PROTOCOL_NLA | PROTOCOL_TLS)) + return -1; + nego_send_negotiation_request(rdp->nego); rdp->nla->state = NLA_STATE_POST_NEGO; }