20#include <freerdp/config.h>
24#include <freerdp/log.h>
25#include <freerdp/error.h>
26#include <freerdp/settings.h>
28#include <winpr/assert.h>
29#include <winpr/stream.h>
30#include <winpr/wlog.h>
36#define RDSTLS_VERSION_1 0x01u
37#define RDSTLS_VERSION_2 0x02u
39#define RDSTLS_TYPE_CAPABILITIES 0x01
40#define RDSTLS_TYPE_AUTHREQ 0x02
41#define RDSTLS_TYPE_AUTHRSP 0x04
43#define RDSTLS_DATA_CAPABILITIES 0x01
44#define RDSTLS_DATA_PASSWORD_CREDS 0x01
45#define RDSTLS_DATA_AUTORECONNECT_COOKIE 0x02
46#define RDSTLS_DATA_FEDAUTH_TOKEN 0x03
47#define RDSTLS_DATA_RESULT_CODE 0x01
52 RDSTLS_STATE_CAPABILITIES,
53 RDSTLS_STATE_AUTH_REQ,
54 RDSTLS_STATE_AUTH_RSP,
61 RDSTLS_RESULT_SUCCESS = 0x00000000,
62 RDSTLS_RESULT_ACCESS_DENIED = 0x00000005,
63 RDSTLS_RESULT_LOGON_FAILURE = 0x0000052e,
64 RDSTLS_RESULT_INVALID_LOGON_HOURS = 0x00000530,
65 RDSTLS_RESULT_PASSWORD_EXPIRED = 0x00000532,
66 RDSTLS_RESULT_ACCOUNT_DISABLED = 0x00000533,
67 RDSTLS_RESULT_PASSWORD_MUST_CHANGE = 0x00000773,
68 RDSTLS_RESULT_ACCOUNT_LOCKED_OUT = 0x00000775
76 rdpTransport* transport;
78 RDSTLS_RESULT_CODE resultCode;
80 uint16_t supportedVersions;
83static const uint16_t RDSTLS_VERSION_MASK = RDSTLS_VERSION_1 | RDSTLS_VERSION_2;
86static const char* rdstls_result_code_str(UINT32 resultCode)
90 case RDSTLS_RESULT_SUCCESS:
91 return "RDSTLS_RESULT_SUCCESS";
92 case RDSTLS_RESULT_ACCESS_DENIED:
93 return "RDSTLS_RESULT_ACCESS_DENIED";
94 case RDSTLS_RESULT_LOGON_FAILURE:
95 return "RDSTLS_RESULT_LOGON_FAILURE";
96 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
97 return "RDSTLS_RESULT_INVALID_LOGON_HOURS";
98 case RDSTLS_RESULT_PASSWORD_EXPIRED:
99 return "RDSTLS_RESULT_PASSWORD_EXPIRED";
100 case RDSTLS_RESULT_ACCOUNT_DISABLED:
101 return "RDSTLS_RESULT_ACCOUNT_DISABLED";
102 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
103 return "RDSTLS_RESULT_PASSWORD_MUST_CHANGE";
104 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
105 return "RDSTLS_RESULT_ACCOUNT_LOCKED_OUT";
107 return "RDSTLS_RESULT_UNKNOWN";
111#define rdstls_required_role_is_server(rdstls, isServer) \
112 rdstls_required_role_is_server_((rdstls), (isServer), __FILE__, __func__, __LINE__)
115static BOOL rdstls_required_role_is_server_(
const rdpRdstls* rdstls, BOOL isServer,
116 const char* file,
const char* fkt,
size_t line)
118 WINPR_ASSERT(rdstls);
119 const BOOL rc = rdstls->server == isServer;
122 const DWORD level = WLOG_ERROR;
123 if (WLog_IsLevelActive(rdstls->log, level))
124 WLog_PrintTextMessage(rdstls->log, level, line, file, fkt,
125 "Message not allowed in current role '%s'",
126 rdstls->server ?
"server" :
"client");
139rdpRdstls* rdstls_new(rdpContext* context, rdpTransport* transport)
141 WINPR_ASSERT(context);
142 WINPR_ASSERT(transport);
144 rdpSettings* settings = context->settings;
145 WINPR_ASSERT(settings);
147 rdpRdstls* rdstls = (rdpRdstls*)calloc(1,
sizeof(rdpRdstls));
151 rdstls->log = WLog_Get(FREERDP_TAG(
"core.rdstls"));
152 rdstls->supportedVersions = RDSTLS_VERSION_MASK;
153 rdstls->context = context;
154 rdstls->transport = transport;
155 rdstls->server = settings->ServerMode;
157 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
158 rdstls->state = RDSTLS_STATE_INITIAL;
168void rdstls_free(rdpRdstls* rdstls)
174static const char* rdstls_get_state_str(RDSTLS_STATE state)
178 case RDSTLS_STATE_INITIAL:
179 return "RDSTLS_STATE_INITIAL";
180 case RDSTLS_STATE_CAPABILITIES:
181 return "RDSTLS_STATE_CAPABILITIES";
182 case RDSTLS_STATE_AUTH_REQ:
183 return "RDSTLS_STATE_AUTH_REQ";
184 case RDSTLS_STATE_AUTH_RSP:
185 return "RDSTLS_STATE_AUTH_RSP";
186 case RDSTLS_STATE_FINAL:
187 return "RDSTLS_STATE_FINAL";
194static RDSTLS_STATE rdstls_get_state(rdpRdstls* rdstls)
196 WINPR_ASSERT(rdstls);
197 return rdstls->state;
201static BOOL check_transition(wLog* log, RDSTLS_STATE current, RDSTLS_STATE expected,
202 RDSTLS_STATE requested)
204 if (requested != expected)
206 WLog_Print(log, WLOG_ERROR,
207 "Unexpected rdstls state transition from %s [%u] to %s [%u], expected %s [%u]",
208 rdstls_get_state_str(current), current, rdstls_get_state_str(requested),
209 requested, rdstls_get_state_str(expected), expected);
216static BOOL rdstls_set_state(rdpRdstls* rdstls, RDSTLS_STATE state)
219 WINPR_ASSERT(rdstls);
221 WLog_Print(rdstls->log, WLOG_DEBUG,
"-- %s\t--> %s", rdstls_get_state_str(rdstls->state),
222 rdstls_get_state_str(state));
224 switch (rdstls->state)
226 case RDSTLS_STATE_INITIAL:
227 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_CAPABILITIES, state);
229 case RDSTLS_STATE_CAPABILITIES:
230 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_AUTH_REQ, state);
232 case RDSTLS_STATE_AUTH_REQ:
233 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_AUTH_RSP, state);
235 case RDSTLS_STATE_AUTH_RSP:
236 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_FINAL, state);
238 case RDSTLS_STATE_FINAL:
239 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_CAPABILITIES, state);
242 WLog_Print(rdstls->log, WLOG_ERROR,
243 "Invalid rdstls state %s [%u], requested transition to %s [%u]",
244 rdstls_get_state_str(rdstls->state), rdstls->state,
245 rdstls_get_state_str(state), state);
249 rdstls->state = state;
254#define rdstls_check_state_requirements(rdstls, expected) \
255 rdstls_check_state_requirements_((rdstls), (expected), __FILE__, __func__, __LINE__)
258static BOOL rdstls_check_state_requirements_(rdpRdstls* rdstls, RDSTLS_STATE expected,
259 const char* file,
const char* fkt,
size_t line)
261 const RDSTLS_STATE current = rdstls_get_state(rdstls);
262 if (current == expected)
265 WINPR_ASSERT(rdstls);
267 const DWORD log_level = WLOG_ERROR;
268 if (WLog_IsLevelActive(rdstls->log, log_level))
269 WLog_PrintTextMessage(rdstls->log, log_level, line, file, fkt,
270 "Unexpected rdstls state %s [%u], expected %s [%u]",
271 rdstls_get_state_str(current), current,
272 rdstls_get_state_str(expected), expected);
278static BOOL rdstls_write_capabilities(WINPR_ATTR_UNUSED rdpRdstls* rdstls,
wStream* s)
280 if (!Stream_EnsureRemainingCapacity(s, 8))
283 Stream_Write_UINT16(s, RDSTLS_VERSION_1);
284 Stream_Write_UINT16(s, RDSTLS_TYPE_CAPABILITIES);
285 Stream_Write_UINT16(s, RDSTLS_DATA_CAPABILITIES);
286 Stream_Write_UINT16(s, rdstls->supportedVersions);
292static SSIZE_T rdstls_write_string(
wStream* s,
const char* str)
294 const size_t pos = Stream_GetPosition(s);
296 if (!Stream_EnsureRemainingCapacity(s, 2))
302 Stream_Write_UINT16(s, 2);
303 if (!Stream_EnsureRemainingCapacity(s, 2))
306 Stream_Write_UINT16(s, 0);
307 return (SSIZE_T)(Stream_GetPosition(s) - pos);
310 const SSIZE_T devNameWLen = ConvertUtf8ToWChar(str,
nullptr, 0);
313 const size_t length = WINPR_ASSERTING_INT_CAST(
size_t, devNameWLen) + 1;
314 const size_t slen = strlen(str);
316 Stream_Write_UINT16(s, (UINT16)length *
sizeof(WCHAR));
318 if (!Stream_EnsureRemainingCapacity(s, length *
sizeof(WCHAR)))
321 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, slen, TRUE) < 0)
324 return (SSIZE_T)(Stream_GetPosition(s) - pos);
328static BOOL rdstls_write_data(
wStream* s, UINT32 length,
const BYTE* data)
330 WINPR_ASSERT(data || (length == 0));
332 if (!Stream_EnsureRemainingCapacity(s, 2) || (length > UINT16_MAX))
335 Stream_Write_UINT16(s, (UINT16)length);
337 if (!Stream_EnsureRemainingCapacity(s, length))
340 Stream_Write(s, data, length);
348 WINPR_ASSERT(cookie);
352 if (!Stream_EnsureRemainingCapacity(s, 2))
355 Stream_Write_UINT16(s, length);
357 if (!Stream_EnsureRemainingCapacity(s, length))
360 Stream_Write_UINT32(s, cookie->cbLen);
361 Stream_Write_UINT32(s, cookie->version);
362 Stream_Write_UINT32(s, cookie->logonId);
363 Stream_Write(s, cookie->arcRandomBits,
sizeof(cookie->arcRandomBits));
370 WINPR_ASSERT(cookie);
374 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length + 2ull))
377 const uint16_t len = Stream_Get_UINT16(s);
380 WLog_Print(log, WLOG_ERROR,
381 "RDSTLS Cookie: Unexpected length %" PRIu16
", expected %" PRIu16, len, length);
385 cookie->cbLen = Stream_Get_UINT32(s);
386 cookie->version = Stream_Get_UINT32(s);
387 cookie->logonId = Stream_Get_UINT32(s);
388 Stream_Read(s, cookie->arcRandomBits,
sizeof(cookie->arcRandomBits));
393static BOOL rdstls_write_authentication_request_with_password(rdpRdstls* rdstls,
wStream* s)
395 WINPR_ASSERT(rdstls);
396 WINPR_ASSERT(rdstls->context);
398 if (!rdstls_required_role_is_server(rdstls, FALSE))
400 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
403 WLog_Print(rdstls->log, WLOG_DEBUG,
"Writing RDSTLS password authentication message");
405 rdpSettings* settings = rdstls->context->settings;
406 WINPR_ASSERT(settings);
408 if (!Stream_EnsureRemainingCapacity(s, 4))
411 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
412 Stream_Write_UINT16(s, RDSTLS_DATA_PASSWORD_CREDS);
414 if (!rdstls_write_data(s, settings->RedirectionGuidLength, settings->RedirectionGuid))
417 if (rdstls_write_string(s, settings->Username) < 0)
420 if (rdstls_write_string(s, settings->Domain) < 0)
423 if (!rdstls_write_data(s, settings->RedirectionPasswordLength, settings->RedirectionPassword))
430static BOOL rdstls_write_authentication_request_with_cookie(WINPR_ATTR_UNUSED rdpRdstls* rdstls,
433 WINPR_ASSERT(rdstls);
434 WINPR_ASSERT(rdstls->context);
436 WLog_Print(rdstls->log, WLOG_DEBUG,
"Writing RDSTLS cookie authentication message");
438 if (!rdstls_required_role_is_server(rdstls, FALSE))
440 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
443 rdpSettings* settings = rdstls->context->settings;
444 WINPR_ASSERT(settings);
446 if (!Stream_EnsureRemainingCapacity(s, 8))
449 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
450 Stream_Write_UINT16(s, RDSTLS_DATA_AUTORECONNECT_COOKIE);
451 Stream_Write_UINT32(s, settings->RedirectedSessionId);
453 return (rdstls_write_cookie(s, settings->ServerAutoReconnectCookie));
463static void rdstls_check_fedauth_vmid(rdpRdstls* rdstls,
const char* token,
const char* selectedVm)
465 WINPR_ASSERT(rdstls);
468 if (!selectedVm || !*selectedVm)
471 const char* vmidField = strstr(token,
"VMID=");
476 const size_t vmLen = strlen(selectedVm);
477 const BOOL matches = (_strnicmp(vmidField, selectedVm, vmLen) == 0) &&
478 (vmidField[vmLen] ==
'\0' || vmidField[vmLen] ==
'&');
481 WLog_Print(rdstls->log, WLOG_WARN,
482 "endpoint FedAuth token is issued for a different virtual machine "
483 "than the one selected for connection");
488static BOOL rdstls_write_authentication_request_with_fedauth_token(rdpRdstls* rdstls,
wStream* s)
490 WINPR_ASSERT(rdstls);
491 WINPR_ASSERT(rdstls->context);
493 WLog_Print(rdstls->log, WLOG_DEBUG,
"Writing RDSTLS FedAuth token authentication message");
495 if (!rdstls_required_role_is_server(rdstls, FALSE))
497 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
500 const rdpSettings* settings = rdstls->context->settings;
501 WINPR_ASSERT(settings);
504 if (!token || !*token)
506 WLog_Print(rdstls->log, WLOG_ERROR,
"EndpointFedAuthToken not set");
510 rdstls_check_fedauth_vmid(rdstls, token,
513 const size_t utf8Length = strlen(token);
516 if (utf8Length >= UINT16_MAX /
sizeof(WCHAR))
518 WLog_Print(rdstls->log, WLOG_ERROR,
519 "EndpointFedAuthToken length %" PRIuz
" exceeds RDSTLS wire limit", utf8Length);
523 const SSIZE_T wideLength = ConvertUtf8NToWChar(token, utf8Length,
nullptr, 0);
526 const size_t wideLengthZero = WINPR_ASSERTING_INT_CAST(
size_t, wideLength);
527 const size_t wideBytes = (wideLengthZero + 1ull) *
sizeof(WCHAR);
529 if (!Stream_EnsureRemainingCapacity(s, 6 + wideBytes))
532 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
533 Stream_Write_UINT16(s, RDSTLS_DATA_FEDAUTH_TOKEN);
534 Stream_Write_UINT16(s, (UINT16)wideBytes);
536 return Stream_Write_UTF16_String_From_UTF8(s, wideLengthZero, token, utf8Length, TRUE) >= 0;
540static BOOL rdstls_write_authentication_response(rdpRdstls* rdstls,
wStream* s)
542 WINPR_ASSERT(rdstls);
544 if (!rdstls_required_role_is_server(rdstls, TRUE))
546 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
548 if (!Stream_EnsureRemainingCapacity(s, 8))
551 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHRSP);
552 Stream_Write_UINT16(s, RDSTLS_DATA_RESULT_CODE);
553 Stream_Write_UINT32(s, rdstls->resultCode);
558#define rdstls_version_required(log, expected, actual) \
559 rdstls_version_required_((log), (expected), (actual), __FILE__, __func__, __LINE__)
561static BOOL rdstls_version_required_(wLog* log, uint16_t expected, uint16_t actual,
562 const char* file,
const char* fkt,
size_t line)
564 if (actual < expected)
566 const DWORD level = WLOG_ERROR;
567 if (WLog_IsLevelActive(log, level))
569 WLog_PrintTextMessage(log, WLOG_ERROR, line, file, fkt,
570 "version=0x%04" PRIx16
", expected at least 0x%04" PRIx16, actual,
578#define rdstls_are_some_versions_supported(log, version, mask) \
579 rdstls_are_some_versions_supported_((log), (version), (mask), __FILE__, __func__, __LINE__)
581static BOOL rdstls_are_some_versions_supported_(wLog* log, uint16_t version, BOOL isMask,
582 const char* file,
const char* fkt,
size_t line)
587 for (
size_t x = 0; x < 16; x++)
589 const unsigned val = 1 << x;
590 if ((version & val) != 0)
595 WLog_PrintTextMessage(log, WLOG_ERROR, line, file, fkt,
596 "received invalid version mask=0x%04" PRIx16
597 ", expected { 0x%04" PRIx32
", 0x%04" PRIx32
"}",
598 version, RDSTLS_VERSION_1, RDSTLS_VERSION_2);
603 if ((version & RDSTLS_VERSION_MASK) == 0)
605 const DWORD level = WLOG_ERROR;
606 if (WLog_IsLevelActive(log, level))
608 WLog_PrintTextMessage(log, WLOG_ERROR, line, file, fkt,
609 "received invalid version mask=0x%04" PRIx16
610 ", expected { 0x%04" PRIx32
", 0x%04" PRIx32
"}",
611 version, RDSTLS_VERSION_1, RDSTLS_VERSION_2);
618#define rdstls_is_version_supported(rdstls, version) \
619 rdstls_is_version_supported_((rdstls), (version), __FILE__, __func__, __LINE__)
621static BOOL rdstls_is_version_supported_(rdpRdstls* rdstls, uint16_t version,
const char* file,
622 const char* fkt,
size_t line)
624 WINPR_ASSERT(rdstls);
626 if ((rdstls->supportedVersions & version) == 0)
628 const DWORD level = WLOG_ERROR;
629 if (WLog_IsLevelActive(rdstls->log, level))
631 WLog_PrintTextMessage(rdstls->log, WLOG_ERROR, line, file, fkt,
632 "received invalid version=0x%04" PRIx16
633 ", expected { 0x%04" PRIx32
", 0x%04" PRIx32
"}",
634 version, RDSTLS_VERSION_1, RDSTLS_VERSION_2);
642static BOOL rdstls_process_capabilities(rdpRdstls* rdstls,
wStream* s)
644 WINPR_ASSERT(rdstls);
645 if (!rdstls_required_role_is_server(rdstls, FALSE))
647 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
650 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
653 const UINT16 dataType = Stream_Get_UINT16(s);
654 if (dataType != RDSTLS_DATA_CAPABILITIES)
656 WLog_Print(rdstls->log, WLOG_ERROR,
657 "received invalid DataType=0x%04" PRIX16
", expected 0x%04" PRIX32, dataType,
658 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_CAPABILITIES));
662 const UINT16 supportedVersions = Stream_Get_UINT16(s);
663 if (!rdstls_are_some_versions_supported(rdstls->log, supportedVersions, TRUE))
665 rdstls->supportedVersions = supportedVersions & RDSTLS_VERSION_MASK;
671static BOOL rdstls_read_unicode_string(WINPR_ATTR_UNUSED wLog* log,
wStream* s,
char** str)
675 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
678 const UINT16 length = Stream_Get_UINT16(s);
680 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length))
686 Stream_Seek(s, length);
690 *str = Stream_Read_UTF16_String_As_UTF8(s, length /
sizeof(WCHAR),
nullptr);
691 return (*str) !=
nullptr;
695static BOOL rdstls_read_data(WINPR_ATTR_UNUSED wLog* log,
wStream* s, UINT16* pLength,
698 WINPR_ASSERT(pLength);
703 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
706 const UINT16 length = Stream_Get_UINT16(s);
708 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length))
713 Stream_Seek(s, length);
717 *pData = Stream_ConstPointer(s);
719 Stream_Seek(s, length);
724static BOOL rdstls_cmp_data(wLog* log,
const char* field,
const BYTE* serverData,
725 const UINT32 serverDataLength,
const BYTE* clientData,
726 const UINT16 clientDataLength)
728 if (serverDataLength > 0)
730 if (clientDataLength == 0)
732 WLog_Print(log, WLOG_ERROR,
"expected %s", field);
736 if (serverDataLength > UINT16_MAX || serverDataLength != clientDataLength ||
737 memcmp(serverData, clientData, serverDataLength) != 0)
739 WLog_Print(log, WLOG_ERROR,
"%s verification failed", field);
748static BOOL rdstls_cmp_str(wLog* log,
const char* field,
const char* serverStr,
749 const char* clientStr)
751 if (!utils_str_is_empty(serverStr))
753 if (utils_str_is_empty(clientStr))
755 WLog_Print(log, WLOG_ERROR,
"expected %s", field);
759 WINPR_ASSERT(serverStr);
760 WINPR_ASSERT(clientStr);
761 if (strcmp(serverStr, clientStr) != 0)
763 WLog_Print(log, WLOG_ERROR,
"%s verification failed", field);
772static BOOL rdstls_process_authentication_request_with_password(rdpRdstls* rdstls,
wStream* s,
775 WINPR_ASSERT(rdstls);
776 WINPR_ASSERT(rdstls->context);
778 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_1, version))
780 if (!rdstls_required_role_is_server(rdstls, TRUE))
782 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
787 const BYTE* clientRedirectionGuid =
nullptr;
788 UINT16 clientRedirectionGuidLength = 0;
789 char* clientPassword =
nullptr;
790 char* clientUsername =
nullptr;
791 char* clientDomain =
nullptr;
793 const rdpSettings* settings = rdstls->context->settings;
794 WINPR_ASSERT(settings);
796 if (!rdstls_read_data(rdstls->log, s, &clientRedirectionGuidLength, &clientRedirectionGuid))
799 if (!rdstls_read_unicode_string(rdstls->log, s, &clientUsername))
802 if (!rdstls_read_unicode_string(rdstls->log, s, &clientDomain))
805 if (!rdstls_read_unicode_string(rdstls->log, s, &clientPassword))
809 const BYTE* serverRedirectionGuid =
811 const UINT32 serverRedirectionGuidLength =
817 if (!rdstls_cmp_data(rdstls->log,
"RedirectionGuid", serverRedirectionGuid,
818 serverRedirectionGuidLength, clientRedirectionGuid,
819 clientRedirectionGuidLength))
820 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
821 else if (!rdstls_cmp_str(rdstls->log,
"UserName", serverUsername, clientUsername))
822 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
823 else if (!rdstls_cmp_str(rdstls->log,
"Domain", serverDomain, clientDomain))
824 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
825 else if (!rdstls_cmp_str(rdstls->log,
"Password", serverPassword, clientPassword))
826 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
828 rdstls->resultCode = RDSTLS_RESULT_SUCCESS;
836static BOOL rdstls_process_authentication_request_with_cookie(rdpRdstls* rdstls,
wStream* s,
839 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_1, version))
842 if (!rdstls_required_role_is_server(rdstls, TRUE))
844 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
847 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
850 const rdpSettings* settings = rdstls->context->settings;
851 WINPR_ASSERT(settings);
853 const uint32_t
id = Stream_Get_UINT32(s);
857 WLog_Print(rdstls->log, WLOG_ERROR,
858 "RDSTLS Cookie SessionId does not match RedirectedSessionId. Deny access.");
863 if (!rdstls_read_cookie(rdstls->log, s, &cookie))
870 WLog_Print(rdstls->log, WLOG_ERROR,
"No RDSTLS Cookie provided by server. Deny access.");
876 WLog_Print(rdstls->log, WLOG_ERROR,
"RDSTLS Cookie does not match. Deny access.");
880 WLog_Print(rdstls->log, WLOG_DEBUG,
"RDSTLS Cookie matches. Grant access.");
881 rdstls->resultCode = RDSTLS_RESULT_SUCCESS;
886static BOOL rdstls_process_authentication_request_with_fedauth_token(rdpRdstls* rdstls,
wStream* s,
889 WINPR_ASSERT(rdstls);
891 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_2, version))
893 if (!rdstls_required_role_is_server(rdstls, TRUE))
895 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
897 if ((rdstls->supportedVersions & RDSTLS_VERSION_2) == 0)
899 WLog_Print(rdstls->log, WLOG_ERROR,
"FedAuth token only supported with RDSTLS_VERSION_2");
903 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 2))
905 const uint16_t wbytes = Stream_Get_UINT16(s);
908 WLog_Print(rdstls->log, WLOG_ERROR,
"Empty FedAuth token given by client. Deny access");
911 if ((wbytes %
sizeof(WCHAR)) != 0)
913 WLog_Print(rdstls->log, WLOG_ERROR,
914 "Invalid FedAuth token length %" PRIu16
"given by client. Must be even", wbytes);
917 const size_t wcharlen = wbytes /
sizeof(WCHAR);
918 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, wbytes))
921 const rdpSettings* settings = rdstls->context->settings;
922 WINPR_ASSERT(settings);
927 if (!token || (len == 0))
930 WLog_Print(rdstls->log, WLOG_ERROR,
931 "No FedAuth token provided by server to compare. Deny access");
937 WLog_Print(rdstls->log, WLOG_ERROR,
"FedAuth token length does not match. Deny access");
942 const int rc = memcmp(token, Stream_Pointer(s), len *
sizeof(WCHAR));
946 WLog_Print(rdstls->log, WLOG_ERROR,
"FedAuth token does not match. Deny access");
950 WLog_Print(rdstls->log, WLOG_INFO,
"FedAuth token does match. Grant access");
955static BOOL rdstls_process_authentication_request(rdpRdstls* rdstls,
wStream* s, uint16_t version)
957 if (!rdstls_required_role_is_server(rdstls, TRUE))
960 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
963 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 2))
966 const UINT16 dataType = Stream_Get_UINT16(s);
969 case RDSTLS_DATA_PASSWORD_CREDS:
970 if (!rdstls_process_authentication_request_with_password(rdstls, s, version))
973 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
974 if (!rdstls_process_authentication_request_with_cookie(rdstls, s, version))
977 case RDSTLS_DATA_FEDAUTH_TOKEN:
978 if (!rdstls_process_authentication_request_with_fedauth_token(rdstls, s, version))
982 WLog_Print(rdstls->log, WLOG_ERROR,
983 "received invalid DataType=0x%04" PRIX16
", expected 0x%04" PRIX32
985 dataType, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_PASSWORD_CREDS),
986 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_AUTORECONNECT_COOKIE));
994static BOOL rdstls_process_authentication_response(rdpRdstls* rdstls,
wStream* s)
996 if (!rdstls_required_role_is_server(rdstls, FALSE))
998 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
1001 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 6))
1004 const UINT16 dataType = Stream_Get_UINT16(s);
1005 if (dataType != RDSTLS_DATA_RESULT_CODE)
1007 WLog_Print(rdstls->log, WLOG_ERROR,
1008 "received invalid DataType=0x%04" PRIX16
", expected 0x%04" PRIX32, dataType,
1009 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_RESULT_CODE));
1013 const UINT32 resultCode = Stream_Get_UINT32(s);
1014 if (resultCode != RDSTLS_RESULT_SUCCESS)
1016 WLog_Print(rdstls->log, WLOG_ERROR,
"resultCode: %s [0x%08" PRIX32
"]",
1017 rdstls_result_code_str(resultCode), resultCode);
1019 UINT32 error = FREERDP_ERROR_CONNECT_UNDEFINED;
1022 case RDSTLS_RESULT_ACCESS_DENIED:
1023 error = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
1025 case RDSTLS_RESULT_ACCOUNT_DISABLED:
1026 error = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
1028 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
1029 error = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
1031 case RDSTLS_RESULT_LOGON_FAILURE:
1032 error = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
1034 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
1035 error = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
1037 case RDSTLS_RESULT_PASSWORD_EXPIRED:
1038 error = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
1040 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
1041 error = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
1044 WLog_Print(rdstls->log, WLOG_ERROR,
1045 "Unexpected resultCode: [0x%08" PRIX32
"], NTSTATUS=%s, Win32Error=%s",
1046 resultCode, GetSecurityStatusString((SECURITY_STATUS)resultCode),
1047 Win32ErrorCode2Tag(resultCode & 0xFFFF));
1048 error = FREERDP_ERROR_CONNECT_UNDEFINED;
1052 freerdp_set_last_error_if_not(rdstls->context, error);
1060static BOOL rdstls_send_capabilities(rdpRdstls* rdstls)
1064 if (!rdstls_required_role_is_server(rdstls, TRUE))
1067 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
1070 wStream* s = Stream_New(
nullptr, 512);
1074 if (!rdstls_write_capabilities(rdstls, s))
1076 if (transport_write(rdstls->transport, s) < 0)
1079 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
1081 Stream_Free(s, TRUE);
1086static BOOL rdstls_recv_authentication_request(rdpRdstls* rdstls, uint16_t* pVersion)
1089 WINPR_ASSERT(pVersion);
1091 if (!rdstls_required_role_is_server(rdstls, TRUE))
1093 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
1096 wStream* s = Stream_New(
nullptr, 4096);
1100 WINPR_ASSERT(rdstls);
1103 const int res = transport_read_pdu(rdstls->transport, s);
1108 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1111 const UINT16 version = Stream_Get_UINT16(s);
1112 if (!rdstls_is_version_supported(rdstls, version))
1114 *pVersion = version;
1116 const UINT16 pduType = Stream_Get_UINT16(s);
1119 case RDSTLS_TYPE_AUTHREQ:
1120 if (!rdstls_process_authentication_request(rdstls, s, version))
1124 WLog_Print(rdstls->log, WLOG_ERROR,
1125 "Invalid RDSTLS PDU type [0x%04" PRIx16
"] while reading AUTHREQ", pduType);
1129 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
1131 Stream_Free(s, TRUE);
1136static BOOL rdstls_send_authentication_response(rdpRdstls* rdstls, uint16_t version)
1140 if (!rdstls_required_role_is_server(rdstls, TRUE))
1143 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
1146 wStream* s = Stream_New(
nullptr, 512);
1150 if (!Stream_EnsureRemainingCapacity(s, 2))
1153 Stream_Write_UINT16(s, version);
1155 if (!rdstls_write_authentication_response(rdstls, s))
1158 if (transport_write(rdstls->transport, s) < 0)
1161 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
1163 Stream_Free(s, TRUE);
1168static BOOL rdstls_recv_capabilities(rdpRdstls* rdstls)
1172 if (!rdstls_required_role_is_server(rdstls, FALSE))
1175 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
1178 wStream* s = Stream_New(
nullptr, 512);
1182 WINPR_ASSERT(rdstls);
1185 const int res = transport_read_pdu(rdstls->transport, s);
1190 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1193 const UINT16 version = Stream_Get_UINT16(s);
1194 if (!rdstls_is_version_supported(rdstls, version))
1197 const UINT16 pduType = Stream_Get_UINT16(s);
1200 case RDSTLS_TYPE_CAPABILITIES:
1201 if (!rdstls_process_capabilities(rdstls, s))
1205 WLog_Print(rdstls->log, WLOG_ERROR,
1206 "Invalid pduType 0x%04" PRIx16
" while reading capability", pduType);
1210 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
1212 Stream_Free(s, TRUE);
1217static BOOL rdstls_send_authentication_request(rdpRdstls* rdstls, uint16_t* pVersion)
1219 WINPR_ASSERT(pVersion);
1223 if (!rdstls_required_role_is_server(rdstls, FALSE))
1226 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
1229 wStream* s = Stream_New(
nullptr, 4096);
1233 WINPR_ASSERT(rdstls->context);
1235 const rdpSettings* settings = rdstls->context->settings;
1236 WINPR_ASSERT(settings);
1238 if (!Stream_EnsureRemainingCapacity(s, 2))
1241 const RDSTLS_STATE state = rdstls_get_state(rdstls);
1243 BOOL useFedAuth = (state == RDSTLS_STATE_AUTH_REQ) && !utils_str_is_empty(fedAuthToken);
1244 if ((rdstls->supportedVersions & RDSTLS_VERSION_2) == 0)
1247 WLog_Print(rdstls->log, WLOG_WARN,
1248 "Client has FedAuthToken ready, but server did not announce RDSTLS_VERSION_2.");
1251 *pVersion = useFedAuth ? RDSTLS_VERSION_2 : RDSTLS_VERSION_1;
1252 Stream_Write_UINT16(s, *pVersion);
1256 if (!rdstls_write_authentication_request_with_fedauth_token(rdstls, s))
1259 else if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED)
1261 if (!rdstls_write_authentication_request_with_password(rdstls, s))
1264 else if (settings->ServerAutoReconnectCookie !=
nullptr)
1266 if (!rdstls_write_authentication_request_with_cookie(rdstls, s))
1271 WLog_Print(rdstls->log, WLOG_ERROR,
1272 "cannot authenticate with FedAuth token, password or "
1273 "auto-reconnect cookie");
1277 WINPR_ASSERT(rdstls);
1278 if (transport_write(rdstls->transport, s) < 0)
1281 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
1283 Stream_Free(s, TRUE);
1288static BOOL rdstls_recv_authentication_response(rdpRdstls* rdstls, uint16_t expected)
1292 WINPR_ASSERT(rdstls);
1294 if (!rdstls_required_role_is_server(rdstls, FALSE))
1297 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
1300 wStream* s = Stream_New(
nullptr, 512);
1305 const int res = transport_read_pdu(rdstls->transport, s);
1310 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1313 const UINT16 version = Stream_Get_UINT16(s);
1314 if (!rdstls_is_version_supported(rdstls, version))
1316 if (version != expected)
1319 const UINT16 pduType = Stream_Get_UINT16(s);
1322 case RDSTLS_TYPE_AUTHRSP:
1323 if (!rdstls_process_authentication_response(rdstls, s))
1327 WLog_Print(rdstls->log, WLOG_ERROR,
1328 "Invalid RDSTLS PDU type [0x%04" PRIx16
"] while reading AUTHRSP", pduType);
1332 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
1334 Stream_Free(s, TRUE);
1339static int rdstls_server_authenticate(rdpRdstls* rdstls)
1341 WINPR_ASSERT(rdstls);
1342 uint16_t version = 0;
1344 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
1347 if (!rdstls_send_capabilities(rdstls))
1350 if (!rdstls_recv_authentication_request(rdstls, &version))
1353 if (!rdstls_send_authentication_response(rdstls, version))
1356 if (rdstls->resultCode != RDSTLS_RESULT_SUCCESS)
1363static int rdstls_client_authenticate(rdpRdstls* rdstls)
1365 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
1368 if (!rdstls_recv_capabilities(rdstls))
1371 uint16_t version = 0;
1372 if (!rdstls_send_authentication_request(rdstls, &version))
1375 if (!rdstls_recv_authentication_response(rdstls, version))
1388int rdstls_authenticate(rdpRdstls* rdstls)
1390 WINPR_ASSERT(rdstls);
1393 return rdstls_server_authenticate(rdstls);
1395 return rdstls_client_authenticate(rdstls);
1399static SSIZE_T rdstls_parse_pdu_data_type(wLog* log, UINT16 dataType,
wStream* s)
1401 size_t pduLength = 0;
1405 case RDSTLS_DATA_PASSWORD_CREDS:
1407 if (Stream_GetRemainingLength(s) < 2)
1410 const UINT16 redirGuidLength = Stream_Get_UINT16(s);
1412 if (Stream_GetRemainingLength(s) < redirGuidLength)
1414 Stream_Seek(s, redirGuidLength);
1416 if (Stream_GetRemainingLength(s) < 2)
1419 const UINT16 usernameLength = Stream_Get_UINT16(s);
1421 if (Stream_GetRemainingLength(s) < usernameLength)
1423 Stream_Seek(s, usernameLength);
1425 if (Stream_GetRemainingLength(s) < 2)
1427 const UINT16 domainLength = Stream_Get_UINT16(s);
1429 if (Stream_GetRemainingLength(s) < domainLength)
1431 Stream_Seek(s, domainLength);
1433 if (Stream_GetRemainingLength(s) < 2)
1435 const UINT16 passwordLength = Stream_Get_UINT16(s);
1437 if (passwordLength == 0)
1439 WLog_Print(log, WLOG_ERROR,
"invalid RDSLTS PASSWORD_CREDS: empty password");
1442 else if ((redirGuidLength == 0) && (usernameLength == 0) && (domainLength == 0) &&
1443 (passwordLength == 0))
1445 WLog_Print(log, WLOG_ERROR,
"invalid RDSLTS PASSWORD_CREDS: lengths 0");
1448 pduLength = Stream_GetPosition(s) + passwordLength;
1451 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
1453 if (Stream_GetRemainingLength(s) < 6)
1456 const UINT16 cookieLength = Stream_Get_UINT16(s);
1457 if (cookieLength == 0)
1459 WLog_Print(log, WLOG_ERROR,
"invalid RDSLTS COOKIE::length");
1462 pduLength = Stream_GetPosition(s) + cookieLength;
1465 case RDSTLS_DATA_FEDAUTH_TOKEN:
1467 if (Stream_GetRemainingLength(s) < 6)
1470 const UINT16 tokenLength = Stream_Get_UINT16(s);
1471 if (tokenLength == 0)
1473 WLog_Print(log, WLOG_ERROR,
"invalid RDSLTS FEDAUTH_TOKEN::length");
1476 pduLength = Stream_GetPosition(s) + tokenLength;
1480 WLog_Print(log, WLOG_ERROR,
"invalid RDSLTS dataType");
1484 if (pduLength > SSIZE_MAX)
1486 return (SSIZE_T)pduLength;
1489SSIZE_T rdstls_parse_pdu(wLog* log,
wStream* stream)
1491 SSIZE_T pduLength = -1;
1492 wStream sbuffer = WINPR_C_ARRAY_INIT;
1493 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
1495 if (Stream_GetRemainingLength(s) < 2)
1498 const UINT16 version = Stream_Get_UINT16(s);
1499 if (!rdstls_are_some_versions_supported(log, version, FALSE))
1502 if (Stream_GetRemainingLength(s) < 2)
1505 const UINT16 pduType = Stream_Get_UINT16(s);
1508 case RDSTLS_TYPE_CAPABILITIES:
1511 case RDSTLS_TYPE_AUTHREQ:
1513 if (Stream_GetRemainingLength(s) < 2)
1516 const UINT16 dataType = Stream_Get_UINT16(s);
1517 pduLength = rdstls_parse_pdu_data_type(log, dataType, s);
1520 case RDSTLS_TYPE_AUTHRSP:
1524 WLog_Print(log, WLOG_ERROR,
"invalid RDSTLS PDU type");
WINPR_ATTR_NODISCARD FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API WCHAR * freerdp_settings_get_string_as_utf16(const rdpSettings *settings, FreeRDP_Settings_Keys_String id, size_t *pCharLen)
Return an allocated UTF16 string.