return FALSE;
}
+ rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO);
+
if (!nego_connect(rdp->nego))
{
if (!freerdp_get_last_error(rdp->context))
settings->AutoLogonEnabled = TRUE;
}
- rdp_set_blocking_mode(rdp, FALSE);
+ /* everything beyond this point is event-driven and non blocking */
- rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO);
- rdp->finalize_sc_pdus = 0;
+ rdp->transport->ReceiveCallback = rdp_recv_callback;
+ 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))
{
return ret;
}
-BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s)
-{
- if (!mcs_recv_connect_response(rdp->mcs, s))
- {
- WLog_ERR(TAG, "rdp_client_connect_mcs_connect_response: mcs_recv_connect_response failed");
- return FALSE;
- }
-
- if (!mcs_send_erect_domain_request(rdp->mcs))
- return FALSE;
-
- if (!mcs_send_attach_user_request(rdp->mcs))
- return FALSE;
-
- rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
-
- return TRUE;
-}
-
-BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s)
-{
- if (!mcs_recv_attach_user_confirm(rdp->mcs, s))
- return FALSE;
-
- if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->userId))
- return FALSE;
-
- rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN);
-
- return TRUE;
-}
-
BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s)
{
UINT32 i;
BOOL rdp_client_disconnect(rdpRdp* rdp);
BOOL rdp_client_reconnect(rdpRdp* rdp);
BOOL rdp_client_redirect(rdpRdp* rdp);
-BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s);
-BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s);
BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s);
int rdp_client_connect_license(rdpRdp* rdp, wStream* s);
{
nego->state = NEGO_STATE_INITIAL;
nego->RequestedProtocols = PROTOCOL_RDP;
- nego->transport->ReceiveCallback = nego_recv;
- nego->transport->ReceiveExtra = (void*) nego;
nego->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH;
nego->sendNegoData = FALSE;
nego->flags = 0;
rdpNego* nego_new(rdpTransport* transport)
{
rdpNego* nego = (rdpNego*) calloc(1, sizeof(rdpNego));
+
if (!nego)
return NULL;
-
nego->transport = transport;
+
nego_init(nego);
return nego;
* @param credssp
*/
-int nla_ntlm_client_init(rdpNla* nla)
+int nla_client_init(rdpNla* nla)
{
char* spn;
int length;
settings = nla->settings;
instance = (freerdp*) settings->instance;
+ nla->state = NLA_STATE_INITIAL;
+
if (settings->RestrictedAdminModeRequired)
settings->DisableCredentialsDelegation = TRUE;
int nla_client_authenticate(rdpNla* nla)
{
- if (nla_ntlm_client_init(nla) < 1)
+ if (nla_client_init(nla) < 1)
return -1;
- while (TRUE)
+ if (nla->state == NLA_STATE_INITIAL)
{
nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
nla->outputBufferDesc.cBuffers = 1;
return -1;
nla->status = nla->table->InitializeSecurityContext(&nla->credentials,
- (nla->haveContext) ? &nla->context : NULL,
- nla->ServicePrincipalName, nla->fContextReq, 0,
- SECURITY_NATIVE_DREP, (nla->haveInputBuffer) ? &nla->inputBufferDesc : NULL,
- 0, &nla->context, &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
+ NULL, nla->ServicePrincipalName, nla->fContextReq, 0,
+ SECURITY_NATIVE_DREP, NULL, 0, &nla->context,
+ &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
- if (nla->haveInputBuffer && (nla->inputBuffer.pvBuffer))
+ if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
{
- free(nla->inputBuffer.pvBuffer);
- nla->inputBuffer.pvBuffer = NULL;
+ 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_recv(nla) < 0)
+ return -1;
+
+ if (nla->state == NLA_STATE_NEGO_TOKEN)
+ {
+ nla->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
+ nla->inputBufferDesc.cBuffers = 1;
+ nla->inputBufferDesc.pBuffers = &nla->inputBuffer;
+ nla->inputBuffer.BufferType = SECBUFFER_TOKEN;
+ nla->inputBuffer.pvBuffer = nla->negoToken.pvBuffer;
+ nla->inputBuffer.cbBuffer = nla->negoToken.cbBuffer;
+
+ 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,
+ &nla->context, nla->ServicePrincipalName, nla->fContextReq, 0,
+ SECURITY_NATIVE_DREP, &nla->inputBufferDesc,
+ 0, &nla->context, &nla->outputBufferDesc, &nla->pfContextAttr, &nla->expiration);
+
+ free(nla->inputBuffer.pvBuffer);
+ nla->inputBuffer.pvBuffer = NULL;
+
if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED))
{
if (nla->table->CompleteAuthToken)
nla_encrypt_public_key_echo(nla);
}
- /* send authentication token to server */
-
- if (nla->outputBuffer.cbBuffer > 0)
- {
- 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);
- }
-
- if (nla->status != SEC_I_CONTINUE_NEEDED)
- break;
-
- /* receive server response and place in input buffer */
- nla->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
- nla->inputBufferDesc.cBuffers = 1;
- nla->inputBufferDesc.pBuffers = &nla->inputBuffer;
- nla->inputBuffer.BufferType = SECBUFFER_TOKEN;
-
- if (nla_recv(nla) < 0)
+ if (nla->outputBuffer.cbBuffer < 1)
return -1;
- WLog_DBG(TAG, "Receiving Authentication Token (%d)", (int) nla->negoToken.cbBuffer);
+ 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->inputBuffer.pvBuffer = nla->negoToken.pvBuffer;
- nla->inputBuffer.cbBuffer = nla->negoToken.cbBuffer;
- nla->haveInputBuffer = TRUE;
- nla->haveContext = TRUE;
+ nla_send(nla);
+ nla_buffer_free(nla);
+
+ nla->state = NLA_STATE_PUB_KEY_AUTH;
}
- /* Encrypted Public Key +1 */
if (nla_recv(nla) < 0)
return -1;
- /* Verify Server Public Key Echo */
- nla->status = nla_decrypt_public_key_echo(nla);
- nla_buffer_free(nla);
-
- if (nla->status != SEC_E_OK)
+ if (nla->state == NLA_STATE_PUB_KEY_AUTH)
{
- WLog_ERR(TAG, "Could not verify public key echo!");
- return -1;
- }
+ /* Verify Server Public Key Echo */
+ nla->status = nla_decrypt_public_key_echo(nla);
+ nla_buffer_free(nla);
- /* Send encrypted credentials */
- nla->status = nla_encrypt_ts_credentials(nla);
+ if (nla->status != SEC_E_OK)
+ {
+ WLog_ERR(TAG, "Could not verify public key echo!");
+ return -1;
+ }
- if (nla->status != SEC_E_OK)
- {
- WLog_ERR(TAG, "nla_encrypt_ts_credentials status: 0x%08X", nla->status);
- return -1;
- }
+ /* Send encrypted credentials */
+ nla->status = nla_encrypt_ts_credentials(nla);
- nla_send(nla);
- nla_buffer_free(nla);
+ if (nla->status != SEC_E_OK)
+ {
+ WLog_ERR(TAG, "nla_encrypt_ts_credentials status: 0x%08X", nla->status);
+ return -1;
+ }
- /* Free resources */
- nla->table->FreeCredentialsHandle(&nla->credentials);
- nla->table->FreeContextBuffer(nla->pPackageInfo);
+ 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);
+ }
return 1;
}
* @param credssp
*/
-int nla_ntlm_server_init(rdpNla* nla)
+int nla_server_init(rdpNla* nla)
{
rdpTls* tls = nla->transport->tls;
int nla_server_authenticate(rdpNla* nla)
{
- if (nla_ntlm_server_init(nla) < 1)
+ if (nla_server_init(nla) < 1)
return -1;
while (TRUE)
Stream_Free(s, TRUE);
}
-/**
- * Receive CredSSP message.
- * @param credssp
- * @return
- */
-
-int nla_recv(rdpNla* nla)
+int nla_recv_ts_request(rdpNla* nla, wStream* s)
{
- wStream* s;
int length;
- int status;
UINT32 version;
- s = Stream_New(NULL, 4096);
-
- status = transport_read_pdu(nla->transport, s);
-
- if (status < 0)
- {
- WLog_ERR(TAG, "nla_recv() error: %d", status);
- Stream_Free(s, TRUE);
- return -1;
- }
-
/* TSRequest */
if (!ber_read_sequence_tag(s, &length) ||
!ber_read_contextual_tag(s, 0, &length, TRUE) ||
nla->pubKeyAuth.cbBuffer = length;
}
+ return 1;
+}
+
+int nla_recv(rdpNla* nla)
+{
+ wStream* s;
+ int status;
+
+ s = Stream_New(NULL, 4096);
+
+ status = transport_read_pdu(nla->transport, s);
+
+ if (status < 0)
+ {
+ WLog_ERR(TAG, "nla_recv() error: %d", status);
+ Stream_Free(s, TRUE);
+ return -1;
+ }
+
+ if (nla_recv_ts_request(nla, s) < 1)
+ return -1;
+
Stream_Free(s, TRUE);
return 1;
}
#include "transport.h"
+enum _NLA_STATE
+{
+ NLA_STATE_INITIAL,
+ NLA_STATE_NEGO_TOKEN,
+ NLA_STATE_PUB_KEY_AUTH,
+ NLA_STATE_AUTH_INFO,
+ NLA_STATE_FINAL
+};
+typedef enum _NLA_STATE NLA_STATE;
+
struct rdp_nla
{
BOOL server;
+ NLA_STATE state;
int sendSeqNum;
int recvSeqNum;
freerdp* instance;
rdp_set_error_info(rdp, ERRINFO_RPC_INITIATED_DISCONNECT);
}
- WLog_ERR(TAG, "DisconnectProviderUltimatum: reason: %d", reason);
+ WLog_ERR(TAG, "DisconnectProviderUltimatum: reason: %d", reason);
rdp->disconnect = TRUE;
EventArgsInit(&e, "freerdp");
if (Stream_GetRemainingLength(s) < (size_t) SrcSize)
{
- WLog_ERR(TAG, "bulk_decompress: not enough bytes for compressedLength %d", compressedLength);
+ WLog_ERR(TAG, "bulk_decompress: not enough bytes for compressedLength %d", compressedLength);
return -1;
}
}
else
{
- WLog_ERR(TAG, "bulk_decompress() failed");
+ WLog_ERR(TAG, "bulk_decompress() failed");
return -1;
}
if (!security_fips_decrypt(Stream_Pointer(s), length, rdp))
{
- WLog_ERR(TAG, "FATAL: cannot decrypt");
+ WLog_ERR(TAG, "FATAL: cannot decrypt");
return FALSE; /* TODO */
}
if (!security_fips_check_signature(Stream_Pointer(s), length - pad, sig, rdp))
{
- WLog_ERR(TAG, "FATAL: invalid packet signature");
+ WLog_ERR(TAG, "FATAL: invalid packet signature");
return FALSE; /* TODO */
}
if (memcmp(wmac, cmac, sizeof(wmac)) != 0)
{
- WLog_ERR(TAG, "WARNING: invalid packet signature");
+ WLog_ERR(TAG, "WARNING: invalid packet signature");
/*
* Because Standard RDP Security is totally broken,
* and cannot protect against MITM, don't treat signature
if (!rdp_read_header(rdp, s, &length, &channelId))
{
- WLog_ERR(TAG, "Incorrect RDP header.");
+ WLog_ERR(TAG, "Incorrect RDP header.");
return -1;
}
{
if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
{
- WLog_ERR(TAG, "rdp_decrypt failed");
+ WLog_ERR(TAG, "rdp_decrypt failed");
return -1;
}
}
case PDU_TYPE_DATA:
if (rdp_recv_data_pdu(rdp, s) < 0)
{
- WLog_ERR(TAG, "rdp_recv_data_pdu failed");
+ WLog_ERR(TAG, "rdp_recv_data_pdu failed");
return -1;
}
break;
break;
default:
- WLog_ERR(TAG, "incorrect PDU type: 0x%04X", pduType);
+ WLog_ERR(TAG, "incorrect PDU type: 0x%04X", pduType);
break;
}
if ((length == 0) || (length > Stream_GetRemainingLength(s)))
{
- WLog_ERR(TAG, "incorrect FastPath PDU header length %d", length);
+ WLog_ERR(TAG, "incorrect FastPath PDU header length %d", length);
return -1;
}
return rdp_recv_fastpath_pdu(rdp, s);
}
-static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
+int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra)
{
int status = 0;
rdpRdp* rdp = (rdpRdp*) extra;
* enters the active state, an auto-detect PDU can be received
* on the MCS message channel.
*/
- if ((rdp->state > CONNECTION_STATE_MCS_CHANNEL_JOIN) &&
- (rdp->state < CONNECTION_STATE_ACTIVE))
+ if ((rdp->state > CONNECTION_STATE_MCS_CHANNEL_JOIN) && (rdp->state < CONNECTION_STATE_ACTIVE))
{
if (rdp_client_connect_auto_detect(rdp, s))
return 0;
switch (rdp->state)
{
- case CONNECTION_STATE_NEGO:
- if (!rdp_client_connect_mcs_connect_response(rdp, s))
- status = -1;
+ case CONNECTION_STATE_MCS_CONNECT:
+ if (!mcs_recv_connect_response(rdp->mcs, s))
+ {
+ WLog_ERR(TAG, "mcs_recv_connect_response failure");
+ return -1;
+ }
+
+ if (!mcs_send_erect_domain_request(rdp->mcs))
+ {
+ WLog_ERR(TAG, "mcs_send_erect_domain_request failure");
+ return -1;
+ }
+
+ if (!mcs_send_attach_user_request(rdp->mcs))
+ {
+ WLog_ERR(TAG, "mcs_send_attach_user_request failure");
+ return -1;
+ }
+
+ rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER);
break;
case CONNECTION_STATE_MCS_ATTACH_USER:
- if (!rdp_client_connect_mcs_attach_user_confirm(rdp, s))
- status = -1;
+ if (!mcs_recv_attach_user_confirm(rdp->mcs, s))
+ {
+ WLog_ERR(TAG, "mcs_recv_attach_user_confirm failure");
+ return -1;
+ }
+
+ if (!mcs_send_channel_join_request(rdp->mcs, rdp->mcs->userId))
+ {
+ WLog_ERR(TAG, "mcs_send_channel_join_request failure");
+ return -1;
+ }
+
+ rdp_client_transition_to_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN);
break;
case CONNECTION_STATE_MCS_CHANNEL_JOIN:
break;
default:
- WLog_ERR(TAG, "Invalid state %d", rdp->state);
+ WLog_ERR(TAG, "Invalid state %d", rdp->state);
status = -1;
break;
}
return status;
}
-/**
- * Set non-blocking mode information.
- * @param rdp RDP module
- * @param blocking blocking mode
- */
-void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking)
-{
- rdp->transport->ReceiveCallback = rdp_recv_callback;
- rdp->transport->ReceiveExtra = rdp;
- transport_set_blocking_mode(rdp->transport, blocking);
-}
-
int rdp_check_fds(rdpRdp* rdp)
{
int status;
void rdp_read_flow_control_pdu(wStream* s, UINT16* type);
-void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking);
+int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra);
+
int rdp_check_fds(rdpRdp* rdp);
rdpRdp* rdp_new(rdpContext* context);
/* Make sure there is enough space for the longest header within the stream */
Stream_EnsureCapacity(s, 4);
- /* Make sure at least two bytes are read for futher processing */
+ /* Make sure at least two bytes are read for further processing */
if (position < 2 && (status = transport_read_layer_bytes(transport, s, 2 - position)) != 1)
{
/* No data available at the moment */