CredSSP with early user auth (nla_ext) support

This commit is contained in:
Hugues LEFEBVRE 2023-06-23 00:49:27 +02:00 committed by akallabeth
parent 535faeb879
commit b67afecf0f
6 changed files with 137 additions and 56 deletions

View File

@ -318,7 +318,11 @@ static BOOL nego_try_connect(rdpNego* nego)
break;
case PROTOCOL_HYBRID:
WLog_DBG(TAG, "nego_security_connect with PROTOCOL_HYBRID");
nego->SecurityConnected = transport_connect_nla(nego->transport);
nego->SecurityConnected = transport_connect_nla(nego->transport, FALSE);
break;
case PROTOCOL_HYBRID_EX:
WLog_DBG(TAG, "nego_security_connect with PROTOCOL_HYBRID_EX");
nego->SecurityConnected = transport_connect_nla(nego->transport, TRUE);
break;
case PROTOCOL_SSL:
WLog_DBG(TAG, "nego_security_connect with PROTOCOL_SSL");

View File

@ -54,6 +54,12 @@
#define NLA_AUTH_PKG NEGO_SSP_NAME
typedef enum
{
AUTHZ_SUCCESS = 0x00000000,
AUTHZ_ACCESS_DENIED = 0x00000005,
} AUTHZ_RESULT;
/**
* TSRequest ::= SEQUENCE {
* version [0] INTEGER,
@ -127,6 +133,7 @@ struct rdp_nla
char* pkinitArgs;
SmartcardCertInfo* smartcardCert;
BYTE certSha1[20];
BOOL earlyUserAuth;
};
static BOOL nla_send(rdpNla* nla);
@ -138,6 +145,13 @@ static BOOL nla_decrypt_public_key_hash(rdpNla* nla);
static BOOL nla_encrypt_ts_credentials(rdpNla* nla);
static BOOL nla_decrypt_ts_credentials(rdpNla* nla);
void nla_set_early_user_auth(rdpNla* nla, BOOL earlyUserAuth)
{
WINPR_ASSERT(nla);
WLog_DBG(TAG, "Early User Auth active: %s", nla->earlyUserAuth ? "true" : "false");
nla->earlyUserAuth = earlyUserAuth;
}
static void nla_buffer_free(rdpNla* nla)
{
WINPR_ASSERT(nla);
@ -551,6 +565,23 @@ static int nla_client_recv_pub_key_auth(rdpNla* nla)
if (!nla_send(nla))
return -1;
if (nla->earlyUserAuth)
{
transport_set_early_user_auth_mode(nla->transport, TRUE);
nla_set_state(nla, NLA_STATE_EARLY_USER_AUTH);
}
else
nla_set_state(nla, NLA_STATE_AUTH_INFO);
return 1;
}
static int nla_client_recv_early_user_auth(rdpNla* nla)
{
BOOL rc = FALSE;
WINPR_ASSERT(nla);
transport_set_early_user_auth_mode(nla->transport, FALSE);
nla_set_state(nla, NLA_STATE_AUTH_INFO);
return 1;
}
@ -567,6 +598,9 @@ static int nla_client_recv(rdpNla* nla)
case NLA_STATE_PUB_KEY_AUTH:
return nla_client_recv_pub_key_auth(nla);
case NLA_STATE_EARLY_USER_AUTH:
return nla_client_recv_early_user_auth(nla);
case NLA_STATE_FINAL:
default:
WLog_ERR(TAG, "NLA in invalid client receive state %s",
@ -1552,63 +1586,80 @@ int nla_recv_pdu(rdpNla* nla, wStream* s)
WINPR_ASSERT(nla);
WINPR_ASSERT(s);
if (nla_decode_ts_request(nla, s) < 1)
return -1;
if (nla->errorCode)
if (nla_get_state(nla) == NLA_STATE_EARLY_USER_AUTH)
{
UINT32 code;
switch (nla->errorCode)
Stream_Read_UINT32(s, code);
if (code != AUTHZ_SUCCESS)
{
case STATUS_PASSWORD_MUST_CHANGE:
code = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
break;
case STATUS_PASSWORD_EXPIRED:
code = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
break;
case STATUS_ACCOUNT_DISABLED:
code = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
break;
case STATUS_LOGON_FAILURE:
code = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
break;
case STATUS_WRONG_PASSWORD:
code = FREERDP_ERROR_CONNECT_WRONG_PASSWORD;
break;
case STATUS_ACCESS_DENIED:
code = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
break;
case STATUS_ACCOUNT_RESTRICTION:
code = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
break;
case STATUS_ACCOUNT_LOCKED_OUT:
code = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
break;
case STATUS_ACCOUNT_EXPIRED:
code = FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED;
break;
case STATUS_LOGON_TYPE_NOT_GRANTED:
code = FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED;
break;
default:
WLog_ERR(TAG, "SPNEGO failed with NTSTATUS: 0x%08" PRIX32 "", nla->errorCode);
code = FREERDP_ERROR_AUTHENTICATION_FAILED;
break;
WLog_DBG(TAG, "Early User Auth active: FAILURE code 0x%08" PRIX32 "", code);
code = FREERDP_ERROR_AUTHENTICATION_FAILED;
freerdp_set_last_error_log(nla->rdpcontext, code);
return -1;
}
else
WLog_DBG(TAG, "Early User Auth active: SUCCESS");
}
else
{
if (nla_decode_ts_request(nla, s) < 1)
return -1;
freerdp_set_last_error_log(nla->rdpcontext, code);
return -1;
if (nla->errorCode)
{
UINT32 code;
switch (nla->errorCode)
{
case STATUS_PASSWORD_MUST_CHANGE:
code = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
break;
case STATUS_PASSWORD_EXPIRED:
code = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
break;
case STATUS_ACCOUNT_DISABLED:
code = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
break;
case STATUS_LOGON_FAILURE:
code = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
break;
case STATUS_WRONG_PASSWORD:
code = FREERDP_ERROR_CONNECT_WRONG_PASSWORD;
break;
case STATUS_ACCESS_DENIED:
code = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
break;
case STATUS_ACCOUNT_RESTRICTION:
code = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
break;
case STATUS_ACCOUNT_LOCKED_OUT:
code = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
break;
case STATUS_ACCOUNT_EXPIRED:
code = FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED;
break;
case STATUS_LOGON_TYPE_NOT_GRANTED:
code = FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED;
break;
default:
WLog_ERR(TAG, "SPNEGO failed with NTSTATUS: 0x%08" PRIX32 "", nla->errorCode);
code = FREERDP_ERROR_AUTHENTICATION_FAILED;
break;
}
freerdp_set_last_error_log(nla->rdpcontext, code);
return -1;
}
}
return nla_client_recv(nla);
@ -1658,6 +1709,7 @@ rdpNla* nla_new(rdpContext* context, rdpTransport* transport)
nla->sendSeqNum = 0;
nla->recvSeqNum = 0;
nla->version = 6;
nla->earlyUserAuth = FALSE;
nla->identity = calloc(1, sizeof(SEC_WINNT_AUTH_IDENTITY));
if (!nla->identity)
@ -1761,6 +1813,8 @@ const char* nla_get_state_str(NLA_STATE state)
return "NLA_STATE_AUTH_INFO";
case NLA_STATE_POST_NEGO:
return "NLA_STATE_POST_NEGO";
case NLA_STATE_EARLY_USER_AUTH:
return "NLA_STATE_EARLY_USER_AUTH";
case NLA_STATE_FINAL:
return "NLA_STATE_FINAL";
default:

View File

@ -40,6 +40,7 @@ typedef enum
NLA_STATE_INITIAL,
NLA_STATE_NEGO_TOKEN,
NLA_STATE_PUB_KEY_AUTH,
NLA_STATE_EARLY_USER_AUTH,
NLA_STATE_AUTH_INFO,
NLA_STATE_POST_NEGO,
NLA_STATE_FINAL
@ -70,5 +71,6 @@ FREERDP_LOCAL BOOL nla_revert_to_self(rdpNla* nla);
FREERDP_LOCAL rdpNla* nla_new(rdpContext* context, rdpTransport* transport);
FREERDP_LOCAL void nla_free(rdpNla* nla);
FREERDP_LOCAL void nla_set_early_user_auth(rdpNla* nla, BOOL earlyUserAuth);
#endif /* FREERDP_LIB_CORE_NLA_H */

