Made nego self contained.

This commit is contained in:
Armin Novak 2018-11-20 16:38:06 +01:00
parent a1c2033226
commit 5ca8eca18e
5 changed files with 164 additions and 62 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
/**

View File

@ -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;
}