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 0x01
37
38#define RDSTLS_TYPE_CAPABILITIES 0x01
39#define RDSTLS_TYPE_AUTHREQ 0x02
40#define RDSTLS_TYPE_AUTHRSP 0x04
41
42#define RDSTLS_DATA_CAPABILITIES 0x01
43#define RDSTLS_DATA_PASSWORD_CREDS 0x01
44#define RDSTLS_DATA_AUTORECONNECT_COOKIE 0x02
45#define RDSTLS_DATA_RESULT_CODE 0x01
46
47typedef enum
48{
49 RDSTLS_STATE_INITIAL,
50 RDSTLS_STATE_CAPABILITIES,
51 RDSTLS_STATE_AUTH_REQ,
52 RDSTLS_STATE_AUTH_RSP,
53 RDSTLS_STATE_FINAL,
54} RDSTLS_STATE;
55
56typedef enum
57{
58
59 RDSTLS_RESULT_SUCCESS = 0x00000000,
60 RDSTLS_RESULT_ACCESS_DENIED = 0x00000005,
61 RDSTLS_RESULT_LOGON_FAILURE = 0x0000052e,
62 RDSTLS_RESULT_INVALID_LOGON_HOURS = 0x00000530,
63 RDSTLS_RESULT_PASSWORD_EXPIRED = 0x00000532,
64 RDSTLS_RESULT_ACCOUNT_DISABLED = 0x00000533,
65 RDSTLS_RESULT_PASSWORD_MUST_CHANGE = 0x00000773,
66 RDSTLS_RESULT_ACCOUNT_LOCKED_OUT = 0x00000775
67} RDSTLS_RESULT_CODE;
68
69struct rdp_rdstls
70{
71 BOOL server;
72 RDSTLS_STATE state;
73 rdpContext* context;
74 rdpTransport* transport;
75
76 RDSTLS_RESULT_CODE resultCode;
77 wLog* log;
78};
79
80static const char* rdstls_result_code_str(UINT32 resultCode)
81{
82 switch (resultCode)
83 {
84 case RDSTLS_RESULT_SUCCESS:
85 return "RDSTLS_RESULT_SUCCESS";
86 case RDSTLS_RESULT_ACCESS_DENIED:
87 return "RDSTLS_RESULT_ACCESS_DENIED";
88 case RDSTLS_RESULT_LOGON_FAILURE:
89 return "RDSTLS_RESULT_LOGON_FAILURE";
90 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
91 return "RDSTLS_RESULT_INVALID_LOGON_HOURS";
92 case RDSTLS_RESULT_PASSWORD_EXPIRED:
93 return "RDSTLS_RESULT_PASSWORD_EXPIRED";
94 case RDSTLS_RESULT_ACCOUNT_DISABLED:
95 return "RDSTLS_RESULT_ACCOUNT_DISABLED";
96 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
97 return "RDSTLS_RESULT_PASSWORD_MUST_CHANGE";
98 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
99 return "RDSTLS_RESULT_ACCOUNT_LOCKED_OUT";
100 default:
101 return "RDSTLS_RESULT_UNKNOWN";
102 }
103}
112rdpRdstls* rdstls_new(rdpContext* context, rdpTransport* transport)
113{
114 WINPR_ASSERT(context);
115 WINPR_ASSERT(transport);
116
117 rdpSettings* settings = context->settings;
118 WINPR_ASSERT(settings);
119
120 rdpRdstls* rdstls = (rdpRdstls*)calloc(1, sizeof(rdpRdstls));
121
122 if (!rdstls)
123 return NULL;
124 rdstls->log = WLog_Get(FREERDP_TAG("core.rdstls"));
125 rdstls->context = context;
126 rdstls->transport = transport;
127 rdstls->server = settings->ServerMode;
128
129 rdstls->state = RDSTLS_STATE_INITIAL;
130
131 return rdstls;
132}
133
139void rdstls_free(rdpRdstls* rdstls)
140{
141 free(rdstls);
142}
143
144static const char* rdstls_get_state_str(RDSTLS_STATE state)
145{
146 switch (state)
147 {
148 case RDSTLS_STATE_INITIAL:
149 return "RDSTLS_STATE_INITIAL";
150 case RDSTLS_STATE_CAPABILITIES:
151 return "RDSTLS_STATE_CAPABILITIES";
152 case RDSTLS_STATE_AUTH_REQ:
153 return "RDSTLS_STATE_AUTH_REQ";
154 case RDSTLS_STATE_AUTH_RSP:
155 return "RDSTLS_STATE_AUTH_RSP";
156 case RDSTLS_STATE_FINAL:
157 return "RDSTLS_STATE_FINAL";
158 default:
159 return "UNKNOWN";
160 }
161}
162
163static RDSTLS_STATE rdstls_get_state(rdpRdstls* rdstls)
164{
165 WINPR_ASSERT(rdstls);
166 return rdstls->state;
167}
168
169static BOOL check_transition(wLog* log, RDSTLS_STATE current, RDSTLS_STATE expected,
170 RDSTLS_STATE requested)
171{
172 if (requested != expected)
173 {
174 WLog_Print(log, WLOG_ERROR,
175 "Unexpected rdstls state transition from %s [%u] to %s [%u], expected %s [%u]",
176 rdstls_get_state_str(current), current, rdstls_get_state_str(requested),
177 requested, rdstls_get_state_str(expected), expected);
178 return FALSE;
179 }
180 return TRUE;
181}
182
183static BOOL rdstls_set_state(rdpRdstls* rdstls, RDSTLS_STATE state)
184{
185 BOOL rc = FALSE;
186 WINPR_ASSERT(rdstls);
187
188 WLog_Print(rdstls->log, WLOG_DEBUG, "-- %s\t--> %s", rdstls_get_state_str(rdstls->state),
189 rdstls_get_state_str(state));
190
191 switch (rdstls->state)
192 {
193 case RDSTLS_STATE_INITIAL:
194 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_CAPABILITIES, state);
195 break;
196 case RDSTLS_STATE_CAPABILITIES:
197 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_AUTH_REQ, state);
198 break;
199 case RDSTLS_STATE_AUTH_REQ:
200 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_AUTH_RSP, state);
201 break;
202 case RDSTLS_STATE_AUTH_RSP:
203 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_FINAL, state);
204 break;
205 case RDSTLS_STATE_FINAL:
206 rc = check_transition(rdstls->log, rdstls->state, RDSTLS_STATE_CAPABILITIES, state);
207 break;
208 default:
209 WLog_Print(rdstls->log, WLOG_ERROR,
210 "Invalid rdstls state %s [%u], requested transition to %s [%u]",
211 rdstls_get_state_str(rdstls->state), rdstls->state,
212 rdstls_get_state_str(state), state);
213 break;
214 }
215 if (rc)
216 rdstls->state = state;
217
218 return rc;
219}
220
221static BOOL rdstls_write_capabilities(WINPR_ATTR_UNUSED rdpRdstls* rdstls, wStream* s)
222{
223 if (!Stream_EnsureRemainingCapacity(s, 6))
224 return FALSE;
225
226 Stream_Write_UINT16(s, RDSTLS_TYPE_CAPABILITIES);
227 Stream_Write_UINT16(s, RDSTLS_DATA_CAPABILITIES);
228 Stream_Write_UINT16(s, RDSTLS_VERSION_1);
229
230 return TRUE;
231}
232
233static SSIZE_T rdstls_write_string(wStream* s, const char* str)
234{
235 const size_t pos = Stream_GetPosition(s);
236
237 if (!Stream_EnsureRemainingCapacity(s, 2))
238 return -1;
239
240 if (!str)
241 {
242 /* Write unicode null */
243 Stream_Write_UINT16(s, 2);
244 if (!Stream_EnsureRemainingCapacity(s, 2))
245 return -1;
246
247 Stream_Write_UINT16(s, 0);
248 return (SSIZE_T)(Stream_GetPosition(s) - pos);
249 }
250
251 const size_t length = (strlen(str) + 1);
252
253 Stream_Write_UINT16(s, (UINT16)length * sizeof(WCHAR));
254
255 if (!Stream_EnsureRemainingCapacity(s, length * sizeof(WCHAR)))
256 return -1;
257
258 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
259 return -1;
260
261 return (SSIZE_T)(Stream_GetPosition(s) - pos);
262}
263
264static BOOL rdstls_write_data(wStream* s, UINT32 length, const BYTE* data)
265{
266 WINPR_ASSERT(data || (length == 0));
267
268 if (!Stream_EnsureRemainingCapacity(s, 2) || (length > UINT16_MAX))
269 return FALSE;
270
271 Stream_Write_UINT16(s, (UINT16)length);
272
273 if (!Stream_EnsureRemainingCapacity(s, length))
274 return FALSE;
275
276 Stream_Write(s, data, length);
277
278 return TRUE;
279}
280
281static BOOL rdstls_write_authentication_request_with_password(rdpRdstls* rdstls, wStream* s)
282{
283 rdpSettings* settings = rdstls->context->settings;
284 WINPR_ASSERT(settings);
285
286 if (!Stream_EnsureRemainingCapacity(s, 4))
287 return FALSE;
288
289 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHREQ);
290 Stream_Write_UINT16(s, RDSTLS_DATA_PASSWORD_CREDS);
291
292 if (!rdstls_write_data(s, settings->RedirectionGuidLength, settings->RedirectionGuid))
293 return FALSE;
294
295 if (rdstls_write_string(s, settings->Username) < 0)
296 return FALSE;
297
298 if (rdstls_write_string(s, settings->Domain) < 0)
299 return FALSE;
300
301 if (!rdstls_write_data(s, settings->RedirectionPasswordLength, settings->RedirectionPassword))
302 return FALSE;
303
304 return TRUE;
305}
306
307static BOOL rdstls_write_authentication_request_with_cookie(WINPR_ATTR_UNUSED rdpRdstls* rdstls,
308 WINPR_ATTR_UNUSED wStream* s)
309{
310 // TODO
311 return FALSE;
312}
313
314static BOOL rdstls_write_authentication_response(rdpRdstls* rdstls, wStream* s)
315{
316 if (!Stream_EnsureRemainingCapacity(s, 8))
317 return FALSE;
318
319 Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHRSP);
320 Stream_Write_UINT16(s, RDSTLS_DATA_RESULT_CODE);
321 Stream_Write_UINT32(s, rdstls->resultCode);
322
323 return TRUE;
324}
325
326static BOOL rdstls_process_capabilities(rdpRdstls* rdstls, wStream* s)
327{
328 UINT16 dataType = 0;
329 UINT16 supportedVersions = 0;
330
331 if (Stream_GetRemainingLength(s) < 4)
332 return FALSE;
333
334 Stream_Read_UINT16(s, dataType);
335 if (dataType != RDSTLS_DATA_CAPABILITIES)
336 {
337 WLog_Print(rdstls->log, WLOG_ERROR,
338 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32, dataType,
339 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_CAPABILITIES));
340 return FALSE;
341 }
342
343 Stream_Read_UINT16(s, supportedVersions);
344 if ((supportedVersions & RDSTLS_VERSION_1) == 0)
345 {
346 WLog_Print(rdstls->log, WLOG_ERROR,
347 "received invalid supportedVersions=0x%04" PRIX16 ", expected 0x%04" PRIX32,
348 supportedVersions, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_VERSION_1));
349 return FALSE;
350 }
351
352 return TRUE;
353}
354
355static BOOL rdstls_read_unicode_string(WINPR_ATTR_UNUSED wLog* log, wStream* s, char** str)
356{
357 UINT16 length = 0;
358
359 WINPR_ASSERT(str);
360
361 if (Stream_GetRemainingLength(s) < 2)
362 return FALSE;
363
364 Stream_Read_UINT16(s, length);
365
366 if (Stream_GetRemainingLength(s) < length)
367 return FALSE;
368
369 if (length <= 2)
370 {
371 Stream_Seek(s, length);
372 return TRUE;
373 }
374
375 *str = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), NULL);
376 if (!*str)
377 return FALSE;
378
379 return TRUE;
380}
381
382static BOOL rdstls_read_data(WINPR_ATTR_UNUSED wLog* log, wStream* s, UINT16* pLength,
383 const BYTE** pData)
384{
385 UINT16 length = 0;
386
387 WINPR_ASSERT(pLength);
388 WINPR_ASSERT(pData);
389
390 *pData = NULL;
391 *pLength = 0;
392 if (Stream_GetRemainingLength(s) < 2)
393 return FALSE;
394
395 Stream_Read_UINT16(s, length);
396
397 if (Stream_GetRemainingLength(s) < length)
398 return FALSE;
399
400 if (length <= 2)
401 {
402 Stream_Seek(s, length);
403 return TRUE;
404 }
405
406 *pData = Stream_ConstPointer(s);
407 *pLength = length;
408 Stream_Seek(s, length);
409 return TRUE;
410}
411
412static BOOL rdstls_cmp_data(wLog* log, const char* field, const BYTE* serverData,
413 const UINT32 serverDataLength, const BYTE* clientData,
414 const UINT16 clientDataLength)
415{
416 if (serverDataLength > 0)
417 {
418 if (clientDataLength == 0)
419 {
420 WLog_Print(log, WLOG_ERROR, "expected %s", field);
421 return FALSE;
422 }
423
424 if (serverDataLength > UINT16_MAX || serverDataLength != clientDataLength ||
425 memcmp(serverData, clientData, serverDataLength) != 0)
426 {
427 WLog_Print(log, WLOG_ERROR, "%s verification failed", field);
428 return FALSE;
429 }
430 }
431
432 return TRUE;
433}
434
435static BOOL rdstls_cmp_str(wLog* log, const char* field, const char* serverStr,
436 const char* clientStr)
437{
438 if (!utils_str_is_empty(serverStr))
439 {
440 if (utils_str_is_empty(clientStr))
441 {
442 WLog_Print(log, WLOG_ERROR, "expected %s", field);
443 return FALSE;
444 }
445
446 WINPR_ASSERT(serverStr);
447 WINPR_ASSERT(clientStr);
448 if (strcmp(serverStr, clientStr) != 0)
449 {
450 WLog_Print(log, WLOG_ERROR, "%s verification failed", field);
451 return FALSE;
452 }
453 }
454
455 return TRUE;
456}
457
458static BOOL rdstls_process_authentication_request_with_password(rdpRdstls* rdstls, wStream* s)
459{
460 BOOL rc = FALSE;
461
462 const BYTE* clientRedirectionGuid = NULL;
463 UINT16 clientRedirectionGuidLength = 0;
464 char* clientPassword = NULL;
465 char* clientUsername = NULL;
466 char* clientDomain = NULL;
467
468 const BYTE* serverRedirectionGuid = NULL;
469 const char* serverPassword = NULL;
470 const char* serverUsername = NULL;
471 const char* serverDomain = NULL;
472
473 rdpSettings* settings = rdstls->context->settings;
474 WINPR_ASSERT(settings);
475
476 if (!rdstls_read_data(rdstls->log, s, &clientRedirectionGuidLength, &clientRedirectionGuid))
477 goto fail;
478
479 if (!rdstls_read_unicode_string(rdstls->log, s, &clientUsername))
480 goto fail;
481
482 if (!rdstls_read_unicode_string(rdstls->log, s, &clientDomain))
483 goto fail;
484
485 if (!rdstls_read_unicode_string(rdstls->log, s, &clientPassword))
486 goto fail;
487
488 serverRedirectionGuid = freerdp_settings_get_pointer(settings, FreeRDP_RedirectionGuid);
489 const UINT32 serverRedirectionGuidLength =
490 freerdp_settings_get_uint32(settings, FreeRDP_RedirectionGuidLength);
491 serverUsername = freerdp_settings_get_string(settings, FreeRDP_Username);
492 serverDomain = freerdp_settings_get_string(settings, FreeRDP_Domain);
493 serverPassword = freerdp_settings_get_string(settings, FreeRDP_Password);
494
495 rdstls->resultCode = RDSTLS_RESULT_SUCCESS;
496
497 if (!rdstls_cmp_data(rdstls->log, "RedirectionGuid", serverRedirectionGuid,
498 serverRedirectionGuidLength, clientRedirectionGuid,
499 clientRedirectionGuidLength))
500 rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
501
502 if (!rdstls_cmp_str(rdstls->log, "UserName", serverUsername, clientUsername))
503 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
504
505 if (!rdstls_cmp_str(rdstls->log, "Domain", serverDomain, clientDomain))
506 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
507
508 if (!rdstls_cmp_str(rdstls->log, "Password", serverPassword, clientPassword))
509 rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
510
511 rc = TRUE;
512fail:
513 return rc;
514}
515
516static BOOL rdstls_process_authentication_request_with_cookie(WINPR_ATTR_UNUSED rdpRdstls* rdstls,
517 WINPR_ATTR_UNUSED wStream* s)
518{
519 // TODO
520 return FALSE;
521}
522
523static BOOL rdstls_process_authentication_request(rdpRdstls* rdstls, wStream* s)
524{
525 UINT16 dataType = 0;
526
527 if (Stream_GetRemainingLength(s) < 2)
528 return FALSE;
529
530 Stream_Read_UINT16(s, dataType);
531 switch (dataType)
532 {
533 case RDSTLS_DATA_PASSWORD_CREDS:
534 if (!rdstls_process_authentication_request_with_password(rdstls, s))
535 return FALSE;
536 break;
537 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
538 if (!rdstls_process_authentication_request_with_cookie(rdstls, s))
539 return FALSE;
540 break;
541 default:
542 WLog_Print(rdstls->log, WLOG_ERROR,
543 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32
544 " or 0x%04" PRIX32,
545 dataType, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_PASSWORD_CREDS),
546 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_AUTORECONNECT_COOKIE));
547 return FALSE;
548 }
549
550 return TRUE;
551}
552
553static BOOL rdstls_process_authentication_response(rdpRdstls* rdstls, wStream* s)
554{
555 UINT16 dataType = 0;
556 UINT32 resultCode = 0;
557
558 if (Stream_GetRemainingLength(s) < 6)
559 return FALSE;
560
561 Stream_Read_UINT16(s, dataType);
562 if (dataType != RDSTLS_DATA_RESULT_CODE)
563 {
564 WLog_Print(rdstls->log, WLOG_ERROR,
565 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32, dataType,
566 WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_RESULT_CODE));
567 return FALSE;
568 }
569
570 Stream_Read_UINT32(s, resultCode);
571 if (resultCode != RDSTLS_RESULT_SUCCESS)
572 {
573 WLog_Print(rdstls->log, WLOG_ERROR, "resultCode: %s [0x%08" PRIX32 "]",
574 rdstls_result_code_str(resultCode), resultCode);
575
576 UINT32 error = ERROR_INTERNAL_ERROR;
577 switch (resultCode)
578 {
579 case RDSTLS_RESULT_ACCESS_DENIED:
580 error = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
581 break;
582 case RDSTLS_RESULT_ACCOUNT_DISABLED:
583 error = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
584 break;
585 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
586 error = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
587 break;
588 case RDSTLS_RESULT_LOGON_FAILURE:
589 error = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
590 break;
591 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
592 error = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
593 break;
594 case RDSTLS_RESULT_PASSWORD_EXPIRED:
595 error = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
596 break;
597 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
598 error = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
599 break;
600 default:
601 error = ERROR_INVALID_PARAMETER;
602 break;
603 }
604
605 freerdp_set_last_error_if_not(rdstls->context, error);
606 return FALSE;
607 }
608
609 return TRUE;
610}
611
612static BOOL rdstls_send(WINPR_ATTR_UNUSED rdpTransport* transport, wStream* s, void* extra)
613{
614 rdpRdstls* rdstls = (rdpRdstls*)extra;
615 rdpSettings* settings = NULL;
616
617 WINPR_ASSERT(transport);
618 WINPR_ASSERT(s);
619 WINPR_ASSERT(rdstls);
620
621 settings = rdstls->context->settings;
622 WINPR_ASSERT(settings);
623
624 if (!Stream_EnsureRemainingCapacity(s, 2))
625 return FALSE;
626
627 Stream_Write_UINT16(s, RDSTLS_VERSION_1);
628
629 const RDSTLS_STATE state = rdstls_get_state(rdstls);
630 switch (state)
631 {
632 case RDSTLS_STATE_CAPABILITIES:
633 if (!rdstls_write_capabilities(rdstls, s))
634 return FALSE;
635 break;
636 case RDSTLS_STATE_AUTH_REQ:
637 if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED)
638 {
639 if (!rdstls_write_authentication_request_with_password(rdstls, s))
640 return FALSE;
641 }
642 else if (settings->ServerAutoReconnectCookie != NULL)
643 {
644 if (!rdstls_write_authentication_request_with_cookie(rdstls, s))
645 return FALSE;
646 }
647 else
648 {
649 WLog_Print(rdstls->log, WLOG_ERROR,
650 "cannot authenticate with password or auto-reconnect cookie");
651 return FALSE;
652 }
653 break;
654 case RDSTLS_STATE_AUTH_RSP:
655 if (!rdstls_write_authentication_response(rdstls, s))
656 return FALSE;
657 break;
658 default:
659 WLog_Print(rdstls->log, WLOG_ERROR, "Invalid rdstls state %s [%" PRIu32 "]",
660 rdstls_get_state_str(state), state);
661 return FALSE;
662 }
663
664 if (transport_write(rdstls->transport, s) < 0)
665 return FALSE;
666
667 return TRUE;
668}
669
670static int rdstls_recv(WINPR_ATTR_UNUSED rdpTransport* transport, wStream* s, void* extra)
671{
672 UINT16 version = 0;
673 UINT16 pduType = 0;
674 rdpRdstls* rdstls = (rdpRdstls*)extra;
675
676 WINPR_ASSERT(transport);
677 WINPR_ASSERT(s);
678 WINPR_ASSERT(rdstls);
679
680 if (Stream_GetRemainingLength(s) < 4)
681 return FALSE;
682
683 Stream_Read_UINT16(s, version);
684 if (version != RDSTLS_VERSION_1)
685 {
686 WLog_Print(rdstls->log, WLOG_ERROR,
687 "received invalid RDSTLS Version=0x%04" PRIX16 ", expected 0x%04" PRIX16,
688 version, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_VERSION_1));
689 return -1;
690 }
691
692 Stream_Read_UINT16(s, pduType);
693 switch (pduType)
694 {
695 case RDSTLS_TYPE_CAPABILITIES:
696 if (!rdstls_process_capabilities(rdstls, s))
697 return -1;
698 break;
699 case RDSTLS_TYPE_AUTHREQ:
700 if (!rdstls_process_authentication_request(rdstls, s))
701 return -1;
702 break;
703 case RDSTLS_TYPE_AUTHRSP:
704 if (!rdstls_process_authentication_response(rdstls, s))
705 return -1;
706 break;
707 default:
708 WLog_Print(rdstls->log, WLOG_ERROR, "unknown RDSTLS PDU type [0x%04" PRIx16 "]",
709 pduType);
710 return -1;
711 }
712
713 return 1;
714}
715
716#define rdstls_check_state_requirements(rdstls, expected) \
717 rdstls_check_state_requirements_((rdstls), (expected), __FILE__, __func__, __LINE__)
718static BOOL rdstls_check_state_requirements_(rdpRdstls* rdstls, RDSTLS_STATE expected,
719 const char* file, const char* fkt, size_t line)
720{
721 const RDSTLS_STATE current = rdstls_get_state(rdstls);
722 if (current == expected)
723 return TRUE;
724
725 const DWORD log_level = WLOG_ERROR;
726 if (WLog_IsLevelActive(rdstls->log, log_level))
727 WLog_PrintTextMessage(rdstls->log, log_level, line, file, fkt,
728 "Unexpected rdstls state %s [%u], expected %s [%u]",
729 rdstls_get_state_str(current), current,
730 rdstls_get_state_str(expected), expected);
731
732 return FALSE;
733}
734
735static BOOL rdstls_send_capabilities(rdpRdstls* rdstls)
736{
737 BOOL rc = FALSE;
738 wStream* s = NULL;
739
740 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
741 goto fail;
742
743 s = Stream_New(NULL, 512);
744 if (!s)
745 goto fail;
746
747 if (!rdstls_send(rdstls->transport, s, rdstls))
748 goto fail;
749
750 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
751fail:
752 Stream_Free(s, TRUE);
753 return rc;
754}
755
756static BOOL rdstls_recv_authentication_request(rdpRdstls* rdstls)
757{
758 BOOL rc = FALSE;
759 int status = 0;
760 wStream* s = NULL;
761
762 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
763 goto fail;
764
765 s = Stream_New(NULL, 4096);
766 if (!s)
767 goto fail;
768
769 status = transport_read_pdu(rdstls->transport, s);
770
771 if (status < 0)
772 goto fail;
773
774 status = rdstls_recv(rdstls->transport, s, rdstls);
775
776 if (status < 0)
777 goto fail;
778
779 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
780fail:
781 Stream_Free(s, TRUE);
782 return rc;
783}
784
785static BOOL rdstls_send_authentication_response(rdpRdstls* rdstls)
786{
787 BOOL rc = FALSE;
788 wStream* s = NULL;
789
790 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
791 goto fail;
792
793 s = Stream_New(NULL, 512);
794 if (!s)
795 goto fail;
796
797 if (!rdstls_send(rdstls->transport, s, rdstls))
798 goto fail;
799
800 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
801fail:
802 Stream_Free(s, TRUE);
803 return rc;
804}
805
806static BOOL rdstls_recv_capabilities(rdpRdstls* rdstls)
807{
808 BOOL rc = FALSE;
809 int status = 0;
810 wStream* s = NULL;
811
812 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
813 goto fail;
814
815 s = Stream_New(NULL, 512);
816 if (!s)
817 goto fail;
818
819 status = transport_read_pdu(rdstls->transport, s);
820
821 if (status < 0)
822 goto fail;
823
824 status = rdstls_recv(rdstls->transport, s, rdstls);
825
826 if (status < 0)
827 goto fail;
828
829 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
830fail:
831 Stream_Free(s, TRUE);
832 return rc;
833}
834
835static BOOL rdstls_send_authentication_request(rdpRdstls* rdstls)
836{
837 BOOL rc = FALSE;
838 wStream* s = NULL;
839
840 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
841 goto fail;
842
843 s = Stream_New(NULL, 4096);
844 if (!s)
845 goto fail;
846
847 if (!rdstls_send(rdstls->transport, s, rdstls))
848 goto fail;
849
850 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
851fail:
852 Stream_Free(s, TRUE);
853 return rc;
854}
855
856static BOOL rdstls_recv_authentication_response(rdpRdstls* rdstls)
857{
858 BOOL rc = FALSE;
859 int status = 0;
860 wStream* s = NULL;
861
862 WINPR_ASSERT(rdstls);
863
864 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
865 goto fail;
866
867 s = Stream_New(NULL, 512);
868 if (!s)
869 goto fail;
870
871 status = transport_read_pdu(rdstls->transport, s);
872
873 if (status < 0)
874 goto fail;
875
876 status = rdstls_recv(rdstls->transport, s, rdstls);
877
878 if (status < 0)
879 goto fail;
880
881 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
882fail:
883 Stream_Free(s, TRUE);
884 return rc;
885}
886
887static int rdstls_server_authenticate(rdpRdstls* rdstls)
888{
889 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
890 return -1;
891
892 if (!rdstls_send_capabilities(rdstls))
893 return -1;
894
895 if (!rdstls_recv_authentication_request(rdstls))
896 return -1;
897
898 if (!rdstls_send_authentication_response(rdstls))
899 return -1;
900
901 if (rdstls->resultCode != RDSTLS_RESULT_SUCCESS)
902 return -1;
903
904 return 1;
905}
906
907static int rdstls_client_authenticate(rdpRdstls* rdstls)
908{
909 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
910 return -1;
911
912 if (!rdstls_recv_capabilities(rdstls))
913 return -1;
914
915 if (!rdstls_send_authentication_request(rdstls))
916 return -1;
917
918 if (!rdstls_recv_authentication_response(rdstls))
919 return -1;
920
921 return 1;
922}
923
931int rdstls_authenticate(rdpRdstls* rdstls)
932{
933 WINPR_ASSERT(rdstls);
934
935 if (rdstls->server)
936 return rdstls_server_authenticate(rdstls);
937 else
938 return rdstls_client_authenticate(rdstls);
939}
940
941static SSIZE_T rdstls_parse_pdu_data_type(wLog* log, UINT16 dataType, wStream* s)
942{
943 size_t pduLength = 0;
944
945 switch (dataType)
946 {
947 case RDSTLS_DATA_PASSWORD_CREDS:
948 {
949 UINT16 redirGuidLength = 0;
950 if (Stream_GetRemainingLength(s) < 2)
951 return 0;
952 Stream_Read_UINT16(s, redirGuidLength);
953
954 if (Stream_GetRemainingLength(s) < redirGuidLength)
955 return 0;
956 Stream_Seek(s, redirGuidLength);
957
958 UINT16 usernameLength = 0;
959 if (Stream_GetRemainingLength(s) < 2)
960 return 0;
961 Stream_Read_UINT16(s, usernameLength);
962
963 if (Stream_GetRemainingLength(s) < usernameLength)
964 return 0;
965 Stream_Seek(s, usernameLength);
966
967 UINT16 domainLength = 0;
968 if (Stream_GetRemainingLength(s) < 2)
969 return 0;
970 Stream_Read_UINT16(s, domainLength);
971
972 if (Stream_GetRemainingLength(s) < domainLength)
973 return 0;
974 Stream_Seek(s, domainLength);
975
976 UINT16 passwordLength = 0;
977 if (Stream_GetRemainingLength(s) < 2)
978 return 0;
979 Stream_Read_UINT16(s, passwordLength);
980
981 pduLength = Stream_GetPosition(s) + passwordLength;
982 }
983 break;
984 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
985 {
986 if (Stream_GetRemainingLength(s) < 4)
987 return 0;
988 Stream_Seek(s, 4);
989
990 UINT16 cookieLength = 0;
991 if (Stream_GetRemainingLength(s) < 2)
992 return 0;
993 Stream_Read_UINT16(s, cookieLength);
994
995 pduLength = Stream_GetPosition(s) + cookieLength;
996 }
997 break;
998 default:
999 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS dataType");
1000 return -1;
1001 }
1002
1003 if (pduLength > SSIZE_MAX)
1004 return 0;
1005 return (SSIZE_T)pduLength;
1006}
1007
1008SSIZE_T rdstls_parse_pdu(wLog* log, wStream* stream)
1009{
1010 SSIZE_T pduLength = -1;
1011 wStream sbuffer = { 0 };
1012 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
1013
1014 UINT16 version = 0;
1015 if (Stream_GetRemainingLength(s) < 2)
1016 return 0;
1017 Stream_Read_UINT16(s, version);
1018 if (version != RDSTLS_VERSION_1)
1019 {
1020 WLog_Print(log, WLOG_ERROR, "invalid RDSTLS version");
1021 return -1;
1022 }
1023
1024 UINT16 pduType = 0;
1025 if (Stream_GetRemainingLength(s) < 2)
1026 return 0;
1027 Stream_Read_UINT16(s, pduType);
1028 switch (pduType)
1029 {
1030 case RDSTLS_TYPE_CAPABILITIES:
1031 pduLength = 8;
1032 break;
1033 case RDSTLS_TYPE_AUTHREQ:
1034 if (Stream_GetRemainingLength(s) < 2)
1035 return 0;
1036 UINT16 dataType = 0;
1037 Stream_Read_UINT16(s, dataType);
1038 pduLength = rdstls_parse_pdu_data_type(log, dataType, s);
1039
1040 break;
1041 case RDSTLS_TYPE_AUTHRSP:
1042 pduLength = 10;
1043 break;
1044 default:
1045 WLog_Print(log, WLOG_ERROR, "invalid RDSTLS PDU type");
1046 return -1;
1047 }
1048
1049 return pduLength;
1050}
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API const void * freerdp_settings_get_pointer(const rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id)
Returns a immutable pointer settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.