Coverage Report

Created: 2024-09-08 06:20

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