FreeRDP
Loading...
Searching...
No Matches
rdstls.c
1
20#include <freerdp/config.h>
21
22#include "settings.h"
23
24#include <freerdp/log.h>
25#include <freerdp/error.h>
26#include <freerdp/settings.h>
27
28#include <winpr/assert.h>
29#include <winpr/stream.h>
30#include <winpr/wlog.h>
31
32#include "rdstls.h"
33#include "transport.h"
34#include "utils.h"
35
36#define RDSTLS_VERSION_1 0x01u
37#define RDSTLS_VERSION_2 0x02u
38
39#define RDSTLS_TYPE_CAPABILITIES 0x01
40#define RDSTLS_TYPE_AUTHREQ 0x02
41#define RDSTLS_TYPE_AUTHRSP 0x04
42
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
48
49typedef enum
50{
51 RDSTLS_STATE_INITIAL,
52 RDSTLS_STATE_CAPABILITIES,
53 RDSTLS_STATE_AUTH_REQ,
54 RDSTLS_STATE_AUTH_RSP,
55 RDSTLS_STATE_FINAL,
56} RDSTLS_STATE;
57
58typedef enum
59{
60
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
69} RDSTLS_RESULT_CODE;
70
71struct rdp_rdstls
72{
73 BOOL server;
74 RDSTLS_STATE state;
75 rdpContext* context;
76 rdpTransport* transport;
77
78 RDSTLS_RESULT_CODE resultCode;
79 wLog* log;
80 uint16_t supportedVersions;
81};
82
83static const uint16_t RDSTLS_VERSION_MASK = RDSTLS_VERSION_1 | RDSTLS_VERSION_2;
84
85WINPR_ATTR_NODISCARD
86static const char* rdstls_result_code_str(UINT32 resultCode)
87{
88 switch (resultCode)
89 {
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";
106 default:
107 return "RDSTLS_RESULT_UNKNOWN";
108 }
109}
110
111#define rdstls_required_role_is_server(rdstls, isServer) \
112 rdstls_required_role_is_server_((rdstls), (isServer), __FILE__, __func__, __LINE__)
113
114WINPR_ATTR_NODISCARD
115static BOOL rdstls_required_role_is_server_(const rdpRdstls* rdstls, BOOL isServer,
116 const char* file, const char* fkt, size_t line)
117{
118 WINPR_ASSERT(rdstls);
119 const BOOL rc = rdstls->server == isServer;
120 if (!rc)
121 {
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");
127 }
128 return rc;
129}
130
139rdpRdstls* rdstls_new(rdpContext* context, rdpTransport* transport)
140{
141 WINPR_ASSERT(context);
142 WINPR_ASSERT(transport);
143
144 rdpSettings* settings = context->settings;
145 WINPR_ASSERT(settings);
146
147 rdpRdstls* rdstls = (rdpRdstls*)calloc(1, sizeof(rdpRdstls));
148
149 if (!rdstls)
150 return nullptr;
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;
156
157 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
158 rdstls->state = RDSTLS_STATE_INITIAL;
159
160 return rdstls;
161}
162
168void rdstls_free(rdpRdstls* rdstls)
169{
170 free(rdstls);
171}
172
173WINPR_ATTR_NODISCARD
174static const char* rdstls_get_state_str(RDSTLS_STATE state)
175{
176 switch (state)
177 {
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";
188 default:
189 return "UNKNOWN";
190 }
191}
192
193WINPR_ATTR_NODISCARD
194static RDSTLS_STATE rdstls_get_state(rdpRdstls* rdstls)
195{
196 WINPR_ASSERT(rdstls);
197 return rdstls->state;
198}
199
200WINPR_ATTR_NODISCARD
201static BOOL check_transition(wLog* log, RDSTLS_STATE current, RDSTLS_STATE expected,
202 RDSTLS_STATE requested)
203{
204 if (requested != expected)
205 {
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);
210 return FALSE;
211 }
212 return TRUE;
213}
214
215WINPR_ATTR_NODISCARD
216static BOOL rdstls_set_state(rdpRdstls* rdstls, RDSTLS_STATE state)
217{
218 BOOL rc = FALSE;
219 WINPR_ASSERT(rdstls);
220
221 WLog_Print(rdstls->log, WLOG_DEBUG, "-- %s\t--> %s", rdstls_get_state_str(rdstls->state),
222 rdstls_get_state_str(state));
223
224 switch (rdstls->state)
225 {
226 case RDSTLS_STATE_INITIAL:
227 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_CAPABILITIES, state);
228 break;
229 case RDSTLS_STATE_CAPABILITIES:
230 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_AUTH_REQ, state);
231 break;
232 case RDSTLS_STATE_AUTH_REQ:
233 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_AUTH_RSP, state);
234 break;
235 case RDSTLS_STATE_AUTH_RSP:
236 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_FINAL, state);
237 break;
238 case RDSTLS_STATE_FINAL:
239 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_CAPABILITIES, state);
240 break;
241 default:
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);
246 break;
247 }
248 if (rc)
249 rdstls->state = state;
250
251 return rc;
252}
253
254#define rdstls_check_state_requirements(rdstls, expected) \
255 rdstls_check_state_requirements_((rdstls), (expected), __FILE__, __func__, __LINE__)
256
257WINPR_ATTR_NODISCARD
258static BOOL rdstls_check_state_requirements_(rdpRdstls* rdstls, RDSTLS_STATE expected,
259 const char* file, const char* fkt, size_t line)
260{
261 const RDSTLS_STATE current = rdstls_get_state(rdstls);
262 if (current == expected)
263 return TRUE;
264
265 WINPR_ASSERT(rdstls);
266
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);
273
274 return FALSE;
275}
276
277WINPR_ATTR_NODISCARD
278static BOOL rdstls_write_capabilities(WINPR_ATTR_UNUSED rdpRdstls* rdstls, wStream* s)
279{
280 if (!Stream_EnsureRemainingCapacity(s, 8))
281 return FALSE;
282
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);
287
288 return TRUE;
289}
290
291WINPR_ATTR_NODISCARD
292static SSIZE_T rdstls_write_string(wStream* s, const char* str)
293{
294 const size_t pos = Stream_GetPosition(s);
295
296 if (!Stream_EnsureRemainingCapacity(s, 2))
297 return -1;
298
299 if (!str)
300 {
301 /* Write unicode null */
302 Stream_Write_UINT16(s, 2);
303 if (!Stream_EnsureRemainingCapacity(s, 2))
304 return -1;
305
306 Stream_Write_UINT16(s, 0);
307 return (SSIZE_T)(Stream_GetPosition(s) - pos);
308 }
309
310 const SSIZE_T devNameWLen = ConvertUtf8ToWChar(str, nullptr, 0);
311 if (devNameWLen < 0)
312 return -1;
313 const size_t length = WINPR_ASSERTING_INT_CAST(size_t, devNameWLen) + 1;
314 const size_t slen = strlen(str);
315
316 Stream_Write_UINT16(s, (UINT16)length * sizeof(WCHAR));
317
318 if (!Stream_EnsureRemainingCapacity(s, length * sizeof(WCHAR)))
319 return -1;
320
321 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, slen, TRUE) < 0)
322 return -1;
323
324 return (SSIZE_T)(Stream_GetPosition(s) - pos);
325}
326
327WINPR_ATTR_NODISCARD
328static BOOL rdstls_write_data(wStream* s, UINT32 length, const BYTE* data)
329{
330 WINPR_ASSERT(data || (length == 0));
331
332 if (!Stream_EnsureRemainingCapacity(s, 2) || (length > UINT16_MAX))
333 return FALSE;
334
335 Stream_Write_UINT16(s, (UINT16)length);
336
337 if (!Stream_EnsureRemainingCapacity(s, length))
338 return FALSE;
339
340 Stream_Write(s, data, length);
341
342 return TRUE;
343}
344
345WINPR_ATTR_NODISCARD
346static BOOL rdstls_write_cookie(wStream* s, const ARC_SC_PRIVATE_PACKET* cookie)
347{
348 WINPR_ASSERT(cookie);
349 const uint16_t length = sizeof(ARC_SC_PRIVATE_PACKET);
350 WINPR_STATIC_ASSERT(sizeof(ARC_SC_PRIVATE_PACKET) == 28);
351
352 if (!Stream_EnsureRemainingCapacity(s, 2))
353 return FALSE;
354
355 Stream_Write_UINT16(s, length);
356
357 if (!Stream_EnsureRemainingCapacity(s, length))
358 return FALSE;
359
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));
364 return TRUE;
365}
366
367WINPR_ATTR_NODISCARD
368static BOOL rdstls_read_cookie(wLog* log, wStream* s, ARC_SC_PRIVATE_PACKET* cookie)
369{
370 WINPR_ASSERT(cookie);
371 const uint16_t length = sizeof(ARC_SC_PRIVATE_PACKET);
372 WINPR_STATIC_ASSERT(sizeof(ARC_SC_PRIVATE_PACKET) == 28);
373
374 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length + 2ull))
375 return FALSE;
376
377 const uint16_t len = Stream_Get_UINT16(s);
378 if (len != length)
379 {
380 WLog_Print(log, WLOG_ERROR,
381 "RDSTLS Cookie: Unexpected length %" PRIu16 ", expected %" PRIu16, len, length);
382 return FALSE;
383 }
384
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));
389 return TRUE;
390}
391
392WINPR_ATTR_NODISCARD
393static BOOL rdstls_write_authentication_request_with_password(rdpRdstls* rdstls, wStream* s)
394{
395 WINPR_ASSERT(rdstls);
396 WINPR_ASSERT(rdstls->context);
397
398 if (!rdstls_required_role_is_server(rdstls, FALSE))
399 return FALSE;
400 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
401 return FALSE;
402
403 WLog_Print(rdstls->log, WLOG_DEBUG, "Writing RDSTLS password authentication message");
404
405 rdpSettings* settings = rdstls->context->settings;
406 WINPR_ASSERT(settings);
407
408 if (!Stream_EnsureRemainingCapacity(s, 4))
409 return FALSE;
410
411 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
412 Stream_Write_UINT16(s, RDSTLS_DATA_PASSWORD_CREDS);
413
414 if (!rdstls_write_data(s, settings->RedirectionGuidLength, settings->RedirectionGuid))
415 return FALSE;
416
417 if (rdstls_write_string(s, settings->Username) < 0)
418 return FALSE;
419
420 if (rdstls_write_string(s, settings->Domain) < 0)
421 return FALSE;
422
423 if (!rdstls_write_data(s, settings->RedirectionPasswordLength, settings->RedirectionPassword))
424 return FALSE;
425
426 return TRUE;
427}
428
429WINPR_ATTR_NODISCARD
430static BOOL rdstls_write_authentication_request_with_cookie(WINPR_ATTR_UNUSED rdpRdstls* rdstls,
431 WINPR_ATTR_UNUSED wStream* s)
432{
433 WINPR_ASSERT(rdstls);
434 WINPR_ASSERT(rdstls->context);
435
436 WLog_Print(rdstls->log, WLOG_DEBUG, "Writing RDSTLS cookie authentication message");
437
438 if (!rdstls_required_role_is_server(rdstls, FALSE))
439 return FALSE;
440 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
441 return FALSE;
442
443 rdpSettings* settings = rdstls->context->settings;
444 WINPR_ASSERT(settings);
445
446 if (!Stream_EnsureRemainingCapacity(s, 8))
447 return FALSE;
448
449 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
450 Stream_Write_UINT16(s, RDSTLS_DATA_AUTORECONNECT_COOKIE);
451 Stream_Write_UINT32(s, settings->RedirectedSessionId);
452
453 return (rdstls_write_cookie(s, settings->ServerAutoReconnectCookie));
454}
455
456/*
457 * Warn if the endpoint FedAuth token targets a different virtual machine
458 * than the VM identifier passed via the .rdp `pcb` field / /pcb command
459 * line switch. The token payload starts with "VMID=<guid>&..."; a
460 * mismatch would be silently rejected by the server later on. This is a
461 * best-effort local sanity check.
462 */
463static void rdstls_check_fedauth_vmid(rdpRdstls* rdstls, const char* token, const char* selectedVm)
464{
465 WINPR_ASSERT(rdstls);
466 WINPR_ASSERT(token);
467
468 if (!selectedVm || !*selectedVm)
469 return;
470
471 const char* vmidField = strstr(token, "VMID=");
472 if (!vmidField)
473 return;
474 vmidField += 5;
475
476 const size_t vmLen = strlen(selectedVm);
477 const BOOL matches = (_strnicmp(vmidField, selectedVm, vmLen) == 0) &&
478 (vmidField[vmLen] == '\0' || vmidField[vmLen] == '&');
479 if (!matches)
480 {
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");
484 }
485}
486
487WINPR_ATTR_NODISCARD
488static BOOL rdstls_write_authentication_request_with_fedauth_token(rdpRdstls* rdstls, wStream* s)
489{
490 WINPR_ASSERT(rdstls);
491 WINPR_ASSERT(rdstls->context);
492
493 WLog_Print(rdstls->log, WLOG_DEBUG, "Writing RDSTLS FedAuth token authentication message");
494
495 if (!rdstls_required_role_is_server(rdstls, FALSE))
496 return FALSE;
497 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
498 return FALSE;
499
500 const rdpSettings* settings = rdstls->context->settings;
501 WINPR_ASSERT(settings);
502
503 const char* token = freerdp_settings_get_string(settings, FreeRDP_EndpointFedAuthToken);
504 if (!token || !*token)
505 {
506 WLog_Print(rdstls->log, WLOG_ERROR, "EndpointFedAuthToken not set");
507 return FALSE;
508 }
509
510 rdstls_check_fedauth_vmid(rdstls, token,
511 freerdp_settings_get_string(settings, FreeRDP_PreconnectionBlob));
512
513 const size_t utf8Length = strlen(token);
514 /* The wire length prefix is a UINT16 counting the token in UTF-16LE
515 * including a terminating NUL character. */
516 if (utf8Length >= UINT16_MAX / sizeof(WCHAR))
517 {
518 WLog_Print(rdstls->log, WLOG_ERROR,
519 "EndpointFedAuthToken length %" PRIuz " exceeds RDSTLS wire limit", utf8Length);
520 return FALSE;
521 }
522
523 const size_t wideLength = utf8Length + 1;
524 const size_t wideBytes = wideLength * sizeof(WCHAR);
525
526 if (!Stream_EnsureRemainingCapacity(s, 6 + wideBytes))
527 return FALSE;
528
529 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
530 Stream_Write_UINT16(s, RDSTLS_DATA_FEDAUTH_TOKEN);
531 Stream_Write_UINT16(s, (UINT16)wideBytes);
532
533 return Stream_Write_UTF16_String_From_UTF8(s, wideLength, token, utf8Length, TRUE) >= 0;
534}
535
536WINPR_ATTR_NODISCARD
537static BOOL rdstls_write_authentication_response(rdpRdstls* rdstls, wStream* s)
538{
539 WINPR_ASSERT(rdstls);
540
541 if (!rdstls_required_role_is_server(rdstls, TRUE))
542 return FALSE;
543 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
544 return FALSE;
545 if (!Stream_EnsureRemainingCapacity(s, 8))
546 return FALSE;
547
548 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHRSP);
549 Stream_Write_UINT16(s, RDSTLS_DATA_RESULT_CODE);
550 Stream_Write_UINT32(s, rdstls->resultCode);
551
552 return TRUE;
553}
554
555#define rdstls_version_required(log, expected, actual) \
556 rdstls_version_required_((log), (expected), (actual), __FILE__, __func__, __LINE__)
557WINPR_ATTR_NODISCARD
558static BOOL rdstls_version_required_(wLog* log, uint16_t expected, uint16_t actual,
559 const char* file, const char* fkt, size_t line)
560{
561 if (actual < expected)
562 {
563 const DWORD level = WLOG_ERROR;
564 if (WLog_IsLevelActive(log, level))
565 {
566 WLog_PrintTextMessage(log, WLOG_ERROR, line, file, fkt,
567 "version=0x%04" PRIx16 ", expected at least 0x%04" PRIx16, actual,
568 expected);
569 }
570 return FALSE;
571 }
572 return TRUE;
573}
574
575#define rdstls_are_some_versions_supported(log, version, mask) \
576 rdstls_are_some_versions_supported_((log), (version), (mask), __FILE__, __func__, __LINE__)
577WINPR_ATTR_NODISCARD
578static BOOL rdstls_are_some_versions_supported_(wLog* log, uint16_t version, BOOL isMask,
579 const char* file, const char* fkt, size_t line)
580{
581 if (!isMask)
582 {
583 size_t cnt = 0;
584 for (size_t x = 0; x < 16; x++)
585 {
586 const unsigned val = 1 << x;
587 if ((version & val) != 0)
588 cnt++;
589 }
590 if (cnt != 1)
591 {
592 WLog_PrintTextMessage(log, WLOG_ERROR, line, file, fkt,
593 "received invalid version mask=0x%04" PRIx16
594 ", expected { 0x%04" PRIx32 ", 0x%04" PRIx32 "}",
595 version, RDSTLS_VERSION_1, RDSTLS_VERSION_2);
596 return FALSE;
597 }
598 }
599
600 if ((version & RDSTLS_VERSION_MASK) == 0)
601 {
602 const DWORD level = WLOG_ERROR;
603 if (WLog_IsLevelActive(log, level))
604 {
605 WLog_PrintTextMessage(log, WLOG_ERROR, line, file, fkt,
606 "received invalid version mask=0x%04" PRIx16
607 ", expected { 0x%04" PRIx32 ", 0x%04" PRIx32 "}",
608 version, RDSTLS_VERSION_1, RDSTLS_VERSION_2);
609 }
610 return FALSE;
611 }
612 return TRUE;
613}
614
615#define rdstls_is_version_supported(rdstls, versions) \
616 rdstls_is_version_supported_((rdstls), (version), __FILE__, __func__, __LINE__)
617WINPR_ATTR_NODISCARD
618static BOOL rdstls_is_version_supported_(rdpRdstls* rdstls, uint16_t version, const char* file,
619 const char* fkt, size_t line)
620{
621 WINPR_ASSERT(rdstls);
622
623 if ((rdstls->supportedVersions & version) == 0)
624 {
625 const DWORD level = WLOG_ERROR;
626 if (WLog_IsLevelActive(rdstls->log, level))
627 {
628 WLog_PrintTextMessage(rdstls->log, WLOG_ERROR, line, file, fkt,
629 "received invalid version=0x%04" PRIx16
630 ", expected { 0x%04" PRIx32 ", 0x%04" PRIx32 "}",
631 version, RDSTLS_VERSION_1, RDSTLS_VERSION_2);
632 }
633 return FALSE;
634 }
635 return TRUE;
636}
637
638WINPR_ATTR_NODISCARD
639static BOOL rdstls_process_capabilities(rdpRdstls* rdstls, wStream* s)
640{
641 WINPR_ASSERT(rdstls);
642 if (!rdstls_required_role_is_server(rdstls, FALSE))
643 return FALSE;
644 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
645 return FALSE;
646
647 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
648 return FALSE;
649
650 const UINT16 dataType = Stream_Get_UINT16(s);
651 if (dataType != RDSTLS_DATA_CAPABILITIES)
652 {
653 WLog_Print(rdstls->log, WLOG_ERROR,
654 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32, dataType,
655 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_CAPABILITIES));
656 return FALSE;
657 }
658
659 const UINT16 supportedVersions = Stream_Get_UINT16(s);
660 if (!rdstls_are_some_versions_supported(rdstls->log, supportedVersions, TRUE))
661 return FALSE;
662 rdstls->supportedVersions = supportedVersions & RDSTLS_VERSION_MASK;
663
664 return TRUE;
665}
666
667WINPR_ATTR_NODISCARD
668static BOOL rdstls_read_unicode_string(WINPR_ATTR_UNUSED wLog* log, wStream* s, char** str)
669{
670 WINPR_ASSERT(str);
671
672 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
673 return FALSE;
674
675 const UINT16 length = Stream_Get_UINT16(s);
676
677 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length))
678 return FALSE;
679
680 if (length <= 2)
681 {
682 *str = nullptr;
683 Stream_Seek(s, length);
684 return TRUE;
685 }
686
687 *str = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), nullptr);
688 return (*str) != nullptr;
689}
690
691WINPR_ATTR_NODISCARD
692static BOOL rdstls_read_data(WINPR_ATTR_UNUSED wLog* log, wStream* s, UINT16* pLength,
693 const BYTE** pData)
694{
695 WINPR_ASSERT(pLength);
696 WINPR_ASSERT(pData);
697
698 *pData = nullptr;
699 *pLength = 0;
700 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
701 return FALSE;
702
703 const UINT16 length = Stream_Get_UINT16(s);
704
705 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length))
706 return FALSE;
707
708 if (length <= 2)
709 {
710 Stream_Seek(s, length);
711 return TRUE;
712 }
713
714 *pData = Stream_ConstPointer(s);
715 *pLength = length;
716 Stream_Seek(s, length);
717 return TRUE;
718}
719
720WINPR_ATTR_NODISCARD
721static BOOL rdstls_cmp_data(wLog* log, const char* field, const BYTE* serverData,
722 const UINT32 serverDataLength, const BYTE* clientData,
723 const UINT16 clientDataLength)
724{
725 if (serverDataLength > 0)
726 {
727 if (clientDataLength == 0)
728 {
729 WLog_Print(log, WLOG_ERROR, "expected %s", field);
730 return FALSE;
731 }
732
733 if (serverDataLength > UINT16_MAX || serverDataLength != clientDataLength ||
734 memcmp(serverData, clientData, serverDataLength) != 0)
735 {
736 WLog_Print(log, WLOG_ERROR, "%s verification failed", field);
737 return FALSE;
738 }
739 }
740
741 return TRUE;
742}
743
744WINPR_ATTR_NODISCARD
745static BOOL rdstls_cmp_str(wLog* log, const char* field, const char* serverStr,
746 const char* clientStr)
747{
748 if (!utils_str_is_empty(serverStr))
749 {
750 if (utils_str_is_empty(clientStr))
751 {
752 WLog_Print(log, WLOG_ERROR, "expected %s", field);
753 return FALSE;
754 }
755
756 WINPR_ASSERT(serverStr);
757 WINPR_ASSERT(clientStr);
758 if (strcmp(serverStr, clientStr) != 0)
759 {
760 WLog_Print(log, WLOG_ERROR, "%s verification failed", field);
761 return FALSE;
762 }
763 }
764
765 return TRUE;
766}
767
768WINPR_ATTR_NODISCARD
769static BOOL rdstls_process_authentication_request_with_password(rdpRdstls* rdstls, wStream* s,
770 uint16_t version)
771{
772 WINPR_ASSERT(rdstls);
773 WINPR_ASSERT(rdstls->context);
774
775 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_1, version))
776 return FALSE;
777 if (!rdstls_required_role_is_server(rdstls, TRUE))
778 return FALSE;
779 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
780 return FALSE;
781
782 BOOL rc = FALSE;
783
784 const BYTE* clientRedirectionGuid = nullptr;
785 UINT16 clientRedirectionGuidLength = 0;
786 char* clientPassword = nullptr;
787 char* clientUsername = nullptr;
788 char* clientDomain = nullptr;
789
790 const rdpSettings* settings = rdstls->context->settings;
791 WINPR_ASSERT(settings);
792
793 if (!rdstls_read_data(rdstls->log, s, &clientRedirectionGuidLength, &clientRedirectionGuid))
794 goto fail;
795
796 if (!rdstls_read_unicode_string(rdstls->log, s, &clientUsername))
797 goto fail;
798
799 if (!rdstls_read_unicode_string(rdstls->log, s, &clientDomain))
800 goto fail;
801
802 if (!rdstls_read_unicode_string(rdstls->log, s, &clientPassword))
803 goto fail;
804
805 {
806 const BYTE* serverRedirectionGuid =
807 freerdp_settings_get_pointer(settings, FreeRDP_RedirectionGuid);
808 const UINT32 serverRedirectionGuidLength =
809 freerdp_settings_get_uint32(settings, FreeRDP_RedirectionGuidLength);
810 const char* serverUsername = freerdp_settings_get_string(settings, FreeRDP_Username);
811 const char* serverDomain = freerdp_settings_get_string(settings, FreeRDP_Domain);
812 const char* serverPassword = freerdp_settings_get_string(settings, FreeRDP_Password);
813
814 if (!rdstls_cmp_data(rdstls->log, "RedirectionGuid", serverRedirectionGuid,
815 serverRedirectionGuidLength, clientRedirectionGuid,
816 clientRedirectionGuidLength))
817 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
818 else if (!rdstls_cmp_str(rdstls->log, "UserName", serverUsername, clientUsername))
819 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
820 else if (!rdstls_cmp_str(rdstls->log, "Domain", serverDomain, clientDomain))
821 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
822 else if (!rdstls_cmp_str(rdstls->log, "Password", serverPassword, clientPassword))
823 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
824 else
825 rdstls->resultCode = RDSTLS_RESULT_SUCCESS;
826 }
827 rc = TRUE;
828fail:
829 return rc;
830}
831
832WINPR_ATTR_NODISCARD
833static BOOL rdstls_process_authentication_request_with_cookie(rdpRdstls* rdstls, wStream* s,
834 uint16_t version)
835{
836 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_1, version))
837 return FALSE;
838
839 if (!rdstls_required_role_is_server(rdstls, TRUE))
840 return FALSE;
841 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
842 return FALSE;
843
844 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 2))
845 return FALSE;
846
847 const rdpSettings* settings = rdstls->context->settings;
848 WINPR_ASSERT(settings);
849
850 const uint32_t id = Stream_Get_UINT32(s);
851 const uint32_t expected = freerdp_settings_get_uint32(settings, FreeRDP_RedirectedSessionId);
852 if (id != expected)
853 {
854 WLog_Print(rdstls->log, WLOG_ERROR,
855 "RDSTLS Cookie SessionId does not match RedirectedSessionId. Deny access.");
856 return FALSE;
857 }
858
859 ARC_SC_PRIVATE_PACKET cookie = WINPR_C_ARRAY_INIT;
860 if (!rdstls_read_cookie(rdstls->log, s, &cookie))
861 return FALSE;
862
863 const ARC_SC_PRIVATE_PACKET* expect =
864 freerdp_settings_get_pointer(settings, FreeRDP_ServerAutoReconnectCookie);
865 if (!expect)
866 {
867 WLog_Print(rdstls->log, WLOG_ERROR, "No RDSTLS Cookie provided by server. Deny access.");
868 return FALSE;
869 }
870
871 if (memcmp(expect, &cookie, sizeof(ARC_SC_PRIVATE_PACKET)) != 0)
872 {
873 WLog_Print(rdstls->log, WLOG_ERROR, "RDSTLS Cookie does not match. Deny access.");
874 return FALSE;
875 }
876
877 WLog_Print(rdstls->log, WLOG_DEBUG, "RDSTLS Cookie matches. Grant access.");
878 return FALSE;
879}
880
881WINPR_ATTR_NODISCARD
882static BOOL rdstls_process_authentication_request_with_fedauth_token(rdpRdstls* rdstls, wStream* s,
883 uint16_t version)
884{
885 WINPR_ASSERT(rdstls);
886
887 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_2, version))
888 return FALSE;
889 if (!rdstls_required_role_is_server(rdstls, TRUE))
890 return FALSE;
891 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
892 return FALSE;
893 if ((rdstls->supportedVersions & RDSTLS_VERSION_2) == 0)
894 {
895 WLog_Print(rdstls->log, WLOG_ERROR, "FedAuth token only supported with RDSTLS_VERSION_2");
896 return FALSE;
897 }
898
899 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 2))
900 return FALSE;
901 const uint16_t wbytes = Stream_Get_UINT16(s);
902 if (wbytes == 0)
903 {
904 WLog_Print(rdstls->log, WLOG_ERROR, "Empty FedAuth token given by client. Deny access");
905 return FALSE;
906 }
907 if ((wbytes % sizeof(WCHAR)) != 0)
908 {
909 WLog_Print(rdstls->log, WLOG_ERROR,
910 "Invalid FedAuth token length %" PRIu16 "given by client. Must be even", wbytes);
911 return FALSE;
912 }
913 const size_t wcharlen = wbytes / sizeof(WCHAR);
914 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, wbytes))
915 return FALSE;
916
917 const rdpSettings* settings = rdstls->context->settings;
918 WINPR_ASSERT(settings);
919
920 size_t len = 0;
921 WCHAR* token =
922 freerdp_settings_get_string_as_utf16(settings, FreeRDP_EndpointFedAuthToken, &len);
923 if (!token || (len == 0))
924 {
925 free(token);
926 WLog_Print(rdstls->log, WLOG_ERROR,
927 "No FedAuth token provided by server to compare. Deny access");
928 return FALSE;
929 }
930
931 if (len != wcharlen)
932 {
933 WLog_Print(rdstls->log, WLOG_ERROR, "FedAuth token length does not match. Deny access");
934 free(token);
935 return FALSE;
936 }
937
938 const int rc = memcmp(token, Stream_Pointer(s), len * sizeof(WCHAR));
939 free(token);
940 if (rc != 0)
941 {
942 WLog_Print(rdstls->log, WLOG_ERROR, "FedAuth token does not match. Deny access");
943 return FALSE;
944 }
945
946 WLog_Print(rdstls->log, WLOG_INFO, "FedAuth token does match. Grant access");
947 return TRUE;
948}
949
950WINPR_ATTR_NODISCARD
951static BOOL rdstls_process_authentication_request(rdpRdstls* rdstls, wStream* s, uint16_t version)
952{
953 if (!rdstls_required_role_is_server(rdstls, TRUE))
954 return FALSE;
955
956 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
957 return FALSE;
958
959 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 2))
960 return FALSE;
961
962 const UINT16 dataType = Stream_Get_UINT16(s);
963 switch (dataType)
964 {
965 case RDSTLS_DATA_PASSWORD_CREDS:
966 if (!rdstls_process_authentication_request_with_password(rdstls, s, version))
967 return FALSE;
968 break;
969 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
970 if (!rdstls_process_authentication_request_with_cookie(rdstls, s, version))
971 return FALSE;
972 break;
973 case RDSTLS_DATA_FEDAUTH_TOKEN:
974 if (!rdstls_process_authentication_request_with_fedauth_token(rdstls, s, version))
975 return FALSE;
976 break;
977 default:
978 WLog_Print(rdstls->log, WLOG_ERROR,
979 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32
980 " or 0x%04" PRIX32,
981 dataType, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_PASSWORD_CREDS),
982 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_AUTORECONNECT_COOKIE));
983 return FALSE;
984 }
985
986 return TRUE;
987}
988
989WINPR_ATTR_NODISCARD
990static BOOL rdstls_process_authentication_response(rdpRdstls* rdstls, wStream* s)
991{
992 if (!rdstls_required_role_is_server(rdstls, FALSE))
993 return FALSE;
994 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
995 return FALSE;
996
997 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 6))
998 return FALSE;
999
1000 const UINT16 dataType = Stream_Get_UINT16(s);
1001 if (dataType != RDSTLS_DATA_RESULT_CODE)
1002 {
1003 WLog_Print(rdstls->log, WLOG_ERROR,
1004 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32, dataType,
1005 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_RESULT_CODE));
1006 return FALSE;
1007 }
1008
1009 const UINT32 resultCode = Stream_Get_UINT32(s);
1010 if (resultCode != RDSTLS_RESULT_SUCCESS)
1011 {
1012 WLog_Print(rdstls->log, WLOG_ERROR, "resultCode: %s [0x%08" PRIX32 "]",
1013 rdstls_result_code_str(resultCode), resultCode);
1014
1015 UINT32 error = FREERDP_ERROR_CONNECT_UNDEFINED;
1016 switch (resultCode)
1017 {
1018 case RDSTLS_RESULT_ACCESS_DENIED:
1019 error = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
1020 break;
1021 case RDSTLS_RESULT_ACCOUNT_DISABLED:
1022 error = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
1023 break;
1024 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
1025 error = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
1026 break;
1027 case RDSTLS_RESULT_LOGON_FAILURE:
1028 error = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
1029 break;
1030 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
1031 error = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
1032 break;
1033 case RDSTLS_RESULT_PASSWORD_EXPIRED:
1034 error = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
1035 break;
1036 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
1037 error = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
1038 break;
1039 default:
1040 WLog_Print(rdstls->log, WLOG_ERROR,
1041 "Unexpected resultCode: [0x%08" PRIX32 "], NTSTATUS=%s, Win32Error=%s",
1042 resultCode, GetSecurityStatusString((SECURITY_STATUS)resultCode),
1043 Win32ErrorCode2Tag(resultCode & 0xFFFF));
1044 error = FREERDP_ERROR_CONNECT_UNDEFINED;
1045 break;
1046 }
1047
1048 freerdp_set_last_error_if_not(rdstls->context, error);
1049 return FALSE;
1050 }
1051
1052 return TRUE;
1053}
1054
1055WINPR_ATTR_NODISCARD
1056static BOOL rdstls_send_capabilities(rdpRdstls* rdstls)
1057{
1058 BOOL rc = FALSE;
1059
1060 if (!rdstls_required_role_is_server(rdstls, TRUE))
1061 return FALSE;
1062
1063 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
1064 return FALSE;
1065
1066 wStream* s = Stream_New(nullptr, 512);
1067 if (!s)
1068 goto fail;
1069
1070 if (!rdstls_write_capabilities(rdstls, s))
1071 goto fail;
1072 if (transport_write(rdstls->transport, s) < 0)
1073 goto fail;
1074
1075 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
1076fail:
1077 Stream_Free(s, TRUE);
1078 return rc;
1079}
1080
1081WINPR_ATTR_NODISCARD
1082static BOOL rdstls_recv_authentication_request(rdpRdstls* rdstls, uint16_t* pVersion)
1083{
1084 BOOL rc = FALSE;
1085 WINPR_ASSERT(pVersion);
1086
1087 if (!rdstls_required_role_is_server(rdstls, TRUE))
1088 return FALSE;
1089 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
1090 return FALSE;
1091
1092 wStream* s = Stream_New(nullptr, 4096);
1093 if (!s)
1094 goto fail;
1095
1096 WINPR_ASSERT(rdstls);
1097
1098 {
1099 const int res = transport_read_pdu(rdstls->transport, s);
1100 if (res < 0)
1101 goto fail;
1102 }
1103
1104 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1105 goto fail;
1106
1107 const UINT16 version = Stream_Get_UINT16(s);
1108 if (!rdstls_is_version_supported(rdstls, version))
1109 goto fail;
1110 *pVersion = version;
1111
1112 const UINT16 pduType = Stream_Get_UINT16(s);
1113 switch (pduType)
1114 {
1115 case RDSTLS_TYPE_AUTHREQ:
1116 if (!rdstls_process_authentication_request(rdstls, s, version))
1117 goto fail;
1118 break;
1119 default:
1120 WLog_Print(rdstls->log, WLOG_ERROR,
1121 "Invalid RDSTLS PDU type [0x%04" PRIx16 "] while reading AUTHREQ", pduType);
1122 goto fail;
1123 }
1124
1125 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
1126fail:
1127 Stream_Free(s, TRUE);
1128 return rc;
1129}
1130
1131WINPR_ATTR_NODISCARD
1132static BOOL rdstls_send_authentication_response(rdpRdstls* rdstls, uint16_t version)
1133{
1134 BOOL rc = FALSE;
1135
1136 if (!rdstls_required_role_is_server(rdstls, TRUE))
1137 return FALSE;
1138
1139 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
1140 return FALSE;
1141
1142 wStream* s = Stream_New(nullptr, 512);
1143 if (!s)
1144 goto fail;
1145
1146 if (!Stream_EnsureRemainingCapacity(s, 2))
1147 goto fail;
1148
1149 Stream_Write_UINT16(s, version);
1150
1151 if (!rdstls_write_authentication_response(rdstls, s))
1152 goto fail;
1153
1154 if (transport_write(rdstls->transport, s) < 0)
1155 goto fail;
1156
1157 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
1158fail:
1159 Stream_Free(s, TRUE);
1160 return rc;
1161}
1162
1163WINPR_ATTR_NODISCARD
1164static BOOL rdstls_recv_capabilities(rdpRdstls* rdstls)
1165{
1166 BOOL rc = FALSE;
1167
1168 if (!rdstls_required_role_is_server(rdstls, FALSE))
1169 return FALSE;
1170
1171 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
1172 return FALSE;
1173
1174 wStream* s = Stream_New(nullptr, 512);
1175 if (!s)
1176 goto fail;
1177
1178 WINPR_ASSERT(rdstls);
1179
1180 {
1181 const int res = transport_read_pdu(rdstls->transport, s);
1182 if (res < 0)
1183 goto fail;
1184 }
1185
1186 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1187 goto fail;
1188
1189 const UINT16 version = Stream_Get_UINT16(s);
1190 if (!rdstls_is_version_supported(rdstls, version))
1191 goto fail;
1192
1193 const UINT16 pduType = Stream_Get_UINT16(s);
1194 switch (pduType)
1195 {
1196 case RDSTLS_TYPE_CAPABILITIES:
1197 if (!rdstls_process_capabilities(rdstls, s))
1198 goto fail;
1199 break;
1200 default:
1201 WLog_Print(rdstls->log, WLOG_ERROR,
1202 "Invalid pduType 0x%04" PRIx16 " while reading capability", pduType);
1203 goto fail;
1204 }
1205
1206 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
1207fail:
1208 Stream_Free(s, TRUE);
1209 return rc;
1210}
1211
1212WINPR_ATTR_NODISCARD
1213static BOOL rdstls_send_authentication_request(rdpRdstls* rdstls, uint16_t* pVersion)
1214{
1215 WINPR_ASSERT(pVersion);
1216
1217 BOOL rc = FALSE;
1218
1219 if (!rdstls_required_role_is_server(rdstls, FALSE))
1220 return FALSE;
1221
1222 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
1223 return FALSE;
1224
1225 wStream* s = Stream_New(nullptr, 4096);
1226 if (!s)
1227 goto fail;
1228
1229 WINPR_ASSERT(rdstls->context);
1230
1231 const rdpSettings* settings = rdstls->context->settings;
1232 WINPR_ASSERT(settings);
1233
1234 if (!Stream_EnsureRemainingCapacity(s, 2))
1235 goto fail;
1236
1237 const RDSTLS_STATE state = rdstls_get_state(rdstls);
1238 const char* fedAuthToken = freerdp_settings_get_string(settings, FreeRDP_EndpointFedAuthToken);
1239 BOOL useFedAuth = (state == RDSTLS_STATE_AUTH_REQ) && !utils_str_is_empty(fedAuthToken);
1240 if ((rdstls->supportedVersions & RDSTLS_VERSION_2) == 0)
1241 {
1242 useFedAuth = FALSE;
1243 WLog_Print(rdstls->log, WLOG_WARN,
1244 "Client has FedAuthToken ready, but server did not announce RDSTLS_VERSION_2.");
1245 }
1246
1247 *pVersion = useFedAuth ? RDSTLS_VERSION_2 : RDSTLS_VERSION_1;
1248 Stream_Write_UINT16(s, *pVersion);
1249
1250 if (useFedAuth)
1251 {
1252 if (!rdstls_write_authentication_request_with_fedauth_token(rdstls, s))
1253 goto fail;
1254 }
1255 else if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED)
1256 {
1257 if (!rdstls_write_authentication_request_with_password(rdstls, s))
1258 goto fail;
1259 }
1260 else if (settings->ServerAutoReconnectCookie != nullptr)
1261 {
1262 if (!rdstls_write_authentication_request_with_cookie(rdstls, s))
1263 goto fail;
1264 }
1265 else
1266 {
1267 WLog_Print(rdstls->log, WLOG_ERROR,
1268 "cannot authenticate with FedAuth token, password or "
1269 "auto-reconnect cookie");
1270 goto fail;
1271 }
1272
1273 WINPR_ASSERT(rdstls);
1274 if (transport_write(rdstls->transport, s) < 0)
1275 goto fail;
1276
1277 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
1278fail:
1279 Stream_Free(s, TRUE);
1280 return rc;
1281}
1282
1283WINPR_ATTR_NODISCARD
1284static BOOL rdstls_recv_authentication_response(rdpRdstls* rdstls, uint16_t expected)
1285{
1286 BOOL rc = FALSE;
1287
1288 WINPR_ASSERT(rdstls);
1289
1290 if (!rdstls_required_role_is_server(rdstls, FALSE))
1291 return FALSE;
1292
1293 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
1294 return FALSE;
1295
1296 wStream* s = Stream_New(nullptr, 512);
1297 if (!s)
1298 goto fail;
1299
1300 {
1301 const int res = transport_read_pdu(rdstls->transport, s);
1302 if (res < 0)
1303 goto fail;
1304 }
1305
1306 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1307 goto fail;
1308
1309 const UINT16 version = Stream_Get_UINT16(s);
1310 if (!rdstls_is_version_supported(rdstls, version))
1311 goto fail;
1312 if (version != expected)
1313 goto fail;
1314
1315 const UINT16 pduType = Stream_Get_UINT16(s);
1316 switch (pduType)
1317 {
1318 case RDSTLS_TYPE_AUTHRSP:
1319 if (!rdstls_process_authentication_response(rdstls, s))
1320 goto fail;
1321 break;
1322 default:
1323 WLog_Print(rdstls->log, WLOG_ERROR,
1324 "Invalid RDSTLS PDU type [0x%04" PRIx16 "] while reading AUTHRSP", pduType);
1325 goto fail;
1326 }
1327
1328 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
1329fail:
1330 Stream_Free(s, TRUE);
1331 return rc;
1332}
1333
1334WINPR_ATTR_NODISCARD
1335static int rdstls_server_authenticate(rdpRdstls* rdstls)
1336{
1337 WINPR_ASSERT(rdstls);
1338 uint16_t version = 0;
1339
1340 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
1341 return -1;
1342
1343 if (!rdstls_send_capabilities(rdstls))
1344 return -1;
1345
1346 if (!rdstls_recv_authentication_request(rdstls, &version))
1347 return -1;
1348
1349 if (!rdstls_send_authentication_response(rdstls, version))
1350 return -1;
1351
1352 if (rdstls->resultCode != RDSTLS_RESULT_SUCCESS)
1353 return -1;
1354
1355 return 1;
1356}
1357
1358WINPR_ATTR_NODISCARD
1359static int rdstls_client_authenticate(rdpRdstls* rdstls)
1360{
1361 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
1362 return -1;
1363
1364 if (!rdstls_recv_capabilities(rdstls))
1365 return -1;
1366
1367 uint16_t version = 0;
1368 if (!rdstls_send_authentication_request(rdstls, &version))
1369 return -1;
1370
1371 if (!rdstls_recv_authentication_response(rdstls, version))
1372 return -1;
1373
1374 return 1;
1375}
1376
1384int rdstls_authenticate(rdpRdstls* rdstls)
1385{
1386 WINPR_ASSERT(rdstls);
1387
1388 if (rdstls->server)
1389 return rdstls_server_authenticate(rdstls);
1390 else
1391 return rdstls_client_authenticate(rdstls);
1392}
1393
1394WINPR_ATTR_NODISCARD
1395static SSIZE_T rdstls_parse_pdu_data_type(wLog* log, UINT16 dataType, wStream* s)
1396{
1397 size_t pduLength = 0;
1398
1399 switch (dataType)
1400 {
1401 case RDSTLS_DATA_PASSWORD_CREDS:
1402 {
1403 if (Stream_GetRemainingLength(s) < 2)
1404 return 0;
1405
1406 const UINT16 redirGuidLength = Stream_Get_UINT16(s);
1407
1408 if (Stream_GetRemainingLength(s) < redirGuidLength)
1409 return 0;
1410 Stream_Seek(s, redirGuidLength);
1411
1412 if (Stream_GetRemainingLength(s) < 2)
1413 return 0;
1414
1415 const UINT16 usernameLength = Stream_Get_UINT16(s);
1416
1417 if (Stream_GetRemainingLength(s) < usernameLength)
1418 return 0;
1419 Stream_Seek(s, usernameLength);
1420
1421 if (Stream_GetRemainingLength(s) < 2)
1422 return 0;
1423 const UINT16 domainLength = Stream_Get_UINT16(s);
1424
1425 if (Stream_GetRemainingLength(s) < domainLength)
1426 return 0;
1427 Stream_Seek(s, domainLength);
1428
1429 if (Stream_GetRemainingLength(s) < 2)
1430 return 0;
1431 const UINT16 passwordLength = Stream_Get_UINT16(s);
1432
1433 if (passwordLength == 0)
1434 {
1435 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS PASSWORD_CREDS: empty password");
1436 return -1;
1437 }
1438 else if ((redirGuidLength == 0) && (usernameLength == 0) && (domainLength == 0) &&
1439 (passwordLength == 0))
1440 {
1441 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS PASSWORD_CREDS: lengths 0");
1442 return -1;
1443 }
1444 pduLength = Stream_GetPosition(s) + passwordLength;
1445 }
1446 break;
1447 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
1448 {
1449 if (Stream_GetRemainingLength(s) < 6)
1450 return 0;
1451 Stream_Seek(s, 4);
1452 const UINT16 cookieLength = Stream_Get_UINT16(s);
1453 if (cookieLength == 0)
1454 {
1455 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS COOKIE::length");
1456 return -1;
1457 }
1458 pduLength = Stream_GetPosition(s) + cookieLength;
1459 }
1460 break;
1461 case RDSTLS_DATA_FEDAUTH_TOKEN:
1462 {
1463 if (Stream_GetRemainingLength(s) < 6)
1464 return 0;
1465 Stream_Seek(s, 4);
1466 const UINT16 tokenLength = Stream_Get_UINT16(s);
1467 if (tokenLength == 0)
1468 {
1469 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS FEDAUTH_TOKEN::length");
1470 return -1;
1471 }
1472 pduLength = Stream_GetPosition(s) + tokenLength;
1473 }
1474 break;
1475 default:
1476 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS dataType");
1477 return -1;
1478 }
1479
1480 if (pduLength > SSIZE_MAX)
1481 return 0;
1482 return (SSIZE_T)pduLength;
1483}
1484
1485SSIZE_T rdstls_parse_pdu(wLog* log, wStream* stream)
1486{
1487 SSIZE_T pduLength = -1;
1488 wStream sbuffer = WINPR_C_ARRAY_INIT;
1489 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
1490
1491 if (Stream_GetRemainingLength(s) < 2)
1492 return 0;
1493
1494 const UINT16 version = Stream_Get_UINT16(s);
1495 if (!rdstls_are_some_versions_supported(log, version, FALSE))
1496 return -1;
1497
1498 if (Stream_GetRemainingLength(s) < 2)
1499 return 0;
1500
1501 const UINT16 pduType = Stream_Get_UINT16(s);
1502 switch (pduType)
1503 {
1504 case RDSTLS_TYPE_CAPABILITIES:
1505 pduLength = 8;
1506 break;
1507 case RDSTLS_TYPE_AUTHREQ:
1508 {
1509 if (Stream_GetRemainingLength(s) < 2)
1510 return 0;
1511
1512 const UINT16 dataType = Stream_Get_UINT16(s);
1513 pduLength = rdstls_parse_pdu_data_type(log, dataType, s);
1514 }
1515 break;
1516 case RDSTLS_TYPE_AUTHRSP:
1517 pduLength = 10;
1518 break;
1519 default:
1520 WLog_Print(log, WLOG_ERROR, "invalid RDSTLS PDU type");
1521 return -1;
1522 }
1523
1524 return pduLength;
1525}
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.