View File

@ -90,6 +90,7 @@ struct rdp_transport
rdpTransportIo io;
HANDLE ioEvent;
BOOL useIoEvent;
BOOL earlyUserAuth;
};
static void transport_ssl_cb(SSL* ssl, int where, int ret)
@ -323,7 +324,7 @@ static BOOL transport_default_connect_tls(rdpTransport* transport)
return TRUE;
}
BOOL transport_connect_nla(rdpTransport* transport)
BOOL transport_connect_nla(rdpTransport* transport, BOOL earlyUserAuth)
{
rdpContext* context = NULL;
rdpSettings* settings = NULL;
@ -352,6 +353,8 @@ BOOL transport_connect_nla(rdpTransport* transport)
if (!rdp->nla)
return FALSE;
nla_set_early_user_auth(rdp->nla, earlyUserAuth);
transport_set_nla_mode(transport, TRUE);
if (settings->AuthenticationServiceClass)
@ -1028,6 +1031,14 @@ static int transport_default_read_pdu(rdpTransport* transport, wStream* s)
Stream_Write_UINT8(s, c);
} while (c != '\0');
}
else if (transport->earlyUserAuth)
{
if (!Stream_EnsureCapacity(s, 4))
return -1;
const int rc = transport_read_layer_bytes(transport, s, 4);
if (rc != 1)
return rc;
}
else
{
/* Read in pdu length */
@ -1473,6 +1484,7 @@ static BOOL transport_default_disconnect(rdpTransport* transport)
transport->frontBio = NULL;
transport->layer = TRANSPORT_LAYER_TCP;
transport->earlyUserAuth = FALSE;
return status;
}
@ -1723,3 +1735,10 @@ BOOL transport_io_callback_set_event(rdpTransport* transport, BOOL set)
return ResetEvent(transport->ioEvent);
return SetEvent(transport->ioEvent);
}
void transport_set_early_user_auth_mode(rdpTransport* transport, BOOL EUAMode)
{
WINPR_ASSERT(transport);
transport->earlyUserAuth = EUAMode;
WLog_Print(transport->log, WLOG_DEBUG, "Early User Auth Mode: %s", EUAMode ? "on" : "off");
}

