diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 406e535c5..989eb206b 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -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"); diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 938a8434e..198e51c41 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -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: diff --git a/libfreerdp/core/nla.h b/libfreerdp/core/nla.h index 527f749b9..fd5fb2f70 100644 --- a/libfreerdp/core/nla.h +++ b/libfreerdp/core/nla.h @@ -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 */ diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 43de0ad74..a709b5391 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -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"); +} diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index 75813a0f9..0e5b82646 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -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 */ diff --git a/winpr/libwinpr/utils/unwind/debug.c b/winpr/libwinpr/utils/unwind/debug.c index 8b49b22b9..dbc85f7b2 100644 --- a/winpr/libwinpr/utils/unwind/debug.c +++ b/winpr/libwinpr/utils/unwind/debug.c @@ -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;