FreeRDP
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 
47 typedef 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 
56 typedef 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 
69 struct 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 
80 static 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 }
112 rdpRdstls* 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 
139 void rdstls_free(rdpRdstls* rdstls)
140 {
141  free(rdstls);
142 }
143 
144 static 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 
163 static RDSTLS_STATE rdstls_get_state(rdpRdstls* rdstls)
164 {
165  WINPR_ASSERT(rdstls);
166  return rdstls->state;
167 }
168 
169 static 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 
183 static 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 
221 static BOOL rdstls_write_capabilities(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 
233 static 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 
264 static 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 
281 static 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 
307 static BOOL rdstls_write_authentication_request_with_cookie(rdpRdstls* rdstls, wStream* s)
308 {
309  // TODO
310  return FALSE;
311 }
312 
313 static BOOL rdstls_write_authentication_response(rdpRdstls* rdstls, wStream* s)
314 {
315  if (!Stream_EnsureRemainingCapacity(s, 8))
316  return FALSE;
317 
318  Stream_Write_UINT16(s, RDSTLS_TYPE_AUTHRSP);
319  Stream_Write_UINT16(s, RDSTLS_DATA_RESULT_CODE);
320  Stream_Write_UINT32(s, rdstls->resultCode);
321 
322  return TRUE;
323 }
324 
325 static BOOL rdstls_process_capabilities(rdpRdstls* rdstls, wStream* s)
326 {
327  UINT16 dataType = 0;
328  UINT16 supportedVersions = 0;
329 
330  if (Stream_GetRemainingLength(s) < 4)
331  return FALSE;
332 
333  Stream_Read_UINT16(s, dataType);
334  if (dataType != RDSTLS_DATA_CAPABILITIES)
335  {
336  WLog_Print(rdstls->log, WLOG_ERROR,
337  "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX16, dataType,
338  RDSTLS_DATA_CAPABILITIES);
339  return FALSE;
340  }
341 
342  Stream_Read_UINT16(s, supportedVersions);
343  if ((supportedVersions & RDSTLS_VERSION_1) == 0)
344  {
345  WLog_Print(rdstls->log, WLOG_ERROR,
346  "received invalid supportedVersions=0x%04" PRIX16 ", expected 0x%04" PRIX16,
347  supportedVersions, RDSTLS_VERSION_1);
348  return FALSE;
349  }
350 
351  return TRUE;
352 }
353 
354 static BOOL rdstls_read_unicode_string(wLog* log, wStream* s, char** str)
355 {
356  UINT16 length = 0;
357 
358  WINPR_ASSERT(str);
359 
360  if (Stream_GetRemainingLength(s) < 2)
361  return FALSE;
362 
363  Stream_Read_UINT16(s, length);
364 
365  if (Stream_GetRemainingLength(s) < length)
366  return FALSE;
367 
368  if (length <= 2)
369  {
370  Stream_Seek(s, length);
371  return TRUE;
372  }
373 
374  *str = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), NULL);
375  if (!*str)
376  return FALSE;
377 
378  return TRUE;
379 }
380 
381 static BOOL rdstls_read_data(wLog* log, wStream* s, UINT16* pLength, const BYTE** pData)
382 {
383  UINT16 length = 0;
384 
385  WINPR_ASSERT(pLength);
386  WINPR_ASSERT(pData);
387 
388  *pData = NULL;
389  *pLength = 0;
390  if (Stream_GetRemainingLength(s) < 2)
391  return FALSE;
392 
393  Stream_Read_UINT16(s, length);
394 
395  if (Stream_GetRemainingLength(s) < length)
396  return FALSE;
397 
398  if (length <= 2)
399  {
400  Stream_Seek(s, length);
401  return TRUE;
402  }
403 
404  *pData = Stream_ConstPointer(s);
405  *pLength = length;
406  Stream_Seek(s, length);
407  return TRUE;
408 }
409 
410 static BOOL rdstls_cmp_data(wLog* log, const char* field, const BYTE* serverData,
411  const UINT32 serverDataLength, const BYTE* clientData,
412  const UINT16 clientDataLength)
413 {
414  if (serverDataLength > 0)
415  {
416  if (clientDataLength == 0)
417  {
418  WLog_Print(log, WLOG_ERROR, "expected %s", field);
419  return FALSE;
420  }
421 
422  if (serverDataLength > UINT16_MAX || serverDataLength != clientDataLength ||
423  memcmp(serverData, clientData, serverDataLength) != 0)
424  {
425  WLog_Print(log, WLOG_ERROR, "%s verification failed", field);
426  return FALSE;
427  }
428  }
429 
430  return TRUE;
431 }
432 
433 static BOOL rdstls_cmp_str(wLog* log, const char* field, const char* serverStr,
434  const char* clientStr)
435 {
436  if (!utils_str_is_empty(serverStr))
437  {
438  if (utils_str_is_empty(clientStr))
439  {
440  WLog_Print(log, WLOG_ERROR, "expected %s", field);
441  return FALSE;
442  }
443 
444  WINPR_ASSERT(serverStr);
445  WINPR_ASSERT(clientStr);
446  if (strcmp(serverStr, clientStr) != 0)
447  {
448  WLog_Print(log, WLOG_ERROR, "%s verification failed", field);
449  return FALSE;
450  }
451  }
452 
453  return TRUE;
454 }
455 
456 static BOOL rdstls_process_authentication_request_with_password(rdpRdstls* rdstls, wStream* s)
457 {
458  BOOL rc = FALSE;
459 
460  const BYTE* clientRedirectionGuid = NULL;
461  UINT16 clientRedirectionGuidLength = 0;
462  char* clientPassword = NULL;
463  char* clientUsername = NULL;
464  char* clientDomain = NULL;
465 
466  const BYTE* serverRedirectionGuid = NULL;
467  const char* serverPassword = NULL;
468  const char* serverUsername = NULL;
469  const char* serverDomain = NULL;
470 
471  rdpSettings* settings = rdstls->context->settings;
472  WINPR_ASSERT(settings);
473 
474  if (!rdstls_read_data(rdstls->log, s, &clientRedirectionGuidLength, &clientRedirectionGuid))
475  goto fail;
476 
477  if (!rdstls_read_unicode_string(rdstls->log, s, &clientUsername))
478  goto fail;
479 
480  if (!rdstls_read_unicode_string(rdstls->log, s, &clientDomain))
481  goto fail;
482 
483  if (!rdstls_read_unicode_string(rdstls->log, s, &clientPassword))
484  goto fail;
485 
486  serverRedirectionGuid = freerdp_settings_get_pointer(settings, FreeRDP_RedirectionGuid);
487  const UINT32 serverRedirectionGuidLength =
488  freerdp_settings_get_uint32(settings, FreeRDP_RedirectionGuidLength);
489  serverUsername = freerdp_settings_get_string(settings, FreeRDP_Username);
490  serverDomain = freerdp_settings_get_string(settings, FreeRDP_Domain);
491  serverPassword = freerdp_settings_get_string(settings, FreeRDP_Password);
492 
493  rdstls->resultCode = RDSTLS_RESULT_SUCCESS;
494 
495  if (!rdstls_cmp_data(rdstls->log, "RedirectionGuid", serverRedirectionGuid,
496  serverRedirectionGuidLength, clientRedirectionGuid,
497  clientRedirectionGuidLength))
498  rdstls->resultCode = RDSTLS_RESULT_ACCESS_DENIED;
499 
500  if (!rdstls_cmp_str(rdstls->log, "UserName", serverUsername, clientUsername))
501  rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
502 
503  if (!rdstls_cmp_str(rdstls->log, "Domain", serverDomain, clientDomain))
504  rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
505 
506  if (!rdstls_cmp_str(rdstls->log, "Password", serverPassword, clientPassword))
507  rdstls->resultCode = RDSTLS_RESULT_LOGON_FAILURE;
508 
509  rc = TRUE;
510 fail:
511  return rc;
512 }
513 
514 static BOOL rdstls_process_authentication_request_with_cookie(rdpRdstls* rdstls, wStream* s)
515 {
516  // TODO
517  return FALSE;
518 }
519 
520 static BOOL rdstls_process_authentication_request(rdpRdstls* rdstls, wStream* s)
521 {
522  UINT16 dataType = 0;
523 
524  if (Stream_GetRemainingLength(s) < 2)
525  return FALSE;
526 
527  Stream_Read_UINT16(s, dataType);
528  switch (dataType)
529  {
530  case RDSTLS_DATA_PASSWORD_CREDS:
531  if (!rdstls_process_authentication_request_with_password(rdstls, s))
532  return FALSE;
533  break;
534  case RDSTLS_DATA_AUTORECONNECT_COOKIE:
535  if (!rdstls_process_authentication_request_with_cookie(rdstls, s))
536  return FALSE;
537  break;
538  default:
539  WLog_Print(rdstls->log, WLOG_ERROR,
540  "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX16
541  " or 0x%04" PRIX16,
542  dataType, RDSTLS_DATA_PASSWORD_CREDS, RDSTLS_DATA_AUTORECONNECT_COOKIE);
543  return FALSE;
544  }
545 
546  return TRUE;
547 }
548 
549 static BOOL rdstls_process_authentication_response(rdpRdstls* rdstls, wStream* s)
550 {
551  UINT16 dataType = 0;
552  UINT32 resultCode = 0;
553 
554  if (Stream_GetRemainingLength(s) < 6)
555  return FALSE;
556 
557  Stream_Read_UINT16(s, dataType);
558  if (dataType != RDSTLS_DATA_RESULT_CODE)
559  {
560  WLog_Print(rdstls->log, WLOG_ERROR,
561  "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX16, dataType,
562  RDSTLS_DATA_RESULT_CODE);
563  return FALSE;
564  }
565 
566  Stream_Read_UINT32(s, resultCode);
567  if (resultCode != RDSTLS_RESULT_SUCCESS)
568  {
569  WLog_Print(rdstls->log, WLOG_ERROR, "resultCode: %s [0x%08" PRIX32 "]",
570  rdstls_result_code_str(resultCode), resultCode);
571 
572  UINT32 error = ERROR_INTERNAL_ERROR;
573  switch (resultCode)
574  {
575  case RDSTLS_RESULT_ACCESS_DENIED:
576  error = FREERDP_ERROR_CONNECT_ACCESS_DENIED;
577  break;
578  case RDSTLS_RESULT_ACCOUNT_DISABLED:
579  error = FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED;
580  break;
581  case RDSTLS_RESULT_ACCOUNT_LOCKED_OUT:
582  error = FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT;
583  break;
584  case RDSTLS_RESULT_LOGON_FAILURE:
585  error = FREERDP_ERROR_CONNECT_LOGON_FAILURE;
586  break;
587  case RDSTLS_RESULT_INVALID_LOGON_HOURS:
588  error = FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION;
589  break;
590  case RDSTLS_RESULT_PASSWORD_EXPIRED:
591  error = FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED;
592  break;
593  case RDSTLS_RESULT_PASSWORD_MUST_CHANGE:
594  error = FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE;
595  break;
596  default:
597  error = ERROR_INVALID_PARAMETER;
598  break;
599  }
600 
601  freerdp_set_last_error_if_not(rdstls->context, error);
602  return FALSE;
603  }
604 
605  return TRUE;
606 }
607 
608 static BOOL rdstls_send(rdpTransport* transport, wStream* s, void* extra)
609 {
610  rdpRdstls* rdstls = (rdpRdstls*)extra;
611  rdpSettings* settings = NULL;
612 
613  WINPR_ASSERT(transport);
614  WINPR_ASSERT(s);
615  WINPR_ASSERT(rdstls);
616 
617  settings = rdstls->context->settings;
618  WINPR_ASSERT(settings);
619 
620  if (!Stream_EnsureRemainingCapacity(s, 2))
621  return FALSE;
622 
623  Stream_Write_UINT16(s, RDSTLS_VERSION_1);
624 
625  const RDSTLS_STATE state = rdstls_get_state(rdstls);
626  switch (state)
627  {
628  case RDSTLS_STATE_CAPABILITIES:
629  if (!rdstls_write_capabilities(rdstls, s))
630  return FALSE;
631  break;
632  case RDSTLS_STATE_AUTH_REQ:
633  if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED)
634  {
635  if (!rdstls_write_authentication_request_with_password(rdstls, s))
636  return FALSE;
637  }
638  else if (settings->ServerAutoReconnectCookie != NULL)
639  {
640  if (!rdstls_write_authentication_request_with_cookie(rdstls, s))
641  return FALSE;
642  }
643  else
644  {
645  WLog_Print(rdstls->log, WLOG_ERROR,
646  "cannot authenticate with password or auto-reconnect cookie");
647  return FALSE;
648  }
649  break;
650  case RDSTLS_STATE_AUTH_RSP:
651  if (!rdstls_write_authentication_response(rdstls, s))
652  return FALSE;
653  break;
654  default:
655  WLog_Print(rdstls->log, WLOG_ERROR, "Invalid rdstls state %s [%d]",
656  rdstls_get_state_str(state), state);
657  return FALSE;
658  }
659 
660  if (transport_write(rdstls->transport, s) < 0)
661  return FALSE;
662 
663  return TRUE;
664 }
665 
666 static int rdstls_recv(rdpTransport* transport, wStream* s, void* extra)
667 {
668  UINT16 version = 0;
669  UINT16 pduType = 0;
670  rdpRdstls* rdstls = (rdpRdstls*)extra;
671 
672  WINPR_ASSERT(transport);
673  WINPR_ASSERT(s);
674  WINPR_ASSERT(rdstls);
675 
676  if (Stream_GetRemainingLength(s) < 4)
677  return FALSE;
678 
679  Stream_Read_UINT16(s, version);
680  if (version != RDSTLS_VERSION_1)
681  {
682  WLog_Print(rdstls->log, WLOG_ERROR,
683  "received invalid RDSTLS Version=0x%04" PRIX16 ", expected 0x%04" PRIX16,
684  version, RDSTLS_VERSION_1);
685  return -1;
686  }
687 
688  Stream_Read_UINT16(s, pduType);
689  switch (pduType)
690  {
691  case RDSTLS_TYPE_CAPABILITIES:
692  if (!rdstls_process_capabilities(rdstls, s))
693  return -1;
694  break;
695  case RDSTLS_TYPE_AUTHREQ:
696  if (!rdstls_process_authentication_request(rdstls, s))
697  return -1;
698  break;
699  case RDSTLS_TYPE_AUTHRSP:
700  if (!rdstls_process_authentication_response(rdstls, s))
701  return -1;
702  break;
703  default:
704  WLog_Print(rdstls->log, WLOG_ERROR, "unknown RDSTLS PDU type [0x%04" PRIx16 "]",
705  pduType);
706  return -1;
707  }
708 
709  return 1;
710 }
711 
712 #define rdstls_check_state_requirements(rdstls, expected) \
713  rdstls_check_state_requirements_((rdstls), (expected), __FILE__, __func__, __LINE__)
714 static BOOL rdstls_check_state_requirements_(rdpRdstls* rdstls, RDSTLS_STATE expected,
715  const char* file, const char* fkt, size_t line)
716 {
717  const RDSTLS_STATE current = rdstls_get_state(rdstls);
718  if (current == expected)
719  return TRUE;
720 
721  const DWORD log_level = WLOG_ERROR;
722  if (WLog_IsLevelActive(rdstls->log, log_level))
723  WLog_PrintMessage(rdstls->log, WLOG_MESSAGE_TEXT, log_level, line, file, fkt,
724  "Unexpected rdstls state %s [%d], expected %s [%d]",
725  rdstls_get_state_str(current), current, rdstls_get_state_str(expected),
726  expected);
727 
728  return FALSE;
729 }
730 
731 static BOOL rdstls_send_capabilities(rdpRdstls* rdstls)
732 {
733  BOOL rc = FALSE;
734  wStream* s = NULL;
735 
736  if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
737  goto fail;
738 
739  s = Stream_New(NULL, 512);
740  if (!s)
741  goto fail;
742 
743  if (!rdstls_send(rdstls->transport, s, rdstls))
744  goto fail;
745 
746  rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
747 fail:
748  Stream_Free(s, TRUE);
749  return rc;
750 }
751 
752 static BOOL rdstls_recv_authentication_request(rdpRdstls* rdstls)
753 {
754  BOOL rc = FALSE;
755  int status = 0;
756  wStream* s = NULL;
757 
758  if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
759  goto fail;
760 
761  s = Stream_New(NULL, 4096);
762  if (!s)
763  goto fail;
764 
765  status = transport_read_pdu(rdstls->transport, s);
766 
767  if (status < 0)
768  goto fail;
769 
770  status = rdstls_recv(rdstls->transport, s, rdstls);
771 
772  if (status < 0)
773  goto fail;
774 
775  rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
776 fail:
777  Stream_Free(s, TRUE);
778  return rc;
779 }
780 
781 static BOOL rdstls_send_authentication_response(rdpRdstls* rdstls)
782 {
783  BOOL rc = FALSE;
784  wStream* s = NULL;
785 
786  if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
787  goto fail;
788 
789  s = Stream_New(NULL, 512);
790  if (!s)
791  goto fail;
792 
793  if (!rdstls_send(rdstls->transport, s, rdstls))
794  goto fail;
795 
796  rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
797 fail:
798  Stream_Free(s, TRUE);
799  return rc;
800 }
801 
802 static BOOL rdstls_recv_capabilities(rdpRdstls* rdstls)
803 {
804  BOOL rc = FALSE;
805  int status = 0;
806  wStream* s = NULL;
807 
808  if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_CAPABILITIES))
809  goto fail;
810 
811  s = Stream_New(NULL, 512);
812  if (!s)
813  goto fail;
814 
815  status = transport_read_pdu(rdstls->transport, s);
816 
817  if (status < 0)
818  goto fail;
819 
820  status = rdstls_recv(rdstls->transport, s, rdstls);
821 
822  if (status < 0)
823  goto fail;
824 
825  rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_REQ);
826 fail:
827  Stream_Free(s, TRUE);
828  return rc;
829 }
830 
831 static BOOL rdstls_send_authentication_request(rdpRdstls* rdstls)
832 {
833  BOOL rc = FALSE;
834  wStream* s = NULL;
835 
836  if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_REQ))
837  goto fail;
838 
839  s = Stream_New(NULL, 4096);
840  if (!s)
841  goto fail;
842 
843  if (!rdstls_send(rdstls->transport, s, rdstls))
844  goto fail;
845 
846  rc = rdstls_set_state(rdstls, RDSTLS_STATE_AUTH_RSP);
847 fail:
848  Stream_Free(s, TRUE);
849  return rc;
850 }
851 
852 static BOOL rdstls_recv_authentication_response(rdpRdstls* rdstls)
853 {
854  BOOL rc = FALSE;
855  int status = 0;
856  wStream* s = NULL;
857 
858  WINPR_ASSERT(rdstls);
859 
860  if (!rdstls_check_state_requirements(rdstls, RDSTLS_STATE_AUTH_RSP))
861  goto fail;
862 
863  s = Stream_New(NULL, 512);
864  if (!s)
865  goto fail;
866 
867  status = transport_read_pdu(rdstls->transport, s);
868 
869  if (status < 0)
870  goto fail;
871 
872  status = rdstls_recv(rdstls->transport, s, rdstls);
873 
874  if (status < 0)
875  goto fail;
876 
877  rc = rdstls_set_state(rdstls, RDSTLS_STATE_FINAL);
878 fail:
879  Stream_Free(s, TRUE);
880  return rc;
881 }
882 
883 static int rdstls_server_authenticate(rdpRdstls* rdstls)
884 {
885  if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
886  return -1;
887 
888  if (!rdstls_send_capabilities(rdstls))
889  return -1;
890 
891  if (!rdstls_recv_authentication_request(rdstls))
892  return -1;
893 
894  if (!rdstls_send_authentication_response(rdstls))
895  return -1;
896 
897  if (rdstls->resultCode != RDSTLS_RESULT_SUCCESS)
898  return -1;
899 
900  return 1;
901 }
902 
903 static int rdstls_client_authenticate(rdpRdstls* rdstls)
904 {
905  if (!rdstls_set_state(rdstls, RDSTLS_STATE_CAPABILITIES))
906  return -1;
907 
908  if (!rdstls_recv_capabilities(rdstls))
909  return -1;
910 
911  if (!rdstls_send_authentication_request(rdstls))
912  return -1;
913 
914  if (!rdstls_recv_authentication_response(rdstls))
915  return -1;
916 
917  return 1;
918 }
919 
927 int rdstls_authenticate(rdpRdstls* rdstls)
928 {
929  WINPR_ASSERT(rdstls);
930 
931  if (rdstls->server)
932  return rdstls_server_authenticate(rdstls);
933  else
934  return rdstls_client_authenticate(rdstls);
935 }
936 
937 static SSIZE_T rdstls_parse_pdu_data_type(wLog* log, UINT16 dataType, wStream* s)
938 {
939  switch (dataType)
940  {
941  case RDSTLS_DATA_PASSWORD_CREDS:
942  {
943  UINT16 redirGuidLength = 0;
944  if (Stream_GetRemainingLength(s) < 2)
945  return 0;
946  Stream_Read_UINT16(s, redirGuidLength);
947 
948  if (Stream_GetRemainingLength(s) < redirGuidLength)
949  return 0;
950  Stream_Seek(s, redirGuidLength);
951 
952  UINT16 usernameLength = 0;
953  if (Stream_GetRemainingLength(s) < 2)
954  return 0;
955  Stream_Read_UINT16(s, usernameLength);
956 
957  if (Stream_GetRemainingLength(s) < usernameLength)
958  return 0;
959  Stream_Seek(s, usernameLength);
960 
961  UINT16 domainLength = 0;
962  if (Stream_GetRemainingLength(s) < 2)
963  return 0;
964  Stream_Read_UINT16(s, domainLength);
965 
966  if (Stream_GetRemainingLength(s) < domainLength)
967  return 0;
968  Stream_Seek(s, domainLength);
969 
970  UINT16 passwordLength = 0;
971  if (Stream_GetRemainingLength(s) < 2)
972  return 0;
973  Stream_Read_UINT16(s, passwordLength);
974 
975  if (Stream_GetRemainingLength(s) < passwordLength)
976  return 0;
977  Stream_Seek(s, passwordLength);
978  }
979  break;
980  case RDSTLS_DATA_AUTORECONNECT_COOKIE:
981  {
982  if (Stream_GetRemainingLength(s) < 4)
983  return 0;
984  Stream_Seek(s, 4);
985 
986  UINT16 cookieLength = 0;
987  if (Stream_GetRemainingLength(s) < 2)
988  return 0;
989  Stream_Read_UINT16(s, cookieLength);
990  if (!Stream_SafeSeek(s, cookieLength))
991  return 0;
992  }
993  break;
994  default:
995  WLog_Print(log, WLOG_ERROR, "invalid RDSLTS dataType");
996  return -1;
997  }
998 
999  const size_t len = Stream_GetPosition(s);
1000  if (len > SSIZE_MAX)
1001  return 0;
1002  return (SSIZE_T)len;
1003 }
1004 
1005 SSIZE_T rdstls_parse_pdu(wLog* log, wStream* stream)
1006 {
1007  SSIZE_T pduLength = -1;
1008  wStream sbuffer = { 0 };
1009  wStream* s = Stream_StaticConstInit(&sbuffer, Stream_Buffer(stream), Stream_Length(stream));
1010 
1011  UINT16 version = 0;
1012  if (Stream_GetRemainingLength(s) < 2)
1013  return 0;
1014  Stream_Read_UINT16(s, version);
1015  if (version != RDSTLS_VERSION_1)
1016  {
1017  WLog_Print(log, WLOG_ERROR, "invalid RDSTLS version");
1018  return -1;
1019  }
1020 
1021  UINT16 pduType = 0;
1022  if (Stream_GetRemainingLength(s) < 2)
1023  return 0;
1024  Stream_Read_UINT16(s, pduType);
1025  switch (pduType)
1026  {
1027  case RDSTLS_TYPE_CAPABILITIES:
1028  pduLength = 8;
1029  break;
1030  case RDSTLS_TYPE_AUTHREQ:
1031  if (Stream_GetRemainingLength(s) < 2)
1032  return 0;
1033  UINT16 dataType = 0;
1034  Stream_Read_UINT16(s, dataType);
1035  pduLength = rdstls_parse_pdu_data_type(log, dataType, s);
1036 
1037  break;
1038  case RDSTLS_TYPE_AUTHRSP:
1039  pduLength = 10;
1040  break;
1041  default:
1042  WLog_Print(log, WLOG_ERROR, "invalid RDSTLS PDU type");
1043  return -1;
1044  }
1045 
1046  return pduLength;
1047 }
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.