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 SSIZE_T wideLength = ConvertUtf8NToWChar(token, utf8Length, nullptr, 0);
524 if (wideLength < 0)
525 return FALSE;
526 const size_t wideLengthZero = WINPR_ASSERTING_INT_CAST(size_t, wideLength);
527 const size_t wideBytes = (wideLengthZero + 1ull) * sizeof(WCHAR);
528
529 if (!Stream_EnsureRemainingCapacity(s, 6ull + wideBytes))
530 return FALSE;
531
532 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
533 Stream_Write_UINT16(s, RDSTLS_DATA_FEDAUTH_TOKEN);
534 Stream_Write_UINT16(s, (UINT16)wideBytes);
535
536 return Stream_Write_UTF16_String_From_UTF8(s, wideLengthZero, token, utf8Length, TRUE) >= 0;
537}
538
539WINPR_ATTR_NODISCARD
540static BOOL rdstls_write_authentication_response(rdpRdstls* rdstls, wStream* s)
541{
542 WINPR_ASSERT(rdstls);
543
544 if (!rdstls_required_role_is_server(rdstls, TRUE))
545 return FALSE;
546 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
547 return FALSE;
548 if (!Stream_EnsureRemainingCapacity(s, 8))
549 return FALSE;
550
551 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHRSP);
552 Stream_Write_UINT16(s, RDSTLS_DATA_RESULT_CODE);
553 Stream_Write_UINT32(s, rdstls->resultCode);
554
555 return TRUE;
556}
557
558#define rdstls_version_required(log, expected, actual) \
559 rdstls_version_required_((log), (expected), (actual), __FILE__, __func__, __LINE__)
560WINPR_ATTR_NODISCARD
561static BOOL rdstls_version_required_(wLog* log, uint16_t expected, uint16_t actual,
562 const char* file, const char* fkt, size_t line)
563{
564 if (actual < expected)
565 {
566 const DWORD level = WLOG_ERROR;
567 if (WLog_IsLevelActive(log, level))
568 {
569 WLog_PrintTextMessage(log, WLOG_ERROR, line, file, fkt,
570 "version=0x%04" PRIx16 ", expected at least 0x%04" PRIx16, actual,
571 expected);
572 }
573 return FALSE;
574 }
575 return TRUE;
576}
577
578#define rdstls_are_some_versions_supported(log, version, mask) \
579 rdstls_are_some_versions_supported_((log), (version), (mask), __FILE__, __func__, __LINE__)
580WINPR_ATTR_NODISCARD
581static BOOL rdstls_are_some_versions_supported_(wLog* log, uint16_t version, BOOL isMask,
582 const char* file, const char* fkt, size_t line)
583{
584 if (!isMask)
585 {
586 size_t cnt = 0;
587 for (size_t x = 0; x < 16; x++)
588 {
589 const unsigned val = 1 << x;
590 if ((version & val) != 0)
591 cnt++;
592 }
593 if (cnt != 1)
594 {
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);
599 return FALSE;
600 }
601 }
602
603 if ((version & RDSTLS_VERSION_MASK) == 0)
604 {
605 const DWORD level = WLOG_ERROR;
606 if (WLog_IsLevelActive(log, level))
607 {
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);
612 }
613 return FALSE;
614 }
615 return TRUE;
616}
617
618#define rdstls_is_version_supported(rdstls, version) \
619 rdstls_is_version_supported_((rdstls), (version), __FILE__, __func__, __LINE__)
620WINPR_ATTR_NODISCARD
621static BOOL rdstls_is_version_supported_(rdpRdstls* rdstls, uint16_t version, const char* file,
622 const char* fkt, size_t line)
623{
624 WINPR_ASSERT(rdstls);
625
626 if ((rdstls->supportedVersions & version) == 0)
627 {
628 const DWORD level = WLOG_ERROR;
629 if (WLog_IsLevelActive(rdstls->log, level))
630 {
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);
635 }
636 return FALSE;
637 }
638 return TRUE;
639}
640
641WINPR_ATTR_NODISCARD
642static BOOL rdstls_process_capabilities(rdpRdstls* rdstls, wStream* s)
643{
644 WINPR_ASSERT(rdstls);
645 if (!rdstls_required_role_is_server(rdstls, FALSE))
646 return FALSE;
647 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
648 return FALSE;
649
650 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
651 return FALSE;
652
653 const UINT16 dataType = Stream_Get_UINT16(s);
654 if (dataType != RDSTLS_DATA_CAPABILITIES)
655 {
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));
659 return FALSE;
660 }
661
662 const UINT16 supportedVersions = Stream_Get_UINT16(s);
663 if (!rdstls_are_some_versions_supported(rdstls->log, supportedVersions, TRUE))
664 return FALSE;
665 rdstls->supportedVersions = supportedVersions & RDSTLS_VERSION_MASK;
666
667 return TRUE;
668}
669
670WINPR_ATTR_NODISCARD
671static BOOL rdstls_read_unicode_string(WINPR_ATTR_UNUSED wLog* log, wStream* s, char** str)
672{
673 WINPR_ASSERT(str);
674
675 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
676 return FALSE;
677
678 const UINT16 length = Stream_Get_UINT16(s);
679
680 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length))
681 return FALSE;
682
683 if (length <= 2)
684 {
685 *str = nullptr;
686 Stream_Seek(s, length);
687 return TRUE;
688 }
689
690 *str = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), nullptr);
691 return (*str) != nullptr;
692}
693
694WINPR_ATTR_NODISCARD
695static BOOL rdstls_read_data(WINPR_ATTR_UNUSED wLog* log, wStream* s, UINT16* pLength,
696 const BYTE** pData)
697{
698 WINPR_ASSERT(pLength);
699 WINPR_ASSERT(pData);
700
701 *pData = nullptr;
702 *pLength = 0;
703 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
704 return FALSE;
705
706 const UINT16 length = Stream_Get_UINT16(s);
707
708 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, length))
709 return FALSE;
710
711 if (length <= 2)
712 {
713 Stream_Seek(s, length);
714 return TRUE;
715 }
716
717 *pData = Stream_ConstPointer(s);
718 *pLength = length;
719 Stream_Seek(s, length);
720 return TRUE;
721}
722
723WINPR_ATTR_NODISCARD
724static BOOL rdstls_cmp_data(wLog* log, const char* field, const BYTE* serverData,
725 const UINT32 serverDataLength, const BYTE* clientData,
726 const UINT16 clientDataLength)
727{
728 if (serverDataLength == 0)
729 {
730 WLog_Print(log, WLOG_DEBUG, "serverDataLength == 0, nothing to compare. ignore");
731 return TRUE;
732 }
733
734 if (clientDataLength == 0)
735 {
736 WLog_Print(log, WLOG_ERROR, "expected %s", field);
737 return FALSE;
738 }
739
740 if ((serverDataLength > UINT16_MAX) || (serverDataLength != clientDataLength) ||
741 (memcmp(serverData, clientData, serverDataLength) != 0))
742 {
743 WLog_Print(log, WLOG_ERROR, "%s verification failed", field);
744 return FALSE;
745 }
746
747 /* Discard a server field that was not initialized */
748 for (size_t x = 0; x < serverDataLength; x++)
749 {
750 if (serverData[x] != 0)
751 return TRUE;
752 }
753
754 WLog_Print(log, WLOG_ERROR, "serverData not initialized, reject");
755 return FALSE;
756}
757
758WINPR_ATTR_NODISCARD
759static BOOL rdstls_cmp_str(wLog* log, const char* field, const char* serverStr,
760 const char* clientStr)
761{
762 if (!utils_str_is_empty(serverStr))
763 {
764 if (utils_str_is_empty(clientStr))
765 {
766 WLog_Print(log, WLOG_ERROR, "expected %s", field);
767 return FALSE;
768 }
769
770 WINPR_ASSERT(serverStr);
771 WINPR_ASSERT(clientStr);
772 if (strcmp(serverStr, clientStr) != 0)
773 {
774 WLog_Print(log, WLOG_ERROR, "%s verification failed", field);
775 return FALSE;
776 }
777 }
778
779 return TRUE;
780}
781
782WINPR_ATTR_NODISCARD
783static BOOL rdstls_process_authentication_request_with_password(rdpRdstls* rdstls, wStream* s,
784 uint16_t version)
785{
786 WINPR_ASSERT(rdstls);
787 WINPR_ASSERT(rdstls->context);
788
789 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_1, version))
790 return FALSE;
791 if (!rdstls_required_role_is_server(rdstls, TRUE))
792 return FALSE;
793 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
794 return FALSE;
795
796 BOOL rc = FALSE;
797
798 const BYTE* clientRedirectionGuid = nullptr;
799 UINT16 clientRedirectionGuidLength = 0;
800 char* clientPassword = nullptr;
801 char* clientUsername = nullptr;
802 char* clientDomain = nullptr;
803
804 const rdpSettings* settings = rdstls->context->settings;
805 WINPR_ASSERT(settings);
806
807 if (!rdstls_read_data(rdstls->log, s, &clientRedirectionGuidLength, &clientRedirectionGuid))
808 goto fail;
809
810 if (!rdstls_read_unicode_string(rdstls->log, s, &clientUsername))
811 goto fail;
812
813 if (!rdstls_read_unicode_string(rdstls->log, s, &clientDomain))
814 goto fail;
815
816 if (!rdstls_read_unicode_string(rdstls->log, s, &clientPassword))
817 goto fail;
818
819 {
820 const BYTE* serverRedirectionGuid =
821 freerdp_settings_get_pointer(settings, FreeRDP_RedirectionGuid);
822 const UINT32 serverRedirectionGuidLength =
823 freerdp_settings_get_uint32(settings, FreeRDP_RedirectionGuidLength);
824 const char* serverUsername = freerdp_settings_get_string(settings, FreeRDP_Username);
825 const char* serverDomain = freerdp_settings_get_string(settings, FreeRDP_Domain);
826 const char* serverPassword = freerdp_settings_get_string(settings, FreeRDP_Password);
827
828 if (!rdstls_cmp_data(rdstls->log, "RedirectionGuid", serverRedirectionGuid,
829 serverRedirectionGuidLength, clientRedirectionGuid,
830 clientRedirectionGuidLength))
831 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
832 else if (!rdstls_cmp_str(rdstls->log, "UserName", serverUsername, clientUsername))
833 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
834 else if (!rdstls_cmp_str(rdstls->log, "Domain", serverDomain, clientDomain))
835 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
836 else if (utils_str_is_empty(serverPassword))
837 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
838 else if (!rdstls_cmp_str(rdstls->log, "Password", serverPassword, clientPassword))
839 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
840 else
841 rdstls->resultCode = RDSTLS_RESULT_SUCCESS;
842 }
843 rc = TRUE;
844fail:
845 return rc;
846}
847
848WINPR_ATTR_NODISCARD
849static BOOL rdstls_process_authentication_request_with_cookie(rdpRdstls* rdstls, wStream* s,
850 uint16_t version)
851{
852 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_1, version))
853 return FALSE;
854
855 if (!rdstls_required_role_is_server(rdstls, TRUE))
856 return FALSE;
857 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
858 return FALSE;
859
860 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
861 return FALSE;
862
863 const rdpSettings* settings = rdstls->context->settings;
864 WINPR_ASSERT(settings);
865
866 const uint32_t id = Stream_Get_UINT32(s);
867 const uint32_t expected = freerdp_settings_get_uint32(settings, FreeRDP_RedirectedSessionId);
868 if (id != expected)
869 {
870 WLog_Print(rdstls->log, WLOG_ERROR,
871 "RDSTLS Cookie SessionId does not match RedirectedSessionId. Deny access.");
872 return FALSE;
873 }
874
875 ARC_SC_PRIVATE_PACKET cookie = WINPR_C_ARRAY_INIT;
876 if (!rdstls_read_cookie(rdstls->log, s, &cookie))
877 return FALSE;
878
879 const ARC_SC_PRIVATE_PACKET empty = WINPR_C_ARRAY_INIT;
880 const ARC_SC_PRIVATE_PACKET* expect =
881 freerdp_settings_get_pointer(settings, FreeRDP_ServerAutoReconnectCookie);
882 if (!expect || (memcmp(expect, &empty, sizeof(ARC_SC_PRIVATE_PACKET)) == 0))
883 {
884 WLog_Print(rdstls->log, WLOG_ERROR, "No RDSTLS Cookie provided by server. Deny access.");
885 return FALSE;
886 }
887
888 if (memcmp(expect, &cookie, sizeof(ARC_SC_PRIVATE_PACKET)) != 0)
889 {
890 WLog_Print(rdstls->log, WLOG_ERROR, "RDSTLS Cookie does not match. Deny access.");
891 return FALSE;
892 }
893
894 WLog_Print(rdstls->log, WLOG_DEBUG, "RDSTLS Cookie matches. Grant access.");
895 rdstls->resultCode = RDSTLS_RESULT_SUCCESS;
896 return TRUE;
897}
898
899WINPR_ATTR_NODISCARD
900static BOOL rdstls_process_authentication_request_with_fedauth_token(rdpRdstls* rdstls, wStream* s,
901 uint16_t version)
902{
903 WINPR_ASSERT(rdstls);
904
905 if (!rdstls_version_required(rdstls->log, RDSTLS_VERSION_2, version))
906 return FALSE;
907 if (!rdstls_required_role_is_server(rdstls, TRUE))
908 return FALSE;
909 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
910 return FALSE;
911 if ((rdstls->supportedVersions & RDSTLS_VERSION_2) == 0)
912 {
913 WLog_Print(rdstls->log, WLOG_ERROR, "FedAuth token only supported with RDSTLS_VERSION_2");
914 return FALSE;
915 }
916
917 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 2))
918 return FALSE;
919 const uint16_t wbytes = Stream_Get_UINT16(s);
920 if (wbytes == 0)
921 {
922 WLog_Print(rdstls->log, WLOG_ERROR, "Empty FedAuth token given by client. Deny access");
923 return FALSE;
924 }
925 if ((wbytes % sizeof(WCHAR)) != 0)
926 {
927 WLog_Print(rdstls->log, WLOG_ERROR,
928 "Invalid FedAuth token length %" PRIu16 "given by client. Must be even", wbytes);
929 return FALSE;
930 }
931 const size_t wcharlen = wbytes / sizeof(WCHAR);
932 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, wbytes))
933 return FALSE;
934
935 const rdpSettings* settings = rdstls->context->settings;
936 WINPR_ASSERT(settings);
937
938 size_t len = 0;
939 WCHAR* token =
940 freerdp_settings_get_string_as_utf16(settings, FreeRDP_EndpointFedAuthToken, &len);
941 if (!token || (len == 0))
942 {
943 free(token);
944 WLog_Print(rdstls->log, WLOG_ERROR,
945 "No FedAuth token provided by server to compare. Deny access");
946 return FALSE;
947 }
948
949 if (len != wcharlen)
950 {
951 WLog_Print(rdstls->log, WLOG_ERROR, "FedAuth token length does not match. Deny access");
952 free(token);
953 return FALSE;
954 }
955
956 const int rc = memcmp(token, Stream_Pointer(s), len * sizeof(WCHAR));
957 free(token);
958 if (rc != 0)
959 {
960 WLog_Print(rdstls->log, WLOG_ERROR, "FedAuth token does not match. Deny access");
961 return FALSE;
962 }
963
964 WLog_Print(rdstls->log, WLOG_INFO, "FedAuth token does match. Grant access");
965 return TRUE;
966}
967
968WINPR_ATTR_NODISCARD
969static BOOL rdstls_process_authentication_request(rdpRdstls* rdstls, wStream* s, uint16_t version)
970{
971 if (!rdstls_required_role_is_server(rdstls, TRUE))
972 return FALSE;
973
974 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
975 return FALSE;
976
977 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 2))
978 return FALSE;
979
980 const UINT16 dataType = Stream_Get_UINT16(s);
981 const UINT32 allowedDataTypes =
982 freerdp_settings_get_uint32(rdstls->context->settings, FreeRDP_RdstlsEnabledModes);
983 if ((dataType > 31) || ((allowedDataTypes & (1 << dataType)) == 0))
984 {
985 WLog_Print(rdstls->log, WLOG_ERROR,
986 "dataType=0x%08" PRIx32 ", allowedDataTypes=0x%08" PRIx32 ", deny", dataType,
987 allowedDataTypes);
988 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
989 return TRUE;
990 }
991
992 switch (dataType)
993 {
994 case RDSTLS_DATA_PASSWORD_CREDS:
995 if (!rdstls_process_authentication_request_with_password(rdstls, s, version))
996 return FALSE;
997 break;
998 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
999 if (!rdstls_process_authentication_request_with_cookie(rdstls, s, version))
1000 return FALSE;
1001 break;
1002 case RDSTLS_DATA_FEDAUTH_TOKEN:
1003 if (!rdstls_process_authentication_request_with_fedauth_token(rdstls, s, version))
1004 return FALSE;
1005 break;
1006 default:
1007 WLog_Print(rdstls->log, WLOG_ERROR,
1008 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32
1009 " or 0x%04" PRIX32,
1010 dataType, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_PASSWORD_CREDS),
1011 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_AUTORECONNECT_COOKIE));
1012 return FALSE;
1013 }
1014
1015 return TRUE;
1016}
1017
1018WINPR_ATTR_NODISCARD
1019static BOOL rdstls_process_authentication_response(rdpRdstls* rdstls, wStream* s)
1020{
1021 if (!rdstls_required_role_is_server(rdstls, FALSE))
1022 return FALSE;
1023 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
1024 return FALSE;
1025
1026 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 6))
1027 return FALSE;
1028
1029 const UINT16 dataType = Stream_Get_UINT16(s);
1030 if (dataType != RDSTLS_DATA_RESULT_CODE)
1031 {
1032 WLog_Print(rdstls->log, WLOG_ERROR,
1033 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32, dataType,
1034 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_RESULT_CODE));
1035 return FALSE;
1036 }
1037
1038 const UINT32 resultCode = Stream_Get_UINT32(s);
1039 if (resultCode != RDSTLS_RESULT_SUCCESS)
1040 {
1041 WLog_Print(rdstls->log, WLOG_ERROR, "resultCode: %s [0x%08" PRIX32 "]",
1042 rdstls_result_code_str(resultCode), resultCode);
1043
1044 UINT32 error = FREERDP_ERROR_CONNECT_UNDEFINED;
1045 switch (resultCode)
1046 {
1047 case RDSTLS_RESULT_ACCESS_DENIED:
1048 error = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
1049 break;
1050 case RDSTLS_RESULT_ACCOUNT_DISABLED:
1051 error = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
1052 break;
1053 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
1054 error = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
1055 break;
1056 case RDSTLS_RESULT_LOGON_FAILURE:
1057 error = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
1058 break;
1059 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
1060 error = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
1061 break;
1062 case RDSTLS_RESULT_PASSWORD_EXPIRED:
1063 error = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
1064 break;
1065 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
1066 error = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
1067 break;
1068 default:
1069 WLog_Print(rdstls->log, WLOG_ERROR,
1070 "Unexpected resultCode: [0x%08" PRIX32 "], NTSTATUS=%s, Win32Error=%s",
1071 resultCode, GetSecurityStatusString((SECURITY_STATUS)resultCode),
1072 Win32ErrorCode2Tag(resultCode & 0xFFFF));
1073 error = FREERDP_ERROR_CONNECT_UNDEFINED;
1074 break;
1075 }
1076
1077 freerdp_set_last_error_if_not(rdstls->context, error);
1078 return FALSE;
1079 }
1080
1081 return TRUE;
1082}
1083
1084WINPR_ATTR_NODISCARD
1085static BOOL rdstls_send_capabilities(rdpRdstls* rdstls)
1086{
1087 BOOL rc = FALSE;
1088
1089 if (!rdstls_required_role_is_server(rdstls, TRUE))
1090 return FALSE;
1091
1092 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
1093 return FALSE;
1094
1095 wStream* s = Stream_New(nullptr, 512);
1096 if (!s)
1097 goto fail;
1098
1099 if (!rdstls_write_capabilities(rdstls, s))
1100 goto fail;
1101 if (transport_write(rdstls->transport, s) < 0)
1102 goto fail;
1103
1104 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
1105fail:
1106 Stream_Free(s, TRUE);
1107 return rc;
1108}
1109
1110WINPR_ATTR_NODISCARD
1111static BOOL rdstls_recv_authentication_request(rdpRdstls* rdstls, uint16_t* pVersion)
1112{
1113 BOOL rc = FALSE;
1114 WINPR_ASSERT(pVersion);
1115
1116 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
1117
1118 if (!rdstls_required_role_is_server(rdstls, TRUE))
1119 return FALSE;
1120 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
1121 return FALSE;
1122
1123 wStream* s = Stream_New(nullptr, 4096);
1124 if (!s)
1125 goto fail;
1126
1127 WINPR_ASSERT(rdstls);
1128
1129 {
1130 const int res = transport_read_pdu(rdstls->transport, s);
1131 if (res < 0)
1132 goto fail;
1133 }
1134
1135 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1136 goto fail;
1137
1138 const UINT16 version = Stream_Get_UINT16(s);
1139 if (!rdstls_is_version_supported(rdstls, version))
1140 goto fail;
1141 *pVersion = version;
1142
1143 const UINT16 pduType = Stream_Get_UINT16(s);
1144 switch (pduType)
1145 {
1146 case RDSTLS_TYPE_AUTHREQ:
1147 if (!rdstls_process_authentication_request(rdstls, s, version))
1148 goto fail;
1149 break;
1150 default:
1151 WLog_Print(rdstls->log, WLOG_ERROR,
1152 "Invalid RDSTLS PDU type [0x%04" PRIx16 "] while reading AUTHREQ", pduType);
1153 goto fail;
1154 }
1155
1156 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
1157fail:
1158 Stream_Free(s, TRUE);
1159 return rc;
1160}
1161
1162WINPR_ATTR_NODISCARD
1163static BOOL rdstls_send_authentication_response(rdpRdstls* rdstls, uint16_t version)
1164{
1165 BOOL rc = FALSE;
1166
1167 if (!rdstls_required_role_is_server(rdstls, TRUE))
1168 return FALSE;
1169
1170 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
1171 return FALSE;
1172
1173 wStream* s = Stream_New(nullptr, 512);
1174 if (!s)
1175 goto fail;
1176
1177 if (!Stream_EnsureRemainingCapacity(s, 2))
1178 goto fail;
1179
1180 Stream_Write_UINT16(s, version);
1181
1182 if (!rdstls_write_authentication_response(rdstls, s))
1183 goto fail;
1184
1185 if (transport_write(rdstls->transport, s) < 0)
1186 goto fail;
1187
1188 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
1189fail:
1190 Stream_Free(s, TRUE);
1191 return rc;
1192}
1193
1194WINPR_ATTR_NODISCARD
1195static BOOL rdstls_recv_capabilities(rdpRdstls* rdstls)
1196{
1197 BOOL rc = FALSE;
1198
1199 if (!rdstls_required_role_is_server(rdstls, FALSE))
1200 return FALSE;
1201
1202 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
1203 return FALSE;
1204
1205 wStream* s = Stream_New(nullptr, 512);
1206 if (!s)
1207 goto fail;
1208
1209 WINPR_ASSERT(rdstls);
1210
1211 {
1212 const int res = transport_read_pdu(rdstls->transport, s);
1213 if (res < 0)
1214 goto fail;
1215 }
1216
1217 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1218 goto fail;
1219
1220 const UINT16 version = Stream_Get_UINT16(s);
1221 if (!rdstls_is_version_supported(rdstls, version))
1222 goto fail;
1223
1224 const UINT16 pduType = Stream_Get_UINT16(s);
1225 switch (pduType)
1226 {
1227 case RDSTLS_TYPE_CAPABILITIES:
1228 if (!rdstls_process_capabilities(rdstls, s))
1229 goto fail;
1230 break;
1231 default:
1232 WLog_Print(rdstls->log, WLOG_ERROR,
1233 "Invalid pduType 0x%04" PRIx16 " while reading capability", pduType);
1234 goto fail;
1235 }
1236
1237 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
1238fail:
1239 Stream_Free(s, TRUE);
1240 return rc;
1241}
1242
1243WINPR_ATTR_NODISCARD
1244static BOOL rdstls_send_authentication_request(rdpRdstls* rdstls, uint16_t* pVersion)
1245{
1246 WINPR_ASSERT(pVersion);
1247
1248 BOOL rc = FALSE;
1249
1250 if (!rdstls_required_role_is_server(rdstls, FALSE))
1251 return FALSE;
1252
1253 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
1254 return FALSE;
1255
1256 wStream* s = Stream_New(nullptr, 4096);
1257 if (!s)
1258 goto fail;
1259
1260 WINPR_ASSERT(rdstls->context);
1261
1262 const rdpSettings* settings = rdstls->context->settings;
1263 WINPR_ASSERT(settings);
1264
1265 if (!Stream_EnsureRemainingCapacity(s, 2))
1266 goto fail;
1267
1268 const RDSTLS_STATE state = rdstls_get_state(rdstls);
1269 const char* fedAuthToken = freerdp_settings_get_string(settings, FreeRDP_EndpointFedAuthToken);
1270 BOOL useFedAuth = (state == RDSTLS_STATE_AUTH_REQ) && !utils_str_is_empty(fedAuthToken);
1271 if ((rdstls->supportedVersions & RDSTLS_VERSION_2) == 0)
1272 {
1273 useFedAuth = FALSE;
1274 WLog_Print(rdstls->log, WLOG_WARN,
1275 "Client has FedAuthToken ready, but server did not announce RDSTLS_VERSION_2.");
1276 }
1277
1278 *pVersion = useFedAuth ? RDSTLS_VERSION_2 : RDSTLS_VERSION_1;
1279 Stream_Write_UINT16(s, *pVersion);
1280
1281 if (useFedAuth)
1282 {
1283 if (!rdstls_write_authentication_request_with_fedauth_token(rdstls, s))
1284 goto fail;
1285 }
1286 else if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED)
1287 {
1288 if (!rdstls_write_authentication_request_with_password(rdstls, s))
1289 goto fail;
1290 }
1291 else if (settings->ServerAutoReconnectCookie != nullptr)
1292 {
1293 if (!rdstls_write_authentication_request_with_cookie(rdstls, s))
1294 goto fail;
1295 }
1296 else
1297 {
1298 WLog_Print(rdstls->log, WLOG_ERROR,
1299 "cannot authenticate with FedAuth token, password or "
1300 "auto-reconnect cookie");
1301 goto fail;
1302 }
1303
1304 WINPR_ASSERT(rdstls);
1305 if (transport_write(rdstls->transport, s) < 0)
1306 goto fail;
1307
1308 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
1309fail:
1310 Stream_Free(s, TRUE);
1311 return rc;
1312}
1313
1314WINPR_ATTR_NODISCARD
1315static BOOL rdstls_recv_authentication_response(rdpRdstls* rdstls, uint16_t expected)
1316{
1317 BOOL rc = FALSE;
1318
1319 WINPR_ASSERT(rdstls);
1320
1321 if (!rdstls_required_role_is_server(rdstls, FALSE))
1322 return FALSE;
1323
1324 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
1325 return FALSE;
1326
1327 wStream* s = Stream_New(nullptr, 512);
1328 if (!s)
1329 goto fail;
1330
1331 {
1332 const int res = transport_read_pdu(rdstls->transport, s);
1333 if (res < 0)
1334 goto fail;
1335 }
1336
1337 if (!Stream_CheckAndLogRequiredLengthWLog(rdstls->log, s, 4))
1338 goto fail;
1339
1340 const UINT16 version = Stream_Get_UINT16(s);
1341 if (!rdstls_is_version_supported(rdstls, version))
1342 goto fail;
1343 if (version != expected)
1344 goto fail;
1345
1346 const UINT16 pduType = Stream_Get_UINT16(s);
1347 switch (pduType)
1348 {
1349 case RDSTLS_TYPE_AUTHRSP:
1350 if (!rdstls_process_authentication_response(rdstls, s))
1351 goto fail;
1352 break;
1353 default:
1354 WLog_Print(rdstls->log, WLOG_ERROR,
1355 "Invalid RDSTLS PDU type [0x%04" PRIx16 "] while reading AUTHRSP", pduType);
1356 goto fail;
1357 }
1358
1359 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
1360fail:
1361 Stream_Free(s, TRUE);
1362 return rc;
1363}
1364
1365WINPR_ATTR_NODISCARD
1366static int rdstls_server_authenticate(rdpRdstls* rdstls)
1367{
1368 WINPR_ASSERT(rdstls);
1369 uint16_t version = 0;
1370
1371 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
1372 return -1;
1373
1374 if (!rdstls_send_capabilities(rdstls))
1375 return -1;
1376
1377 if (!rdstls_recv_authentication_request(rdstls, &version))
1378 return -1;
1379
1380 if (!rdstls_send_authentication_response(rdstls, version))
1381 return -1;
1382
1383 if (rdstls->resultCode != RDSTLS_RESULT_SUCCESS)
1384 return -1;
1385
1386 return 1;
1387}
1388
1389WINPR_ATTR_NODISCARD
1390static int rdstls_client_authenticate(rdpRdstls* rdstls)
1391{
1392 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
1393 return -1;
1394
1395 if (!rdstls_recv_capabilities(rdstls))
1396 return -1;
1397
1398 uint16_t version = 0;
1399 if (!rdstls_send_authentication_request(rdstls, &version))
1400 return -1;
1401
1402 if (!rdstls_recv_authentication_response(rdstls, version))
1403 return -1;
1404
1405 return 1;
1406}
1407
1415int rdstls_authenticate(rdpRdstls* rdstls)
1416{
1417 WINPR_ASSERT(rdstls);
1418
1419 if (rdstls->server)
1420 return rdstls_server_authenticate(rdstls);
1421 else
1422 return rdstls_client_authenticate(rdstls);
1423}
1424
1425WINPR_ATTR_NODISCARD
1426static SSIZE_T rdstls_parse_pdu_data_type(wLog* log, UINT16 dataType, wStream* s)
1427{
1428 size_t pduLength = 0;
1429
1430 switch (dataType)
1431 {
1432 case RDSTLS_DATA_PASSWORD_CREDS:
1433 {
1434 if (Stream_GetRemainingLength(s) < 2)
1435 return 0;
1436
1437 const UINT16 redirGuidLength = Stream_Get_UINT16(s);
1438
1439 if (Stream_GetRemainingLength(s) < redirGuidLength)
1440 return 0;
1441 Stream_Seek(s, redirGuidLength);
1442
1443 if (Stream_GetRemainingLength(s) < 2)
1444 return 0;
1445
1446 const UINT16 usernameLength = Stream_Get_UINT16(s);
1447
1448 if (Stream_GetRemainingLength(s) < usernameLength)
1449 return 0;
1450 Stream_Seek(s, usernameLength);
1451
1452 if (Stream_GetRemainingLength(s) < 2)
1453 return 0;
1454 const UINT16 domainLength = Stream_Get_UINT16(s);
1455
1456 if (Stream_GetRemainingLength(s) < domainLength)
1457 return 0;
1458 Stream_Seek(s, domainLength);
1459
1460 if (Stream_GetRemainingLength(s) < 2)
1461 return 0;
1462 const UINT16 passwordLength = Stream_Get_UINT16(s);
1463
1464 if (passwordLength == 0)
1465 {
1466 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS PASSWORD_CREDS: empty password");
1467 return -1;
1468 }
1469 else if ((redirGuidLength == 0) && (usernameLength == 0) && (domainLength == 0) &&
1470 (passwordLength == 0))
1471 {
1472 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS PASSWORD_CREDS: lengths 0");
1473 return -1;
1474 }
1475 pduLength = Stream_GetPosition(s) + passwordLength;
1476 }
1477 break;
1478 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
1479 {
1480 if (Stream_GetRemainingLength(s) < 6)
1481 return 0;
1482 Stream_Seek(s, 4);
1483 const UINT16 cookieLength = Stream_Get_UINT16(s);
1484 if (cookieLength == 0)
1485 {
1486 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS COOKIE::length");
1487 return -1;
1488 }
1489 pduLength = Stream_GetPosition(s) + cookieLength;
1490 }
1491 break;
1492 case RDSTLS_DATA_FEDAUTH_TOKEN:
1493 {
1494 if (Stream_GetRemainingLength(s) < 6)
1495 return 0;
1496 Stream_Seek(s, 4);
1497 const UINT16 tokenLength = Stream_Get_UINT16(s);
1498 if (tokenLength == 0)
1499 {
1500 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS FEDAUTH_TOKEN::length");
1501 return -1;
1502 }
1503 pduLength = Stream_GetPosition(s) + tokenLength;
1504 }
1505 break;
1506 default:
1507 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS dataType");
1508 return -1;
1509 }
1510
1511 if (pduLength > SSIZE_MAX)
1512 return 0;
1513 return (SSIZE_T)pduLength;
1514}
1515
1516SSIZE_T rdstls_parse_pdu(wLog* log, wStream* stream)
1517{
1518 SSIZE_T pduLength = -1;
1519 wStream sbuffer = WINPR_C_ARRAY_INIT;
1520 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
1521
1522 if (Stream_GetRemainingLength(s) < 2)
1523 return 0;
1524
1525 const UINT16 version = Stream_Get_UINT16(s);
1526 if (!rdstls_are_some_versions_supported(log, version, FALSE))
1527 return -1;
1528
1529 if (Stream_GetRemainingLength(s) < 2)
1530 return 0;
1531
1532 const UINT16 pduType = Stream_Get_UINT16(s);
1533 switch (pduType)
1534 {
1535 case RDSTLS_TYPE_CAPABILITIES:
1536 pduLength = 8;
1537 break;
1538 case RDSTLS_TYPE_AUTHREQ:
1539 {
1540 if (Stream_GetRemainingLength(s) < 2)
1541 return 0;
1542
1543 const UINT16 dataType = Stream_Get_UINT16(s);
1544 pduLength = rdstls_parse_pdu_data_type(log, dataType, s);
1545 }
1546 break;
1547 case RDSTLS_TYPE_AUTHRSP:
1548 pduLength = 10;
1549 break;
1550 default:
1551 WLog_Print(log, WLOG_ERROR, "invalid RDSTLS PDU type");
1552 return -1;
1553 }
1554
1555 return pduLength;
1556}
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.