libfreerdp-core: make NLA event-driven
This commit is contained in:
parent
eddfee56a3
commit
9c7b7ab561
@ -289,22 +289,10 @@ BOOL rdp_client_connect(rdpRdp* rdp)
|
||||
rdp->transport->ReceiveExtra = rdp;
|
||||
transport_set_blocking_mode(rdp->transport, FALSE);
|
||||
|
||||
rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CONNECT);
|
||||
|
||||
if (!mcs_send_connect_initial(rdp->mcs))
|
||||
if (rdp->state != CONNECTION_STATE_NLA)
|
||||
{
|
||||
if (!connectErrorCode)
|
||||
{
|
||||
connectErrorCode = MCSCONNECTINITIALERROR;
|
||||
}
|
||||
|
||||
if (!freerdp_get_last_error(rdp->context))
|
||||
{
|
||||
freerdp_set_last_error(rdp->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "Error: unable to send MCS Connect Initial");
|
||||
return FALSE;
|
||||
if (!mcs_client_begin(rdp->mcs))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (rdp->state != CONNECTION_STATE_ACTIVE)
|
||||
@ -898,6 +886,10 @@ int rdp_client_transition_to_state(rdpRdp* rdp, int state)
|
||||
rdp->state = CONNECTION_STATE_NEGO;
|
||||
break;
|
||||
|
||||
case CONNECTION_STATE_NLA:
|
||||
rdp->state = CONNECTION_STATE_NLA;
|
||||
break;
|
||||
|
||||
case CONNECTION_STATE_MCS_CONNECT:
|
||||
rdp->state = CONNECTION_STATE_MCS_CONNECT;
|
||||
break;
|
||||
|
@ -31,20 +31,21 @@
|
||||
|
||||
enum CONNECTION_STATE
|
||||
{
|
||||
CONNECTION_STATE_INITIAL = 0,
|
||||
CONNECTION_STATE_NEGO = 1,
|
||||
CONNECTION_STATE_MCS_CONNECT = 2,
|
||||
CONNECTION_STATE_MCS_ERECT_DOMAIN = 3,
|
||||
CONNECTION_STATE_MCS_ATTACH_USER = 4,
|
||||
CONNECTION_STATE_MCS_CHANNEL_JOIN = 5,
|
||||
CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT = 6,
|
||||
CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE = 7,
|
||||
CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT = 8,
|
||||
CONNECTION_STATE_LICENSING = 9,
|
||||
CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING = 10,
|
||||
CONNECTION_STATE_CAPABILITIES_EXCHANGE = 11,
|
||||
CONNECTION_STATE_FINALIZATION = 12,
|
||||
CONNECTION_STATE_ACTIVE = 13
|
||||
CONNECTION_STATE_INITIAL,
|
||||
CONNECTION_STATE_NEGO,
|
||||
CONNECTION_STATE_NLA,
|
||||
CONNECTION_STATE_MCS_CONNECT,
|
||||
CONNECTION_STATE_MCS_ERECT_DOMAIN,
|
||||
CONNECTION_STATE_MCS_ATTACH_USER,
|
||||
CONNECTION_STATE_MCS_CHANNEL_JOIN,
|
||||
CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT,
|
||||
CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE,
|
||||
CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT,
|
||||
CONNECTION_STATE_LICENSING,
|
||||
CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING,
|
||||
CONNECTION_STATE_CAPABILITIES_EXCHANGE,
|
||||
CONNECTION_STATE_FINALIZATION,
|
||||
CONNECTION_STATE_ACTIVE
|
||||
};
|
||||
|
||||
BOOL rdp_client_connect(rdpRdp* rdp);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "tpdu.h"
|
||||
#include "tpkt.h"
|
||||
#include "client.h"
|
||||
#include "connection.h"
|
||||
|
||||
#define TAG FREERDP_TAG("core")
|
||||
|
||||
@ -1049,6 +1050,30 @@ BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs)
|
||||
return (status < 0) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
BOOL mcs_client_begin(rdpMcs* mcs)
|
||||
{
|
||||
rdpContext* context = mcs->transport->context;
|
||||
|
||||
if (!mcs_send_connect_initial(mcs))
|
||||
{
|
||||
if (!connectErrorCode)
|
||||
{
|
||||
connectErrorCode = MCSCONNECTINITIALERROR;
|
||||
}
|
||||
|
||||
if (!freerdp_get_last_error(context))
|
||||
{
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "Error: unable to send MCS Connect Initial");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rdp_client_transition_to_state(context->rdp, CONNECTION_STATE_MCS_CONNECT);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate new MCS module.
|
||||
* @param transport transport
|
||||
|
@ -186,6 +186,8 @@ BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs);
|
||||
BOOL mcs_read_domain_mcspdu_header(wStream* s, enum DomainMCSPDU* domainMCSPDU, UINT16* length);
|
||||
void mcs_write_domain_mcspdu_header(wStream* s, enum DomainMCSPDU domainMCSPDU, UINT16 length, BYTE options);
|
||||
|
||||
BOOL mcs_client_begin(rdpMcs* mcs);
|
||||
|
||||
rdpMcs* mcs_new(rdpTransport* transport);
|
||||
void mcs_free(rdpMcs* mcs);
|
||||
|
||||
|
@ -251,60 +251,64 @@ int nla_client_init(rdpNla* nla)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nla_client_authenticate(rdpNla* nla)
|
||||
int nla_client_begin(rdpNla* nla)
|
||||
{
|
||||
if (nla_client_init(nla) < 1)
|
||||
return -1;
|
||||
|
||||
if (nla->state == NLA_STATE_INITIAL)
|
||||
if (nla->state != NLA_STATE_INITIAL)
|
||||
return -1;
|
||||
|
||||
nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
nla->outputBufferDesc.cBuffers = 1;
|
||||
nla->outputBufferDesc.pBuffers = &nla->outputBuffer;
|
||||
nla->outputBuffer.BufferType = SECBUFFER_TOKEN;
|
||||
nla->outputBuffer.cbBuffer = nla->cbMaxToken;
|
||||
nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer);
|
||||
|
||||
if (!nla->outputBuffer.pvBuffer)
|
||||
return -1;
|
||||
|
||||
nla->status = nla->table->InitializeSecurityContext(&nla->credentials,
|
||||
NULL, nla->ServicePrincipalName, nla->fContextReq, 0,
|
||||
SECURITY_NATIVE_DREP, NULL, 0, &nla->context,
|
||||
&nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
|
||||
|
||||
if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
nla->outputBufferDesc.cBuffers = 1;
|
||||
nla->outputBufferDesc.pBuffers = &nla->outputBuffer;
|
||||
nla->outputBuffer.BufferType = SECBUFFER_TOKEN;
|
||||
nla->outputBuffer.cbBuffer = nla->cbMaxToken;
|
||||
nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer);
|
||||
if (nla->table->CompleteAuthToken)
|
||||
nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc);
|
||||
|
||||
if (!nla->outputBuffer.pvBuffer)
|
||||
return -1;
|
||||
|
||||
nla->status = nla->table->InitializeSecurityContext(&nla->credentials,
|
||||
NULL, nla->ServicePrincipalName, nla->fContextReq, 0,
|
||||
SECURITY_NATIVE_DREP, NULL, 0, &nla->context,
|
||||
&nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
|
||||
|
||||
if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
if (nla->table->CompleteAuthToken)
|
||||
nla->table->CompleteAuthToken(&nla->context, &nla->outputBufferDesc);
|
||||
|
||||
if (nla->status == SEC_I_COMPLETE_NEEDED)
|
||||
nla->status = SEC_E_OK;
|
||||
else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
nla->status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if (nla->status != SEC_I_CONTINUE_NEEDED)
|
||||
return -1;
|
||||
|
||||
if (nla->outputBuffer.cbBuffer < 1)
|
||||
return -1;
|
||||
|
||||
nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer;
|
||||
nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer;
|
||||
|
||||
WLog_DBG(TAG, "Sending Authentication Token");
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, nla->negoToken.pvBuffer, nla->negoToken.cbBuffer);
|
||||
|
||||
nla_send(nla);
|
||||
nla_buffer_free(nla);
|
||||
|
||||
nla->state = NLA_STATE_NEGO_TOKEN;
|
||||
if (nla->status == SEC_I_COMPLETE_NEEDED)
|
||||
nla->status = SEC_E_OK;
|
||||
else if (nla->status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
nla->status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if (nla_recv(nla) < 0)
|
||||
if (nla->status != SEC_I_CONTINUE_NEEDED)
|
||||
return -1;
|
||||
|
||||
if (nla->outputBuffer.cbBuffer < 1)
|
||||
return -1;
|
||||
|
||||
nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer;
|
||||
nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer;
|
||||
|
||||
WLog_DBG(TAG, "Sending Authentication Token");
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, nla->negoToken.pvBuffer, nla->negoToken.cbBuffer);
|
||||
|
||||
nla_send(nla);
|
||||
nla_buffer_free(nla);
|
||||
|
||||
nla->state = NLA_STATE_NEGO_TOKEN;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nla_client_recv(rdpNla* nla)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
if (nla->state == NLA_STATE_NEGO_TOKEN)
|
||||
{
|
||||
nla->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
@ -369,12 +373,9 @@ int nla_client_authenticate(rdpNla* nla)
|
||||
nla_buffer_free(nla);
|
||||
|
||||
nla->state = NLA_STATE_PUB_KEY_AUTH;
|
||||
status = 1;
|
||||
}
|
||||
|
||||
if (nla_recv(nla) < 0)
|
||||
return -1;
|
||||
|
||||
if (nla->state == NLA_STATE_PUB_KEY_AUTH)
|
||||
else if (nla->state == NLA_STATE_PUB_KEY_AUTH)
|
||||
{
|
||||
/* Verify Server Public Key Echo */
|
||||
nla->status = nla_decrypt_public_key_echo(nla);
|
||||
@ -398,13 +399,47 @@ int nla_client_authenticate(rdpNla* nla)
|
||||
nla_send(nla);
|
||||
nla_buffer_free(nla);
|
||||
|
||||
nla->state = NLA_STATE_AUTH_INFO;
|
||||
|
||||
/* Free resources */
|
||||
nla->table->FreeCredentialsHandle(&nla->credentials);
|
||||
nla->table->FreeContextBuffer(nla->pPackageInfo);
|
||||
|
||||
nla->state = NLA_STATE_AUTH_INFO;
|
||||
status = 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int nla_client_authenticate(rdpNla* nla)
|
||||
{
|
||||
wStream* s;
|
||||
int status;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
|
||||
if (nla_client_begin(nla) < 1)
|
||||
return -1;
|
||||
|
||||
while (nla->state < NLA_STATE_AUTH_INFO)
|
||||
{
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
status = transport_read_pdu(nla->transport, s);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "nla_client_authenticate failure");
|
||||
Stream_Free(s, TRUE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = nla_recv_pdu(nla, s);
|
||||
|
||||
if (status < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1110,7 +1145,7 @@ void nla_send(rdpNla* nla)
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
int nla_recv_ts_request(rdpNla* nla, wStream* s)
|
||||
int nla_decode_ts_request(rdpNla* nla, wStream* s)
|
||||
{
|
||||
int length;
|
||||
UINT32 version;
|
||||
@ -1175,6 +1210,17 @@ int nla_recv_ts_request(rdpNla* nla, wStream* s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nla_recv_pdu(rdpNla* nla, wStream* s)
|
||||
{
|
||||
if (nla_decode_ts_request(nla, s) < 1)
|
||||
return -1;
|
||||
|
||||
if (nla_client_recv(nla) < 1)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nla_recv(rdpNla* nla)
|
||||
{
|
||||
wStream* s;
|
||||
@ -1191,7 +1237,7 @@ int nla_recv(rdpNla* nla)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nla_recv_ts_request(nla, s) < 1)
|
||||
if (nla_recv_pdu(nla, s) < 1)
|
||||
return -1;
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
@ -85,6 +85,9 @@ struct rdp_nla
|
||||
int nla_authenticate(rdpNla* nla);
|
||||
LPTSTR nla_make_spn(const char* ServiceClass, const char* hostname);
|
||||
|
||||
int nla_client_begin(rdpNla* nla);
|
||||
int nla_recv_pdu(rdpNla* nla, wStream* s);
|
||||
|
||||
rdpNla* nla_new(freerdp* instance, rdpTransport* transport, rdpSettings* settings);
|
||||
void nla_free(rdpNla* nla);
|
||||
|
||||
|
@ -1187,6 +1187,23 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
|
||||
|
||||
switch (rdp->state)
|
||||
{
|
||||
case CONNECTION_STATE_NLA:
|
||||
if (nla_recv_pdu(rdp->nla, s) < 1)
|
||||
return -1;
|
||||
|
||||
if (rdp->nla->state == NLA_STATE_AUTH_INFO)
|
||||
{
|
||||
transport_set_nla_mode(rdp->transport, FALSE);
|
||||
|
||||
nla_free(rdp->nla);
|
||||
rdp->nla = NULL;
|
||||
|
||||
if (!mcs_client_begin(rdp->mcs))
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CONNECTION_STATE_MCS_CONNECT:
|
||||
if (!mcs_recv_connect_response(rdp->mcs, s))
|
||||
{
|
||||
@ -1528,6 +1545,7 @@ void rdp_free(rdpRdp* rdp)
|
||||
fastpath_free(rdp->fastpath);
|
||||
nego_free(rdp->nego);
|
||||
mcs_free(rdp->mcs);
|
||||
nla_free(rdp->nla);
|
||||
redirection_free(rdp->redirection);
|
||||
autodetect_free(rdp->autodetect);
|
||||
heartbeat_free(rdp->heartbeat);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "nla.h"
|
||||
#include "mcs.h"
|
||||
#include "tpkt.h"
|
||||
#include "bulk.h"
|
||||
@ -132,6 +133,7 @@ struct rdp_rdp
|
||||
int state;
|
||||
freerdp* instance;
|
||||
rdpContext* context;
|
||||
rdpNla* nla;
|
||||
rdpMcs* mcs;
|
||||
rdpNego* nego;
|
||||
rdpBulk* bulk;
|
||||
|
@ -158,62 +158,51 @@ BOOL transport_connect_tls(rdpTransport* transport)
|
||||
|
||||
BOOL transport_connect_nla(rdpTransport* transport)
|
||||
{
|
||||
rdpNla* nla;
|
||||
freerdp* instance;
|
||||
rdpSettings* settings;
|
||||
settings = transport->settings;
|
||||
instance = (freerdp*) settings->instance;
|
||||
rdpContext* context = transport->context;
|
||||
rdpSettings* settings = context->settings;
|
||||
freerdp* instance = context->instance;
|
||||
rdpRdp* rdp = context->rdp;
|
||||
|
||||
if (!transport_connect_tls(transport))
|
||||
return FALSE;
|
||||
|
||||
/* Network Level Authentication */
|
||||
|
||||
if (!settings->Authentication)
|
||||
return TRUE;
|
||||
|
||||
if (!transport->nla)
|
||||
rdp->nla = nla_new(instance, transport, settings);
|
||||
|
||||
if (!rdp->nla)
|
||||
return FALSE;
|
||||
|
||||
transport_set_nla_mode(transport, TRUE);
|
||||
|
||||
if (settings->AuthenticationServiceClass)
|
||||
{
|
||||
transport->nla = nla_new(instance, transport, settings);
|
||||
rdp->nla->ServicePrincipalName =
|
||||
nla_make_spn(settings->AuthenticationServiceClass, settings->ServerHostname);
|
||||
|
||||
if (!transport->nla)
|
||||
if (!rdp->nla->ServicePrincipalName)
|
||||
return FALSE;
|
||||
|
||||
transport_set_nla_mode(transport, TRUE);
|
||||
|
||||
if (settings->AuthenticationServiceClass)
|
||||
{
|
||||
transport->nla->ServicePrincipalName =
|
||||
nla_make_spn(settings->AuthenticationServiceClass, settings->ServerHostname);
|
||||
|
||||
if (!transport->nla->ServicePrincipalName)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nla = transport->nla;
|
||||
|
||||
if (nla_authenticate(nla) < 0)
|
||||
if (nla_client_begin(rdp->nla) < 0)
|
||||
{
|
||||
if (!connectErrorCode)
|
||||
connectErrorCode = AUTHENTICATIONERROR;
|
||||
|
||||
if (!freerdp_get_last_error(instance->context))
|
||||
{
|
||||
freerdp_set_last_error(instance->context, FREERDP_ERROR_AUTHENTICATION_FAILED);
|
||||
}
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_AUTHENTICATION_FAILED);
|
||||
|
||||
WLog_ERR(TAG, "Authentication failure, check credentials."
|
||||
"If credentials are valid, the NTLMSSP implementation may be to blame.");
|
||||
|
||||
transport_set_nla_mode(transport, FALSE);
|
||||
nla_free(nla);
|
||||
transport->nla = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
transport_set_nla_mode(transport, FALSE);
|
||||
nla_free(nla);
|
||||
transport->nla = NULL;
|
||||
rdp_client_transition_to_state(rdp, CONNECTION_STATE_NLA);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user