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 0x01
37#define RDSTLS_VERSION_2 0x02
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;
82static const char* rdstls_result_code_str(UINT32 resultCode)
86 case RDSTLS_RESULT_SUCCESS:
87 return "RDSTLS_RESULT_SUCCESS";
88 case RDSTLS_RESULT_ACCESS_DENIED:
89 return "RDSTLS_RESULT_ACCESS_DENIED";
90 case RDSTLS_RESULT_LOGON_FAILURE:
91 return "RDSTLS_RESULT_LOGON_FAILURE";
92 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
93 return "RDSTLS_RESULT_INVALID_LOGON_HOURS";
94 case RDSTLS_RESULT_PASSWORD_EXPIRED:
95 return "RDSTLS_RESULT_PASSWORD_EXPIRED";
96 case RDSTLS_RESULT_ACCOUNT_DISABLED:
97 return "RDSTLS_RESULT_ACCOUNT_DISABLED";
98 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
99 return "RDSTLS_RESULT_PASSWORD_MUST_CHANGE";
100 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
101 return "RDSTLS_RESULT_ACCOUNT_LOCKED_OUT";
103 return "RDSTLS_RESULT_UNKNOWN";
114rdpRdstls* rdstls_new(rdpContext* context, rdpTransport* transport)
116 WINPR_ASSERT(context);
117 WINPR_ASSERT(transport);
119 rdpSettings* settings = context->settings;
120 WINPR_ASSERT(settings);
122 rdpRdstls* rdstls = (rdpRdstls*)calloc(1,
sizeof(rdpRdstls));
126 rdstls->log = WLog_Get(FREERDP_TAG(
"core.rdstls"));
127 rdstls->context = context;
128 rdstls->transport = transport;
129 rdstls->server = settings->ServerMode;
131 rdstls->state = RDSTLS_STATE_INITIAL;
141void rdstls_free(rdpRdstls* rdstls)
146static const char* rdstls_get_state_str(RDSTLS_STATE state)
150 case RDSTLS_STATE_INITIAL:
151 return "RDSTLS_STATE_INITIAL";
152 case RDSTLS_STATE_CAPABILITIES:
153 return "RDSTLS_STATE_CAPABILITIES";
154 case RDSTLS_STATE_AUTH_REQ:
155 return "RDSTLS_STATE_AUTH_REQ";
156 case RDSTLS_STATE_AUTH_RSP:
157 return "RDSTLS_STATE_AUTH_RSP";
158 case RDSTLS_STATE_FINAL:
159 return "RDSTLS_STATE_FINAL";
165static RDSTLS_STATE rdstls_get_state(rdpRdstls* rdstls)
167 WINPR_ASSERT(rdstls);
168 return rdstls->state;
171static BOOL check_transition(wLog* log, RDSTLS_STATE current, RDSTLS_STATE expected,
172 RDSTLS_STATE requested)
174 if (requested != expected)
176 WLog_Print(log, WLOG_ERROR,
177 "Unexpected rdstls state transition from %s [%u] to %s [%u], expected %s [%u]",
178 rdstls_get_state_str(current), current, rdstls_get_state_str(requested),
179 requested, rdstls_get_state_str(expected), expected);
185static BOOL rdstls_set_state(rdpRdstls* rdstls, RDSTLS_STATE state)
188 WINPR_ASSERT(rdstls);
190 WLog_Print(rdstls->log, WLOG_DEBUG,
"-- %s\t--> %s", rdstls_get_state_str(rdstls->state),
191 rdstls_get_state_str(state));
193 switch (rdstls->state)
195 case RDSTLS_STATE_INITIAL:
196 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_CAPABILITIES, state);
198 case RDSTLS_STATE_CAPABILITIES:
199 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_AUTH_REQ, state);
201 case RDSTLS_STATE_AUTH_REQ:
202 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_AUTH_RSP, state);
204 case RDSTLS_STATE_AUTH_RSP:
205 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_FINAL, state);
207 case RDSTLS_STATE_FINAL:
208 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_CAPABILITIES, state);
211 WLog_Print(rdstls->log, WLOG_ERROR,
212 "Invalid rdstls state %s [%u], requested transition to %s [%u]",
213 rdstls_get_state_str(rdstls->state), rdstls->state,
214 rdstls_get_state_str(state), state);
218 rdstls->state = state;
223static BOOL rdstls_write_capabilities(WINPR_ATTR_UNUSED rdpRdstls* rdstls,
wStream* s)
225 if (!Stream_EnsureRemainingCapacity(s, 6))
228 Stream_Write_UINT16(s, RDSTLS_TYPE_CAPABILITIES);
229 Stream_Write_UINT16(s, RDSTLS_DATA_CAPABILITIES);
230 Stream_Write_UINT16(s, RDSTLS_VERSION_1);
235static SSIZE_T rdstls_write_string(
wStream* s,
const char* str)
237 const size_t pos = Stream_GetPosition(s);
239 if (!Stream_EnsureRemainingCapacity(s, 2))
245 Stream_Write_UINT16(s, 2);
246 if (!Stream_EnsureRemainingCapacity(s, 2))
249 Stream_Write_UINT16(s, 0);
250 return (SSIZE_T)(Stream_GetPosition(s) - pos);
253 const SSIZE_T devNameWLen = ConvertUtf8ToWChar(str,
nullptr, 0);
256 const size_t length = WINPR_ASSERTING_INT_CAST(
size_t, devNameWLen) + 1;
257 const size_t slen = strlen(str);
259 Stream_Write_UINT16(s, (UINT16)length *
sizeof(WCHAR));
261 if (!Stream_EnsureRemainingCapacity(s, length *
sizeof(WCHAR)))
264 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, slen, TRUE) < 0)
267 return (SSIZE_T)(Stream_GetPosition(s) - pos);
270static BOOL rdstls_write_data(
wStream* s, UINT32 length,
const BYTE* data)
272 WINPR_ASSERT(data || (length == 0));
274 if (!Stream_EnsureRemainingCapacity(s, 2) || (length > UINT16_MAX))
277 Stream_Write_UINT16(s, (UINT16)length);
279 if (!Stream_EnsureRemainingCapacity(s, length))
282 Stream_Write(s, data, length);
289 WINPR_ASSERT(cookie);
290 const uint16_t length = 28;
292 if (!Stream_EnsureRemainingCapacity(s, 2))
295 Stream_Write_UINT16(s, length);
297 if (!Stream_EnsureRemainingCapacity(s, length))
300 Stream_Write_UINT32(s, cookie->cbLen);
301 Stream_Write_UINT32(s, cookie->version);
302 Stream_Write_UINT32(s, cookie->logonId);
303 Stream_Write(s, cookie->arcRandomBits,
sizeof(cookie->arcRandomBits));
307static BOOL rdstls_write_authentication_request_with_password(rdpRdstls* rdstls,
wStream* s)
309 WINPR_ASSERT(rdstls);
310 WINPR_ASSERT(rdstls->context);
312 WLog_Print(rdstls->log, WLOG_DEBUG,
"Writing RDSTLS password authentication message");
314 rdpSettings* settings = rdstls->context->settings;
315 WINPR_ASSERT(settings);
317 if (!Stream_EnsureRemainingCapacity(s, 4))
320 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
321 Stream_Write_UINT16(s, RDSTLS_DATA_PASSWORD_CREDS);
323 if (!rdstls_write_data(s, settings->RedirectionGuidLength, settings->RedirectionGuid))
326 if (rdstls_write_string(s, settings->Username) < 0)
329 if (rdstls_write_string(s, settings->Domain) < 0)
332 if (!rdstls_write_data(s, settings->RedirectionPasswordLength, settings->RedirectionPassword))
338static BOOL rdstls_write_authentication_request_with_cookie(WINPR_ATTR_UNUSED rdpRdstls* rdstls,
341 WINPR_ASSERT(rdstls);
342 WINPR_ASSERT(rdstls->context);
344 WLog_Print(rdstls->log, WLOG_DEBUG,
"Writing RDSTLS cookie authentication message");
346 rdpSettings* settings = rdstls->context->settings;
347 WINPR_ASSERT(settings);
349 if (!Stream_EnsureRemainingCapacity(s, 8))
352 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
353 Stream_Write_UINT16(s, RDSTLS_DATA_AUTORECONNECT_COOKIE);
354 Stream_Write_UINT32(s, settings->RedirectedSessionId);
356 return (rdstls_write_cookie(s, settings->ServerAutoReconnectCookie));
366static void rdstls_check_fedauth_vmid(rdpRdstls* rdstls,
const char* token,
const char* selectedVm)
368 WINPR_ASSERT(rdstls);
371 if (!selectedVm || !*selectedVm)
374 const char* vmidField = strstr(token,
"VMID=");
379 const size_t vmLen = strlen(selectedVm);
380 const BOOL matches = (_strnicmp(vmidField, selectedVm, vmLen) == 0) &&
381 (vmidField[vmLen] ==
'\0' || vmidField[vmLen] ==
'&');
384 WLog_Print(rdstls->log, WLOG_WARN,
385 "endpoint FedAuth token is issued for a different virtual machine "
386 "than the one selected for connection");
391static BOOL rdstls_write_authentication_request_with_fedauth_token(rdpRdstls* rdstls,
wStream* s)
393 WINPR_ASSERT(rdstls);
394 WINPR_ASSERT(rdstls->context);
396 WLog_Print(rdstls->log, WLOG_DEBUG,
"Writing RDSTLS FedAuth token authentication message");
398 const rdpSettings* settings = rdstls->context->settings;
399 WINPR_ASSERT(settings);
402 if (!token || !*token)
404 WLog_Print(rdstls->log, WLOG_ERROR,
"EndpointFedAuthToken not set");
408 rdstls_check_fedauth_vmid(rdstls, token,
411 const size_t utf8Length = strlen(token);
414 if (utf8Length >= UINT16_MAX /
sizeof(WCHAR))
416 WLog_Print(rdstls->log, WLOG_ERROR,
417 "EndpointFedAuthToken length %" PRIuz
" exceeds RDSTLS wire limit", utf8Length);
421 const size_t wideLength = utf8Length + 1;
422 const size_t wideBytes = wideLength *
sizeof(WCHAR);
424 if (!Stream_EnsureRemainingCapacity(s, 6 + wideBytes))
427 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
428 Stream_Write_UINT16(s, RDSTLS_DATA_FEDAUTH_TOKEN);
429 Stream_Write_UINT16(s, (UINT16)wideBytes);
431 return Stream_Write_UTF16_String_From_UTF8(s, wideLength, token, utf8Length, TRUE) >= 0;
434static BOOL rdstls_write_authentication_response(rdpRdstls* rdstls,
wStream* s)
436 WINPR_ASSERT(rdstls);
437 if (!Stream_EnsureRemainingCapacity(s, 8))
440 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHRSP);
441 Stream_Write_UINT16(s, RDSTLS_DATA_RESULT_CODE);
442 Stream_Write_UINT32(s, rdstls->resultCode);
447static BOOL rdstls_process_capabilities(rdpRdstls* rdstls,
wStream* s)
449 WINPR_ASSERT(rdstls);
450 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
453 const UINT16 dataType = Stream_Get_UINT16(s);
454 if (dataType != RDSTLS_DATA_CAPABILITIES)
456 WLog_Print(rdstls->log, WLOG_ERROR,
457 "received invalid DataType=0x%04" PRIX16
", expected 0x%04" PRIX32, dataType,
458 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_CAPABILITIES));
462 const UINT16 supportedVersions = Stream_Get_UINT16(s);
463 if ((supportedVersions & RDSTLS_VERSION_1) == 0)
465 WLog_Print(rdstls->log, WLOG_ERROR,
466 "received invalid supportedVersions=0x%04" PRIX16
", expected 0x%04" PRIX32,
467 supportedVersions, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_VERSION_1));
474static BOOL rdstls_read_unicode_string(WINPR_ATTR_UNUSED wLog* log,
wStream* s,
char** str)
478 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
481 const UINT16 length = Stream_Get_UINT16(s);
483 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length))
488 Stream_Seek(s, length);
492 *str = Stream_Read_UTF16_String_As_UTF8(s, length /
sizeof(WCHAR),
nullptr);
493 return (*str) !=
nullptr;
496static BOOL rdstls_read_data(WINPR_ATTR_UNUSED wLog* log,
wStream* s, UINT16* pLength,
499 WINPR_ASSERT(pLength);
504 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
507 const UINT16 length = Stream_Get_UINT16(s);
509 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length))
514 Stream_Seek(s, length);
518 *pData = Stream_ConstPointer(s);
520 Stream_Seek(s, length);
524static BOOL rdstls_cmp_data(wLog* log,
const char* field,
const BYTE* serverData,
525 const UINT32 serverDataLength,
const BYTE* clientData,
526 const UINT16 clientDataLength)
528 if (serverDataLength > 0)
530 if (clientDataLength == 0)
532 WLog_Print(log, WLOG_ERROR,
"expected %s", field);
536 if (serverDataLength > UINT16_MAX || serverDataLength != clientDataLength ||
537 memcmp(serverData, clientData, serverDataLength) != 0)
539 WLog_Print(log, WLOG_ERROR,
"%s verification failed", field);
547static BOOL rdstls_cmp_str(wLog* log,
const char* field,
const char* serverStr,
548 const char* clientStr)
550 if (!utils_str_is_empty(serverStr))
552 if (utils_str_is_empty(clientStr))
554 WLog_Print(log, WLOG_ERROR,
"expected %s", field);
558 WINPR_ASSERT(serverStr);
559 WINPR_ASSERT(clientStr);
560 if (strcmp(serverStr, clientStr) != 0)
562 WLog_Print(log, WLOG_ERROR,
"%s verification failed", field);
570static BOOL rdstls_process_authentication_request_with_password(rdpRdstls* rdstls,
wStream* s)
572 WINPR_ASSERT(rdstls);
573 WINPR_ASSERT(rdstls->context);
577 const BYTE* clientRedirectionGuid =
nullptr;
578 UINT16 clientRedirectionGuidLength = 0;
579 char* clientPassword =
nullptr;
580 char* clientUsername =
nullptr;
581 char* clientDomain =
nullptr;
583 const rdpSettings* settings = rdstls->context->settings;
584 WINPR_ASSERT(settings);
586 if (!rdstls_read_data(rdstls->log, s, &clientRedirectionGuidLength, &clientRedirectionGuid))
589 if (!rdstls_read_unicode_string(rdstls->log, s, &clientUsername))
592 if (!rdstls_read_unicode_string(rdstls->log, s, &clientDomain))
595 if (!rdstls_read_unicode_string(rdstls->log, s, &clientPassword))
599 const BYTE* serverRedirectionGuid =
601 const UINT32 serverRedirectionGuidLength =
607 rdstls->resultCode = RDSTLS_RESULT_SUCCESS;
609 if (!rdstls_cmp_data(rdstls->log,
"RedirectionGuid", serverRedirectionGuid,
610 serverRedirectionGuidLength, clientRedirectionGuid,
611 clientRedirectionGuidLength))
612 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
614 if (!rdstls_cmp_str(rdstls->log,
"UserName", serverUsername, clientUsername))
615 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
617 if (!rdstls_cmp_str(rdstls->log,
"Domain", serverDomain, clientDomain))
618 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
620 if (!rdstls_cmp_str(rdstls->log,
"Password", serverPassword, clientPassword))
621 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
628static BOOL rdstls_process_authentication_request_with_cookie(WINPR_ATTR_UNUSED rdpRdstls* rdstls,
632 WLog_Print(rdstls->log, WLOG_ERROR,
"TODO: RDSTLS Cookie authentication not implemented");
636static BOOL rdstls_process_authentication_request(rdpRdstls* rdstls,
wStream* s)
638 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 2))
641 const UINT16 dataType = Stream_Get_UINT16(s);
644 case RDSTLS_DATA_PASSWORD_CREDS:
645 if (!rdstls_process_authentication_request_with_password(rdstls, s))
648 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
649 if (!rdstls_process_authentication_request_with_cookie(rdstls, s))
653 WLog_Print(rdstls->log, WLOG_ERROR,
654 "received invalid DataType=0x%04" PRIX16
", expected 0x%04" PRIX32
656 dataType, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_PASSWORD_CREDS),
657 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_AUTORECONNECT_COOKIE));
664static BOOL rdstls_process_authentication_response(rdpRdstls* rdstls,
wStream* s)
666 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 6))
669 const UINT16 dataType = Stream_Get_UINT16(s);
670 if (dataType != RDSTLS_DATA_RESULT_CODE)
672 WLog_Print(rdstls->log, WLOG_ERROR,
673 "received invalid DataType=0x%04" PRIX16
", expected 0x%04" PRIX32, dataType,
674 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_RESULT_CODE));
678 const UINT32 resultCode = Stream_Get_UINT32(s);
679 if (resultCode != RDSTLS_RESULT_SUCCESS)
681 WLog_Print(rdstls->log, WLOG_ERROR,
"resultCode: %s [0x%08" PRIX32
"]",
682 rdstls_result_code_str(resultCode), resultCode);
684 UINT32 error = FREERDP_ERROR_CONNECT_UNDEFINED;
687 case RDSTLS_RESULT_ACCESS_DENIED:
688 error = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
690 case RDSTLS_RESULT_ACCOUNT_DISABLED:
691 error = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
693 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
694 error = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
696 case RDSTLS_RESULT_LOGON_FAILURE:
697 error = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
699 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
700 error = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
702 case RDSTLS_RESULT_PASSWORD_EXPIRED:
703 error = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
705 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
706 error = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
709 WLog_Print(rdstls->log, WLOG_ERROR,
710 "Unexpected resultCode: [0x%08" PRIX32
"], NTSTATUS=%s, Win32Error=%s",
711 resultCode, GetSecurityStatusString((SECURITY_STATUS)resultCode),
712 Win32ErrorCode2Tag(resultCode & 0xFFFF));
713 error = FREERDP_ERROR_CONNECT_UNDEFINED;
717 freerdp_set_last_error_if_not(rdstls->context, error);
724static BOOL rdstls_send(WINPR_ATTR_UNUSED rdpTransport* transport,
wStream* s,
void* extra)
726 rdpRdstls* rdstls = (rdpRdstls*)extra;
727 rdpSettings* settings =
nullptr;
729 WINPR_ASSERT(transport);
731 WINPR_ASSERT(rdstls);
733 settings = rdstls->context->settings;
734 WINPR_ASSERT(settings);
736 if (!Stream_EnsureRemainingCapacity(s, 2))
739 const RDSTLS_STATE state = rdstls_get_state(rdstls);
741 const BOOL useFedAuth = (state == RDSTLS_STATE_AUTH_REQ) && !utils_str_is_empty(fedAuthToken);
743 Stream_Write_UINT16(s, useFedAuth ? RDSTLS_VERSION_2 : RDSTLS_VERSION_1);
747 case RDSTLS_STATE_CAPABILITIES:
748 if (!rdstls_write_capabilities(rdstls, s))
751 case RDSTLS_STATE_AUTH_REQ:
754 if (!rdstls_write_authentication_request_with_fedauth_token(rdstls, s))
757 else if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED)
759 if (!rdstls_write_authentication_request_with_password(rdstls, s))
762 else if (settings->ServerAutoReconnectCookie !=
nullptr)
764 if (!rdstls_write_authentication_request_with_cookie(rdstls, s))
769 WLog_Print(rdstls->log, WLOG_ERROR,
770 "cannot authenticate with FedAuth token, password or "
771 "auto-reconnect cookie");
775 case RDSTLS_STATE_AUTH_RSP:
776 if (!rdstls_write_authentication_response(rdstls, s))
780 WLog_Print(rdstls->log, WLOG_ERROR,
"Invalid rdstls state %s [%" PRIu32
"]",
781 rdstls_get_state_str(state), state);
785 return (transport_write(rdstls->transport, s) >= 0);
788static int rdstls_recv(WINPR_ATTR_UNUSED rdpTransport* transport,
wStream* s,
void* extra)
790 rdpRdstls* rdstls = (rdpRdstls*)extra;
792 WINPR_ASSERT(transport);
794 WINPR_ASSERT(rdstls);
796 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
799 const UINT16 version = Stream_Get_UINT16(s);
800 if (version != RDSTLS_VERSION_1)
802 WLog_Print(rdstls->log, WLOG_ERROR,
803 "received invalid RDSTLS Version=0x%04" PRIX16
", expected 0x%04" PRIX16,
804 version, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_VERSION_1));
808 const UINT16 pduType = Stream_Get_UINT16(s);
811 case RDSTLS_TYPE_CAPABILITIES:
812 if (!rdstls_process_capabilities(rdstls, s))
815 case RDSTLS_TYPE_AUTHREQ:
816 if (!rdstls_process_authentication_request(rdstls, s))
819 case RDSTLS_TYPE_AUTHRSP:
820 if (!rdstls_process_authentication_response(rdstls, s))
824 WLog_Print(rdstls->log, WLOG_ERROR,
"unknown RDSTLS PDU type [0x%04" PRIx16
"]",
832#define rdstls_check_state_requirements(rdstls, expected) \
833 rdstls_check_state_requirements_((rdstls), (expected), __FILE__, __func__, __LINE__)
834static BOOL rdstls_check_state_requirements_(rdpRdstls* rdstls, RDSTLS_STATE expected,
835 const char* file,
const char* fkt,
size_t line)
837 const RDSTLS_STATE current = rdstls_get_state(rdstls);
838 if (current == expected)
841 WINPR_ASSERT(rdstls);
843 const DWORD log_level = WLOG_ERROR;
844 if (WLog_IsLevelActive(rdstls->log, log_level))
845 WLog_PrintTextMessage(rdstls->log, log_level, line, file, fkt,
846 "Unexpected rdstls state %s [%u], expected %s [%u]",
847 rdstls_get_state_str(current), current,
848 rdstls_get_state_str(expected), expected);
853static BOOL rdstls_send_capabilities(rdpRdstls* rdstls)
857 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
860 wStream* s = Stream_New(
nullptr, 512);
864 WINPR_ASSERT(rdstls);
865 if (!rdstls_send(rdstls->transport, s, rdstls))
868 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
870 Stream_Free(s, TRUE);
874static BOOL rdstls_recv_authentication_request(rdpRdstls* rdstls)
878 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
881 wStream* s = Stream_New(
nullptr, 4096);
885 WINPR_ASSERT(rdstls);
888 const int res = transport_read_pdu(rdstls->transport, s);
894 const int status = rdstls_recv(rdstls->transport, s, rdstls);
899 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
901 Stream_Free(s, TRUE);
905static BOOL rdstls_send_authentication_response(rdpRdstls* rdstls)
909 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
912 wStream* s = Stream_New(
nullptr, 512);
916 WINPR_ASSERT(rdstls);
917 if (!rdstls_send(rdstls->transport, s, rdstls))
920 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
922 Stream_Free(s, TRUE);
926static BOOL rdstls_recv_capabilities(rdpRdstls* rdstls)
930 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
933 wStream* s = Stream_New(
nullptr, 512);
937 WINPR_ASSERT(rdstls);
940 const int res = transport_read_pdu(rdstls->transport, s);
946 const int status = rdstls_recv(rdstls->transport, s, rdstls);
951 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
953 Stream_Free(s, TRUE);
957static BOOL rdstls_send_authentication_request(rdpRdstls* rdstls)
961 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
964 wStream* s = Stream_New(
nullptr, 4096);
968 WINPR_ASSERT(rdstls);
969 if (!rdstls_send(rdstls->transport, s, rdstls))
972 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
974 Stream_Free(s, TRUE);
978static BOOL rdstls_recv_authentication_response(rdpRdstls* rdstls)
982 WINPR_ASSERT(rdstls);
984 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
987 wStream* s = Stream_New(
nullptr, 512);
992 const int res = transport_read_pdu(rdstls->transport, s);
998 const int status = rdstls_recv(rdstls->transport, s, rdstls);
1003 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
1005 Stream_Free(s, TRUE);
1009static int rdstls_server_authenticate(rdpRdstls* rdstls)
1011 WINPR_ASSERT(rdstls);
1013 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
1016 if (!rdstls_send_capabilities(rdstls))
1019 if (!rdstls_recv_authentication_request(rdstls))
1022 if (!rdstls_send_authentication_response(rdstls))
1025 if (rdstls->resultCode != RDSTLS_RESULT_SUCCESS)
1031static int rdstls_client_authenticate(rdpRdstls* rdstls)
1033 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
1036 if (!rdstls_recv_capabilities(rdstls))
1039 if (!rdstls_send_authentication_request(rdstls))
1042 if (!rdstls_recv_authentication_response(rdstls))
1055int rdstls_authenticate(rdpRdstls* rdstls)
1057 WINPR_ASSERT(rdstls);
1060 return rdstls_server_authenticate(rdstls);
1062 return rdstls_client_authenticate(rdstls);
1065static SSIZE_T rdstls_parse_pdu_data_type(wLog* log, UINT16 dataType,
wStream* s)
1067 size_t pduLength = 0;
1071 case RDSTLS_DATA_PASSWORD_CREDS:
1073 if (Stream_GetRemainingLength(s) < 2)
1076 const UINT16 redirGuidLength = Stream_Get_UINT16(s);
1078 if (Stream_GetRemainingLength(s) < redirGuidLength)
1080 Stream_Seek(s, redirGuidLength);
1082 if (Stream_GetRemainingLength(s) < 2)
1085 const UINT16 usernameLength = Stream_Get_UINT16(s);
1087 if (Stream_GetRemainingLength(s) < usernameLength)
1089 Stream_Seek(s, usernameLength);
1091 if (Stream_GetRemainingLength(s) < 2)
1093 const UINT16 domainLength = Stream_Get_UINT16(s);
1095 if (Stream_GetRemainingLength(s) < domainLength)
1097 Stream_Seek(s, domainLength);
1099 if (Stream_GetRemainingLength(s) < 2)
1101 const UINT16 passwordLength = Stream_Get_UINT16(s);
1103 pduLength = Stream_GetPosition(s) + passwordLength;
1106 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
1108 if (Stream_GetRemainingLength(s) < 4)
1112 if (Stream_GetRemainingLength(s) < 2)
1114 const UINT16 cookieLength = Stream_Get_UINT16(s);
1116 pduLength = Stream_GetPosition(s) + cookieLength;
1120 WLog_Print(log, WLOG_ERROR,
"invalid RDSLTS dataType");
1124 if (pduLength > SSIZE_MAX)
1126 return (SSIZE_T)pduLength;
1129SSIZE_T rdstls_parse_pdu(wLog* log,
wStream* stream)
1131 SSIZE_T pduLength = -1;
1132 wStream sbuffer = WINPR_C_ARRAY_INIT;
1133 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
1135 if (Stream_GetRemainingLength(s) < 2)
1138 const UINT16 version = Stream_Get_UINT16(s);
1139 if (version != RDSTLS_VERSION_1)
1141 WLog_Print(log, WLOG_ERROR,
"invalid RDSTLS version");
1145 if (Stream_GetRemainingLength(s) < 2)
1148 const UINT16 pduType = Stream_Get_UINT16(s);
1151 case RDSTLS_TYPE_CAPABILITIES:
1154 case RDSTLS_TYPE_AUTHREQ:
1156 if (Stream_GetRemainingLength(s) < 2)
1159 const UINT16 dataType = Stream_Get_UINT16(s);
1160 pduLength = rdstls_parse_pdu_data_type(log, dataType, s);
1163 case RDSTLS_TYPE_AUTHRSP:
1167 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.