Coverage Report

Created: 2025-07-01 06:46

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