FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 [%d] to %s [%d], expected %s [%d]",
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 [%d], requested transition to %s [%d]",
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" PRIX16, dataType,
339 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" PRIX16,
348 supportedVersions, 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" PRIX16
544 " or 0x%04" PRIX16,
545 dataType, RDSTLS_DATA_PASSWORD_CREDS, RDSTLS_DATA_AUTORECONNECT_COOKIE);
546 return FALSE;
547 }
548
549 return TRUE;
550}
551
552static BOOL rdstls_process_authentication_response(rdpRdstls* rdstls, wStream* s)
553{
554 UINT16 dataType = 0;
555 UINT32 resultCode = 0;
556
557 if (Stream_GetRemainingLength(s) < 6)
558 return FALSE;
559
560 Stream_Read_UINT16(s, dataType);
561 if (dataType != RDSTLS_DATA_RESULT_CODE)
562 {
563 WLog_Print(rdstls->log, WLOG_ERROR,
564 "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX16, dataType,
565 RDSTLS_DATA_RESULT_CODE);
566 return FALSE;
567 }
568
569 Stream_Read_UINT32(s, resultCode);
570 if (resultCode != RDSTLS_RESULT_SUCCESS)
571 {
572 WLog_Print(rdstls->log, WLOG_ERROR, "resultCode: %s [0x%08" PRIX32 "]",
573 rdstls_result_code_str(resultCode), resultCode);
574
575 UINT32 error = ERROR_INTERNAL_ERROR;
576 switch (resultCode)
577 {
578 case RDSTLS_RESULT_ACCESS_DENIED:
579 error = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
580 break;
581 case RDSTLS_RESULT_ACCOUNT_DISABLED:
582 error = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
583 break;
584 case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
585 error = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
586 break;
587 case RDSTLS_RESULT_LOGON_FAILURE:
588 error = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
589 break;
590 case RDSTLS_RESULT_INVALID_LOGON_HOURS:
591 error = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
592 break;
593 case RDSTLS_RESULT_PASSWORD_EXPIRED:
594 error = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
595 break;
596 case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
597 error = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
598 break;
599 default:
600 error = ERROR_INVALID_PARAMETER;
601 break;
602 }
603
604 freerdp_set_last_error_if_not(rdstls->context, error);
605 return FALSE;
606 }
607
608 return TRUE;
609}
610
611static BOOL rdstls_send(WINPR_ATTR_UNUSED rdpTransport* transport, wStream* s, void* extra)
612{
613 rdpRdstls* rdstls = (rdpRdstls*)extra;
614 rdpSettings* settings = NULL;
615
616 WINPR_ASSERT(transport);
617 WINPR_ASSERT(s);
618 WINPR_ASSERT(rdstls);
619
620 settings = rdstls->context->settings;
621 WINPR_ASSERT(settings);
622
623 if (!Stream_EnsureRemainingCapacity(s, 2))
624 return FALSE;
625
626 Stream_Write_UINT16(s, RDSTLS_VERSION_1);
627
628 const RDSTLS_STATE state = rdstls_get_state(rdstls);
629 switch (state)
630 {
631 case RDSTLS_STATE_CAPABILITIES:
632 if (!rdstls_write_capabilities(rdstls, s))
633 return FALSE;
634 break;
635 case RDSTLS_STATE_AUTH_REQ:
636 if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED)
637 {
638 if (!rdstls_write_authentication_request_with_password(rdstls, s))
639 return FALSE;
640 }
641 else if (settings->ServerAutoReconnectCookie != NULL)
642 {
643 if (!rdstls_write_authentication_request_with_cookie(rdstls, s))
644 return FALSE;
645 }
646 else
647 {
648 WLog_Print(rdstls->log, WLOG_ERROR,
649 "cannot authenticate with password or auto-reconnect cookie");
650 return FALSE;
651 }
652 break;
653 case RDSTLS_STATE_AUTH_RSP:
654 if (!rdstls_write_authentication_response(rdstls, s))
655 return FALSE;
656 break;
657 default:
658 WLog_Print(rdstls->log, WLOG_ERROR, "Invalid rdstls state %s [%d]",
659 rdstls_get_state_str(state), state);
660 return FALSE;
661 }
662
663 if (transport_write(rdstls->transport, s) < 0)
664 return FALSE;
665
666 return TRUE;
667}
668
669static int rdstls_recv(WINPR_ATTR_UNUSED rdpTransport* transport, wStream* s, void* extra)
670{
671 UINT16 version = 0;
672 UINT16 pduType = 0;
673 rdpRdstls* rdstls = (rdpRdstls*)extra;
674
675 WINPR_ASSERT(transport);
676 WINPR_ASSERT(s);
677 WINPR_ASSERT(rdstls);
678
679 if (Stream_GetRemainingLength(s) < 4)
680 return FALSE;
681
682 Stream_Read_UINT16(s, version);
683 if (version != RDSTLS_VERSION_1)
684 {
685 WLog_Print(rdstls->log, WLOG_ERROR,
686 "received invalid RDSTLS Version=0x%04" PRIX16 ", expected 0x%04" PRIX16,
687 version, RDSTLS_VERSION_1);
688 return -1;
689 }
690
691 Stream_Read_UINT16(s, pduType);
692 switch (pduType)
693 {
694 case RDSTLS_TYPE_CAPABILITIES:
695 if (!rdstls_process_capabilities(rdstls, s))
696 return -1;
697 break;
698 case RDSTLS_TYPE_AUTHREQ:
699 if (!rdstls_process_authentication_request(rdstls, s))
700 return -1;
701 break;
702 case RDSTLS_TYPE_AUTHRSP:
703 if (!rdstls_process_authentication_response(rdstls, s))
704 return -1;
705 break;
706 default:
707 WLog_Print(rdstls->log, WLOG_ERROR, "unknown RDSTLS PDU type [0x%04" PRIx16 "]",
708 pduType);
709 return -1;
710 }
711
712 return 1;
713}
714
715#define rdstls_check_state_requirements(rdstls, expected) \
716 rdstls_check_state_requirements_((rdstls), (expected), __FILE__, __func__, __LINE__)
717static BOOL rdstls_check_state_requirements_(rdpRdstls* rdstls, RDSTLS_STATE expected,
718 const char* file, const char* fkt, size_t line)
719{
720 const RDSTLS_STATE current = rdstls_get_state(rdstls);
721 if (current == expected)
722 return TRUE;
723
724 const DWORD log_level = WLOG_ERROR;
725 if (WLog_IsLevelActive(rdstls->log, log_level))
726 WLog_PrintMessage(rdstls->log, WLOG_MESSAGE_TEXT, log_level, line, file, fkt,
727 "Unexpected rdstls state %s [%d], expected %s [%d]",
728 rdstls_get_state_str(current), current, rdstls_get_state_str(expected),
729 expected);
730
731 return FALSE;
732}
733
734static BOOL rdstls_send_capabilities(rdpRdstls* rdstls)
735{
736 BOOL rc = FALSE;
737 wStream* s = NULL;
738
739 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
740 goto fail;
741
742 s = Stream_New(NULL, 512);
743 if (!s)
744 goto fail;
745
746 if (!rdstls_send(rdstls->transport, s, rdstls))
747 goto fail;
748
749 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
750fail:
751 Stream_Free(s, TRUE);
752 return rc;
753}
754
755static BOOL rdstls_recv_authentication_request(rdpRdstls* rdstls)
756{
757 BOOL rc = FALSE;
758 int status = 0;
759 wStream* s = NULL;
760
761 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
762 goto fail;
763
764 s = Stream_New(NULL, 4096);
765 if (!s)
766 goto fail;
767
768 status = transport_read_pdu(rdstls->transport, s);
769
770 if (status < 0)
771 goto fail;
772
773 status = rdstls_recv(rdstls->transport, s, rdstls);
774
775 if (status < 0)
776 goto fail;
777
778 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
779fail:
780 Stream_Free(s, TRUE);
781 return rc;
782}
783
784static BOOL rdstls_send_authentication_response(rdpRdstls* rdstls)
785{
786 BOOL rc = FALSE;
787 wStream* s = NULL;
788
789 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
790 goto fail;
791
792 s = Stream_New(NULL, 512);
793 if (!s)
794 goto fail;
795
796 if (!rdstls_send(rdstls->transport, s, rdstls))
797 goto fail;
798
799 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
800fail:
801 Stream_Free(s, TRUE);
802 return rc;
803}
804
805static BOOL rdstls_recv_capabilities(rdpRdstls* rdstls)
806{
807 BOOL rc = FALSE;
808 int status = 0;
809 wStream* s = NULL;
810
811 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
812 goto fail;
813
814 s = Stream_New(NULL, 512);
815 if (!s)
816 goto fail;
817
818 status = transport_read_pdu(rdstls->transport, s);
819
820 if (status < 0)
821 goto fail;
822
823 status = rdstls_recv(rdstls->transport, s, rdstls);
824
825 if (status < 0)
826 goto fail;
827
828 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
829fail:
830 Stream_Free(s, TRUE);
831 return rc;
832}
833
834static BOOL rdstls_send_authentication_request(rdpRdstls* rdstls)
835{
836 BOOL rc = FALSE;
837 wStream* s = NULL;
838
839 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
840 goto fail;
841
842 s = Stream_New(NULL, 4096);
843 if (!s)
844 goto fail;
845
846 if (!rdstls_send(rdstls->transport, s, rdstls))
847 goto fail;
848
849 rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
850fail:
851 Stream_Free(s, TRUE);
852 return rc;
853}
854
855static BOOL rdstls_recv_authentication_response(rdpRdstls* rdstls)
856{
857 BOOL rc = FALSE;
858 int status = 0;
859 wStream* s = NULL;
860
861 WINPR_ASSERT(rdstls);
862
863 if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
864 goto fail;
865
866 s = Stream_New(NULL, 512);
867 if (!s)
868 goto fail;
869
870 status = transport_read_pdu(rdstls->transport, s);
871
872 if (status < 0)
873 goto fail;
874
875 status = rdstls_recv(rdstls->transport, s, rdstls);
876
877 if (status < 0)
878 goto fail;
879
880 rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
881fail:
882 Stream_Free(s, TRUE);
883 return rc;
884}
885
886static int rdstls_server_authenticate(rdpRdstls* rdstls)
887{
888 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
889 return -1;
890
891 if (!rdstls_send_capabilities(rdstls))
892 return -1;
893
894 if (!rdstls_recv_authentication_request(rdstls))
895 return -1;
896
897 if (!rdstls_send_authentication_response(rdstls))
898 return -1;
899
900 if (rdstls->resultCode != RDSTLS_RESULT_SUCCESS)
901 return -1;
902
903 return 1;
904}
905
906static int rdstls_client_authenticate(rdpRdstls* rdstls)
907{
908 if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
909 return -1;
910
911 if (!rdstls_recv_capabilities(rdstls))
912 return -1;
913
914 if (!rdstls_send_authentication_request(rdstls))
915 return -1;
916
917 if (!rdstls_recv_authentication_response(rdstls))
918 return -1;
919
920 return 1;
921}
922
930int rdstls_authenticate(rdpRdstls* rdstls)
931{
932 WINPR_ASSERT(rdstls);
933
934 if (rdstls->server)
935 return rdstls_server_authenticate(rdstls);
936 else
937 return rdstls_client_authenticate(rdstls);
938}
939
940static SSIZE_T rdstls_parse_pdu_data_type(wLog* log, UINT16 dataType, wStream* s)
941{
942 size_t pduLength = 0;
943
944 switch (dataType)
945 {
946 case RDSTLS_DATA_PASSWORD_CREDS:
947 {
948 UINT16 redirGuidLength = 0;
949 if (Stream_GetRemainingLength(s) < 2)
950 return 0;
951 Stream_Read_UINT16(s, redirGuidLength);
952
953 if (Stream_GetRemainingLength(s) < redirGuidLength)
954 return 0;
955 Stream_Seek(s, redirGuidLength);
956
957 UINT16 usernameLength = 0;
958 if (Stream_GetRemainingLength(s) < 2)
959 return 0;
960 Stream_Read_UINT16(s, usernameLength);
961
962 if (Stream_GetRemainingLength(s) < usernameLength)
963 return 0;
964 Stream_Seek(s, usernameLength);
965
966 UINT16 domainLength = 0;
967 if (Stream_GetRemainingLength(s) < 2)
968 return 0;
969 Stream_Read_UINT16(s, domainLength);
970
971 if (Stream_GetRemainingLength(s) < domainLength)
972 return 0;
973 Stream_Seek(s, domainLength);
974
975 UINT16 passwordLength = 0;
976 if (Stream_GetRemainingLength(s) < 2)
977 return 0;
978 Stream_Read_UINT16(s, passwordLength);
979
980 pduLength = Stream_GetPosition(s) + passwordLength;
981 }
982 break;
983 case RDSTLS_DATA_AUTORECONNECT_COOKIE:
984 {
985 if (Stream_GetRemainingLength(s) < 4)
986 return 0;
987 Stream_Seek(s, 4);
988
989 UINT16 cookieLength = 0;
990 if (Stream_GetRemainingLength(s) < 2)
991 return 0;
992 Stream_Read_UINT16(s, cookieLength);
993
994 pduLength = Stream_GetPosition(s) + cookieLength;
995 }
996 break;
997 default:
998 WLog_Print(log, WLOG_ERROR, "invalid RDSLTS dataType");
999 return -1;
1000 }
1001
1002 if (pduLength > SSIZE_MAX)
1003 return 0;
1004 return (SSIZE_T)pduLength;
1005}
1006
1007SSIZE_T rdstls_parse_pdu(wLog* log, wStream* stream)
1008{
1009 SSIZE_T pduLength = -1;
1010 wStream sbuffer = { 0 };
1011 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
1012
1013 UINT16 version = 0;
1014 if (Stream_GetRemainingLength(s) < 2)
1015 return 0;
1016 Stream_Read_UINT16(s, version);
1017 if (version != RDSTLS_VERSION_1)
1018 {
1019 WLog_Print(log, WLOG_ERROR, "invalid RDSTLS version");
1020 return -1;
1021 }
1022
1023 UINT16 pduType = 0;
1024 if (Stream_GetRemainingLength(s) < 2)
1025 return 0;
1026 Stream_Read_UINT16(s, pduType);
1027 switch (pduType)
1028 {
1029 case RDSTLS_TYPE_CAPABILITIES:
1030 pduLength = 8;
1031 break;
1032 case RDSTLS_TYPE_AUTHREQ:
1033 if (Stream_GetRemainingLength(s) < 2)
1034 return 0;
1035 UINT16 dataType = 0;
1036 Stream_Read_UINT16(s, dataType);
1037 pduLength = rdstls_parse_pdu_data_type(log, dataType, s);
1038
1039 break;
1040 case RDSTLS_TYPE_AUTHRSP:
1041 pduLength = 10;
1042 break;
1043 default:
1044 WLog_Print(log, WLOG_ERROR, "invalid RDSTLS PDU type");
1045 return -1;
1046 }
1047
1048 return pduLength;
1049}
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.