View File

@ -60,7 +60,7 @@ FREERDP_LOCAL BOOL transport_attach(rdpTransport* transport, int sockfd);
FREERDP_LOCAL BOOL transport_disconnect(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_connect_rdp(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_connect_tls(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_connect_nla(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_connect_nla(rdpTransport* transport, BOOL earlyUserAuth);
FREERDP_LOCAL BOOL transport_connect_rdstls(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_connect_aad(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_accept_rdp(rdpTransport* transport);
@ -129,4 +129,6 @@ FREERDP_LOCAL int transport_tcp_connect(rdpTransport* transport, const char* hos
FREERDP_LOCAL rdpTransport* transport_new(rdpContext* context);
FREERDP_LOCAL void transport_free(rdpTransport* transport);
FREERDP_LOCAL void transport_set_early_user_auth_mode(rdpTransport* transport, BOOL EUAMode);
#endif /* FREERDP_LIB_CORE_TRANSPORT_H */

View File

@ -54,7 +54,7 @@ static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* con
{
unwind_info_t* info = &ctx->info[ctx->pos++];
info->pc = _Unwind_GetIP(context);
info->langSpecificData = _Unwind_GetLanguageSpecificData(context);
info->langSpecificData = (void*)_Unwind_GetLanguageSpecificData(context);
}
return _URC_NO_REASON;