Coverage Report

Created: 2026-10-15 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/nego.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RDP Protocol Security Negotiation
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
7
 * Copyright 2015 Thincast Technologies GmbH
8
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 *     http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22
23
#include <freerdp/config.h>
24
25
#include <winpr/crt.h>
26
#include <winpr/assert.h>
27
#include <winpr/stream.h>
28
29
#include <freerdp/log.h>
30
31
#include "tpkt.h"
32
33
#include "nego.h"
34
#include "aad.h"
35
36
#include "transport.h"
37
38
21.4k
#define NEGO_TAG FREERDP_TAG("core.nego")
39
40
struct rdp_nego
41
{
42
  UINT16 port;
43
  UINT32 flags;
44
  const char* hostname;
45
  char* cookie;
46
  BYTE* RoutingToken;
47
  DWORD RoutingTokenLength;
48
  BOOL SendPreconnectionPdu;
49
  UINT32 PreconnectionId;
50
  const char* PreconnectionBlob;
51
52
  NEGO_STATE state;
53
  BOOL TcpConnected;
54
  BOOL SecurityConnected;
55
  UINT32 CookieMaxLength;
56
57
  BOOL sendNegoData;
58
  UINT32 SelectedProtocol;
59
  UINT32 RequestedProtocols;
60
  UINT32 failureCode; /* last RDP_NEG_FAILURE::failureCode received, 0 if none */
61
  BOOL NegotiateSecurityLayer;
62
  BOOL EnabledProtocols[32];
63
  BOOL RestrictedAdminModeRequired;  /* Client-side */
64
  BOOL RestrictedAdminModeSupported; /* Server-side */
65
  BOOL RemoteCredsGuardRequired;
66
  BOOL RemoteCredsGuardActive;
67
  BOOL RemoteCredsGuardSupported;
68
  BOOL GatewayEnabled;
69
  BOOL GatewayBypassLocal;
70
  BOOL ConnectChildSession;
71
72
  rdpTransport* transport;
73
  wLog* log;
74
};
75
76
WINPR_ATTR_NODISCARD
77
static const char* nego_state_string(NEGO_STATE state)
78
0
{
79
0
  static const char* const NEGO_STATE_STRINGS[] = { "NEGO_STATE_INITIAL", "NEGO_STATE_RDSTLS",
80
0
                                                  "NEGO_STATE_AAD",     "NEGO_STATE_EXT",
81
0
                                                  "NEGO_STATE_NLA",     "NEGO_STATE_TLS",
82
0
                                                  "NEGO_STATE_RDP",     "NEGO_STATE_FAIL",
83
0
                                                  "NEGO_STATE_FINAL",   "NEGO_STATE_INVALID" };
84
0
  if (state >= ARRAYSIZE(NEGO_STATE_STRINGS))
85
0
    return NEGO_STATE_STRINGS[ARRAYSIZE(NEGO_STATE_STRINGS) - 1];
86
0
  return NEGO_STATE_STRINGS[state];
87
0
}
88
89
WINPR_ATTR_NODISCARD
90
static BOOL nego_tcp_connect(rdpNego* nego);
91
92
WINPR_ATTR_NODISCARD
93
static BOOL nego_transport_connect(rdpNego* nego);
94
95
static BOOL nego_transport_disconnect(rdpNego* nego);
96
97
WINPR_ATTR_NODISCARD
98
static BOOL nego_security_connect(rdpNego* nego);
99
100
WINPR_ATTR_NODISCARD
101
static BOOL nego_send_preconnection_pdu(rdpNego* nego);
102
103
WINPR_ATTR_NODISCARD
104
static BOOL nego_recv_response(rdpNego* nego);
105
106
static void nego_send(rdpNego* nego);
107
108
WINPR_ATTR_NODISCARD
109
static BOOL nego_process_negotiation_request(rdpNego* nego, wStream* s);
110
111
WINPR_ATTR_NODISCARD
112
static BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s);
113
114
WINPR_ATTR_NODISCARD
115
static BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s);
116
117
WINPR_ATTR_NODISCARD
118
static const char* nego_rdp_neg_fail_str(uint32_t what);
119
120
/* Map a RDP_NEG_FAILURE::failureCode to a connection error.
121
 *
122
 * Only meaningful once the negotiation has terminally failed: a failure code on its own
123
 * is usually recoverable by falling back to another security protocol.
124
 */
125
WINPR_ATTR_NODISCARD
126
static UINT32 nego_failure_to_error(uint32_t failureCode)
127
0
{
128
0
  switch (failureCode)
129
0
  {
130
0
    case SSL_CERT_NOT_ON_SERVER:
131
      /* The server has no certificate, so neither TLS nor NLA can be used. */
132
0
      return FREERDP_ERROR_TLS_CONNECT_FAILED;
133
134
0
    case HYBRID_REQUIRED_BY_SERVER:
135
      /* The server insists on NLA, but it is not enabled in the client settings.
136
       * Reaching this point means the fallback found no other usable protocol. */
137
0
      return FREERDP_ERROR_CONNECT_HYBRID_REQUIRED_BY_SERVER;
138
139
0
    default:
140
      /* The server rejected every security protocol we were permitted to offer. */
141
0
      return FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED;
142
0
  }
143
0
}
144
145
BOOL nego_update_settings_from_state(rdpNego* nego, rdpSettings* settings)
146
0
{
147
0
  WINPR_ASSERT(nego);
148
149
  /* update settings with negotiated protocol security */
150
0
  return freerdp_settings_set_uint32(settings, FreeRDP_RequestedProtocols,
151
0
                                     nego->RequestedProtocols) &&
152
0
         freerdp_settings_set_uint32(settings, FreeRDP_SelectedProtocol,
153
0
                                     nego->SelectedProtocol) &&
154
0
         freerdp_settings_set_uint32(settings, FreeRDP_NegotiationFlags, nego->flags);
155
0
}
156
157
/**
158
 * Negotiate protocol security and connect.
159
 *
160
 * @param nego A pointer to the NEGO struct
161
 *
162
 * @return \b TRUE for success, \b FALSE otherwise
163
 */
164
165
BOOL nego_connect(rdpNego* nego)
166
0
{
167
0
  rdpContext* context = nullptr;
168
0
  rdpSettings* settings = nullptr;
169
0
  WINPR_ASSERT(nego);
170
0
  context = transport_get_context(nego->transport);
171
0
  WINPR_ASSERT(context);
172
0
  settings = context->settings;
173
0
  WINPR_ASSERT(settings);
174
175
0
  if (nego_get_state(nego) == NEGO_STATE_INITIAL)
176
0
  {
177
0
    if (nego->EnabledProtocols[PROTOCOL_RDSAAD])
178
0
    {
179
0
      nego_set_state(nego, NEGO_STATE_AAD);
180
0
    }
181
0
    else if (nego->EnabledProtocols[PROTOCOL_RDSTLS])
182
0
    {
183
0
      nego_set_state(nego, NEGO_STATE_RDSTLS);
184
0
    }
185
0
    else if (nego->EnabledProtocols[PROTOCOL_HYBRID_EX])
186
0
    {
187
0
      nego_set_state(nego, NEGO_STATE_EXT);
188
0
    }
189
0
    else if (nego->EnabledProtocols[PROTOCOL_HYBRID])
190
0
    {
191
0
      nego_set_state(nego, NEGO_STATE_NLA);
192
0
    }
193
0
    else if (nego->EnabledProtocols[PROTOCOL_SSL])
194
0
    {
195
0
      nego_set_state(nego, NEGO_STATE_TLS);
196
0
    }
197
0
    else if (nego->EnabledProtocols[PROTOCOL_RDP])
198
0
    {
199
0
      nego_set_state(nego, NEGO_STATE_RDP);
200
0
    }
201
0
    else
202
0
    {
203
0
      WLog_Print(nego->log, WLOG_ERROR, "No security protocol is enabled");
204
0
      nego_set_state(nego, NEGO_STATE_FAIL);
205
0
      return FALSE;
206
0
    }
207
208
0
    if (!nego->NegotiateSecurityLayer)
209
0
    {
210
0
      WLog_Print(nego->log, WLOG_DEBUG, "Security Layer Negotiation is disabled");
211
      /* attempt only the highest enabled protocol (see nego_attempt_*) */
212
0
      nego->EnabledProtocols[PROTOCOL_RDSAAD] = FALSE;
213
0
      nego->EnabledProtocols[PROTOCOL_HYBRID] = FALSE;
214
0
      nego->EnabledProtocols[PROTOCOL_SSL] = FALSE;
215
0
      nego->EnabledProtocols[PROTOCOL_RDP] = FALSE;
216
0
      nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = FALSE;
217
0
      nego->EnabledProtocols[PROTOCOL_RDSTLS] = FALSE;
218
219
0
      UINT32 SelectedProtocol = 0;
220
0
      switch (nego_get_state(nego))
221
0
      {
222
0
        case NEGO_STATE_AAD:
223
0
          nego->EnabledProtocols[PROTOCOL_RDSAAD] = TRUE;
224
0
          SelectedProtocol = PROTOCOL_RDSAAD;
225
0
          break;
226
0
        case NEGO_STATE_RDSTLS:
227
0
          nego->EnabledProtocols[PROTOCOL_RDSTLS] = TRUE;
228
0
          SelectedProtocol = PROTOCOL_RDSTLS;
229
0
          break;
230
0
        case NEGO_STATE_EXT:
231
0
          nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = TRUE;
232
0
          nego->EnabledProtocols[PROTOCOL_HYBRID] = TRUE;
233
0
          SelectedProtocol = PROTOCOL_HYBRID_EX;
234
0
          break;
235
0
        case NEGO_STATE_NLA:
236
0
          nego->EnabledProtocols[PROTOCOL_HYBRID] = TRUE;
237
0
          SelectedProtocol = PROTOCOL_HYBRID;
238
0
          break;
239
0
        case NEGO_STATE_TLS:
240
0
          nego->EnabledProtocols[PROTOCOL_SSL] = TRUE;
241
0
          SelectedProtocol = PROTOCOL_SSL;
242
0
          break;
243
0
        case NEGO_STATE_RDP:
244
0
          nego->EnabledProtocols[PROTOCOL_RDP] = TRUE;
245
0
          SelectedProtocol = PROTOCOL_RDP;
246
0
          break;
247
0
        default:
248
0
          WLog_Print(nego->log, WLOG_ERROR, "Invalid NEGO state 0x%08" PRIx32,
249
0
                     nego_get_state(nego));
250
0
          return FALSE;
251
0
      }
252
0
      if (!nego_set_selected_protocol(nego, SelectedProtocol))
253
0
        return FALSE;
254
0
    }
255
256
0
    if (!nego_tcp_connect(nego))
257
0
    {
258
0
      WLog_Print(nego->log, WLOG_ERROR, "Failed to connect");
259
0
      return FALSE;
260
0
    }
261
262
0
    if (nego->SendPreconnectionPdu)
263
0
    {
264
0
      if (!nego_send_preconnection_pdu(nego))
265
0
      {
266
0
        WLog_Print(nego->log, WLOG_ERROR, "Failed to send preconnection pdu");
267
0
        nego_set_state(nego, NEGO_STATE_FINAL);
268
0
        return FALSE;
269
0
      }
270
0
    }
271
0
  }
272
273
0
  if (!nego->NegotiateSecurityLayer)
274
0
  {
275
0
    nego_set_state(nego, NEGO_STATE_FINAL);
276
0
  }
277
0
  else
278
0
  {
279
0
    do
280
0
    {
281
0
      WLog_Print(nego->log, WLOG_DEBUG, "state: %s", nego_state_string(nego_get_state(nego)));
282
0
      nego_send(nego);
283
284
0
      if (nego_get_state(nego) == NEGO_STATE_FAIL)
285
0
      {
286
0
        if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
287
0
        {
288
0
          if (nego->failureCode != 0)
289
0
            WLog_Print(nego->log, WLOG_ERROR,
290
0
                       "Protocol Security Negotiation Failure: %s [0x%08" PRIx32 "]",
291
0
                       nego_rdp_neg_fail_str(nego->failureCode), nego->failureCode);
292
0
          else
293
0
            WLog_Print(nego->log, WLOG_ERROR, "Protocol Security Negotiation Failure");
294
0
        }
295
296
0
        if (nego->failureCode != 0)
297
0
          freerdp_set_last_error_if_not(context,
298
0
                                        nego_failure_to_error(nego->failureCode));
299
300
0
        nego_set_state(nego, NEGO_STATE_FINAL);
301
0
        return FALSE;
302
0
      }
303
0
    } while (nego_get_state(nego) != NEGO_STATE_FINAL);
304
0
  }
305
306
0
  {
307
0
    char buffer[64] = WINPR_C_ARRAY_INIT;
308
0
    WLog_Print(nego->log, WLOG_DEBUG, "Negotiated %s security",
309
0
               nego_protocol_to_str(nego->SelectedProtocol, buffer, sizeof(buffer)));
310
0
  }
311
312
  /* update settings with negotiated protocol security */
313
0
  if (!nego_update_settings_from_state(nego, settings))
314
0
    return FALSE;
315
316
0
  if (nego->SelectedProtocol == PROTOCOL_RDP)
317
0
  {
318
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, TRUE))
319
0
      return FALSE;
320
321
0
    if (freerdp_settings_get_uint32(settings, FreeRDP_EncryptionMethods) == 0)
322
0
    {
323
      /**
324
       * Advertise all supported encryption methods if the client
325
       * implementation did not set any security methods
326
       */
327
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionMethods,
328
0
                                       ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT |
329
0
                                           ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS))
330
0
        return FALSE;
331
0
    }
332
0
  }
333
334
  /* finally connect security layer (if not already done) */
335
0
  if (!nego_security_connect(nego))
336
0
  {
337
0
    char buffer[64] = WINPR_C_ARRAY_INIT;
338
0
    WLog_Print(nego->log, WLOG_DEBUG, "Failed to connect with %s security",
339
0
               nego_protocol_to_str(nego->SelectedProtocol, buffer, sizeof(buffer)));
340
0
    return FALSE;
341
0
  }
342
343
0
  return TRUE;
344
0
}
345
346
BOOL nego_disconnect(rdpNego* nego)
347
0
{
348
0
  WINPR_ASSERT(nego);
349
0
  nego_set_state(nego, NEGO_STATE_INITIAL);
350
0
  return nego_transport_disconnect(nego);
351
0
}
352
353
WINPR_ATTR_NODISCARD
354
static BOOL nego_try_connect(rdpNego* nego)
355
0
{
356
0
  WINPR_ASSERT(nego);
357
358
0
  switch (nego->SelectedProtocol)
359
0
  {
360
0
    case PROTOCOL_RDSAAD:
361
0
      WLog_Print(nego->log, WLOG_DEBUG, "nego_security_connect with PROTOCOL_RDSAAD");
362
0
      nego->SecurityConnected = transport_connect_aad(nego->transport);
363
0
      break;
364
0
    case PROTOCOL_RDSTLS:
365
0
      WLog_Print(nego->log, WLOG_DEBUG, "nego_security_connect with PROTOCOL_RDSTLS");
366
0
      nego->SecurityConnected = transport_connect_rdstls(nego->transport);
367
0
      break;
368
0
    case PROTOCOL_HYBRID:
369
0
      WLog_Print(nego->log, WLOG_DEBUG, "nego_security_connect with PROTOCOL_HYBRID");
370
0
      nego->SecurityConnected = transport_connect_nla(nego->transport, FALSE);
371
0
      break;
372
0
    case PROTOCOL_HYBRID_EX:
373
0
      WLog_Print(nego->log, WLOG_DEBUG, "nego_security_connect with PROTOCOL_HYBRID_EX");
374
0
      nego->SecurityConnected = transport_connect_nla(nego->transport, TRUE);
375
0
      break;
376
0
    case PROTOCOL_SSL:
377
0
      WLog_Print(nego->log, WLOG_DEBUG, "nego_security_connect with PROTOCOL_SSL");
378
0
      nego->SecurityConnected = transport_connect_tls(nego->transport);
379
0
      break;
380
0
    case PROTOCOL_RDP:
381
0
      WLog_Print(nego->log, WLOG_DEBUG, "nego_security_connect with PROTOCOL_RDP");
382
0
      nego->SecurityConnected = transport_connect_rdp(nego->transport);
383
0
      break;
384
0
    default:
385
0
      WLog_Print(nego->log, WLOG_ERROR,
386
0
                 "cannot connect security layer because no protocol has been selected yet.");
387
0
      return FALSE;
388
0
  }
389
0
  return nego->SecurityConnected;
390
0
}
391
392
/* connect to selected security layer */
393
BOOL nego_security_connect(rdpNego* nego)
394
0
{
395
0
  WINPR_ASSERT(nego);
396
0
  if (!nego->TcpConnected)
397
0
  {
398
0
    nego->SecurityConnected = FALSE;
399
0
  }
400
0
  else if (!nego->SecurityConnected)
401
0
  {
402
0
    if (!nego_try_connect(nego))
403
0
      return FALSE;
404
0
  }
405
406
0
  return nego->SecurityConnected;
407
0
}
408
409
WINPR_ATTR_NODISCARD
410
static BOOL nego_tcp_connect(rdpNego* nego)
411
0
{
412
0
  rdpContext* context = nullptr;
413
0
  WINPR_ASSERT(nego);
414
0
  if (!nego->TcpConnected)
415
0
  {
416
0
    UINT32 TcpConnectTimeout = 0;
417
418
0
    context = transport_get_context(nego->transport);
419
0
    WINPR_ASSERT(context);
420
421
0
    TcpConnectTimeout =
422
0
        freerdp_settings_get_uint32(context->settings, FreeRDP_TcpConnectTimeout);
423
424
0
    if (nego->GatewayEnabled)
425
0
    {
426
0
      if (nego->GatewayBypassLocal)
427
0
      {
428
        /* Attempt a direct connection first, and then fallback to using the gateway */
429
0
        WLog_Print(
430
0
            nego->log, WLOG_INFO,
431
0
            "Detecting if host can be reached locally. - This might take some time.");
432
0
        WLog_Print(nego->log, WLOG_INFO,
433
0
                   "To disable auto detection use /gateway-usage-method:direct");
434
0
        transport_set_gateway_enabled(nego->transport, FALSE);
435
0
        nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port,
436
0
                                               TcpConnectTimeout);
437
0
      }
438
439
0
      if (!nego->TcpConnected)
440
0
      {
441
0
        transport_set_gateway_enabled(nego->transport, TRUE);
442
0
        nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port,
443
0
                                               TcpConnectTimeout);
444
0
      }
445
0
    }
446
0
    else if (nego->ConnectChildSession)
447
0
    {
448
0
      nego->TcpConnected = transport_connect_childsession(nego->transport);
449
0
    }
450
0
    else
451
0
    {
452
0
      nego->TcpConnected =
453
0
          transport_connect(nego->transport, nego->hostname, nego->port, TcpConnectTimeout);
454
0
    }
455
0
  }
456
457
0
  return nego->TcpConnected;
458
0
}
459
460
/**
461
 * Connect TCP layer. For direct approach, connect security layer as well.
462
 *
463
 * @param nego A pointer to the NEGO struct
464
 *
465
 * @return \b TRUE for success, \b FALSE otherwise
466
 */
467
468
BOOL nego_transport_connect(rdpNego* nego)
469
0
{
470
0
  WINPR_ASSERT(nego);
471
0
  if (!nego_tcp_connect(nego))
472
0
    return FALSE;
473
474
0
  if (nego->TcpConnected && !nego->NegotiateSecurityLayer)
475
0
    return nego_security_connect(nego);
476
477
0
  return nego->TcpConnected;
478
0
}
479
480
/**
481
 * Disconnect TCP layer.
482
 *
483
 * @param nego A pointer to the NEGO struct
484
 *
485
 * @return \b TRUE for success, \b FALSE otherwise
486
 */
487
488
BOOL nego_transport_disconnect(rdpNego* nego)
489
0
{
490
0
  WINPR_ASSERT(nego);
491
0
  if (nego->TcpConnected)
492
0
    transport_disconnect(nego->transport);
493
494
0
  nego->TcpConnected = FALSE;
495
0
  nego->SecurityConnected = FALSE;
496
0
  return TRUE;
497
0
}
498
499
/**
500
 * Send preconnection information if enabled.
501
 *
502
 * @param nego A pointer to the NEGO struct
503
 *
504
 * @return \b TRUE for success, \b FALSE otherwise
505
 */
506
507
BOOL nego_send_preconnection_pdu(rdpNego* nego)
508
0
{
509
0
  wStream* s = nullptr;
510
0
  UINT32 cbSize = 0;
511
0
  UINT16 cchPCB = 0;
512
0
  WCHAR* wszPCB = nullptr;
513
514
0
  WINPR_ASSERT(nego);
515
516
0
  WLog_Print(nego->log, WLOG_DEBUG, "Sending preconnection PDU");
517
518
0
  if (!nego_tcp_connect(nego))
519
0
    return FALSE;
520
521
  /* it's easier to always send the version 2 PDU, and it's just 2 bytes overhead */
522
0
  cbSize = PRECONNECTION_PDU_V2_MIN_SIZE;
523
524
0
  if (nego->PreconnectionBlob)
525
0
  {
526
0
    size_t len = 0;
527
0
    wszPCB = ConvertUtf8ToWCharAlloc(nego->PreconnectionBlob, &len);
528
0
    if (len > UINT16_MAX - 1)
529
0
    {
530
0
      free(wszPCB);
531
0
      return FALSE;
532
0
    }
533
0
    cchPCB = (UINT16)len;
534
0
    cchPCB += 1; /* zero-termination */
535
0
    cbSize += cchPCB * sizeof(WCHAR);
536
0
  }
537
538
0
  s = Stream_New(nullptr, cbSize);
539
540
0
  if (!s)
541
0
  {
542
0
    free(wszPCB);
543
0
    WLog_Print(nego->log, WLOG_ERROR, "Stream_New failed!");
544
0
    return FALSE;
545
0
  }
546
547
0
  Stream_Write_UINT32(s, cbSize);                /* cbSize */
548
0
  Stream_Write_UINT32(s, 0);                     /* Flags */
549
0
  Stream_Write_UINT32(s, PRECONNECTION_PDU_V2);  /* Version */
550
0
  Stream_Write_UINT32(s, nego->PreconnectionId); /* Id */
551
0
  Stream_Write_UINT16(s, cchPCB);                /* cchPCB */
552
553
0
  if (wszPCB)
554
0
  {
555
0
    Stream_Write(s, wszPCB, cchPCB * sizeof(WCHAR)); /* wszPCB */
556
0
    free(wszPCB);
557
0
  }
558
559
0
  Stream_SealLength(s);
560
561
0
  if (transport_write(nego->transport, s) < 0)
562
0
  {
563
0
    Stream_Free(s, TRUE);
564
0
    return FALSE;
565
0
  }
566
567
0
  Stream_Free(s, TRUE);
568
0
  return TRUE;
569
0
}
570
571
static void nego_attempt_rdstls(rdpNego* nego)
572
0
{
573
0
  WINPR_ASSERT(nego);
574
0
  nego->RequestedProtocols = PROTOCOL_RDSTLS | PROTOCOL_SSL;
575
0
  WLog_Print(nego->log, WLOG_DEBUG, "Attempting RDSTLS security");
576
577
0
  if (!nego_transport_connect(nego))
578
0
  {
579
0
    nego_set_state(nego, NEGO_STATE_FAIL);
580
0
    return;
581
0
  }
582
583
0
  if (!nego_send_negotiation_request(nego))
584
0
  {
585
0
    nego_set_state(nego, NEGO_STATE_FAIL);
586
0
    return;
587
0
  }
588
589
0
  if (!nego_recv_response(nego))
590
0
  {
591
0
    nego_set_state(nego, NEGO_STATE_FAIL);
592
0
    return;
593
0
  }
594
595
0
  WLog_Print(nego->log, WLOG_DEBUG, "state: %s", nego_state_string(nego_get_state(nego)));
596
597
0
  if (nego_get_state(nego) != NEGO_STATE_FINAL)
598
0
  {
599
0
    nego_transport_disconnect(nego);
600
601
0
    if (nego->EnabledProtocols[PROTOCOL_HYBRID_EX])
602
0
      nego_set_state(nego, NEGO_STATE_EXT);
603
0
    else if (nego->EnabledProtocols[PROTOCOL_HYBRID])
604
0
      nego_set_state(nego, NEGO_STATE_NLA);
605
0
    else if (nego->EnabledProtocols[PROTOCOL_SSL])
606
0
      nego_set_state(nego, NEGO_STATE_TLS);
607
0
    else if (nego->EnabledProtocols[PROTOCOL_RDP])
608
0
      nego_set_state(nego, NEGO_STATE_RDP);
609
0
    else
610
0
      nego_set_state(nego, NEGO_STATE_FAIL);
611
0
  }
612
0
}
613
614
static void nego_attempt_rdsaad(rdpNego* nego)
615
0
{
616
0
  WINPR_ASSERT(nego);
617
0
  nego->RequestedProtocols = PROTOCOL_RDSAAD;
618
0
  WLog_Print(nego->log, WLOG_DEBUG, "Attempting RDS AAD Auth security");
619
620
0
  if (!nego_transport_connect(nego))
621
0
  {
622
0
    nego_set_state(nego, NEGO_STATE_FAIL);
623
0
    return;
624
0
  }
625
626
0
  if (!nego_send_negotiation_request(nego))
627
0
  {
628
0
    nego_set_state(nego, NEGO_STATE_FAIL);
629
0
    return;
630
0
  }
631
632
0
  if (!nego_recv_response(nego))
633
0
  {
634
0
    nego_set_state(nego, NEGO_STATE_FAIL);
635
0
    return;
636
0
  }
637
638
0
  WLog_Print(nego->log, WLOG_DEBUG, "state: %s", nego_state_string(nego_get_state(nego)));
639
640
0
  if (nego_get_state(nego) != NEGO_STATE_FINAL)
641
0
  {
642
0
    nego_transport_disconnect(nego);
643
644
0
    if (nego->EnabledProtocols[PROTOCOL_HYBRID_EX])
645
0
      nego_set_state(nego, NEGO_STATE_EXT);
646
0
    else if (nego->EnabledProtocols[PROTOCOL_HYBRID])
647
0
      nego_set_state(nego, NEGO_STATE_NLA);
648
0
    else if (nego->EnabledProtocols[PROTOCOL_SSL])
649
0
      nego_set_state(nego, NEGO_STATE_TLS);
650
0
    else if (nego->EnabledProtocols[PROTOCOL_RDP])
651
0
      nego_set_state(nego, NEGO_STATE_RDP);
652
0
    else
653
0
      nego_set_state(nego, NEGO_STATE_FAIL);
654
0
  }
655
0
}
656
657
static void nego_attempt_ext(rdpNego* nego)
658
0
{
659
0
  WINPR_ASSERT(nego);
660
0
  nego->RequestedProtocols = PROTOCOL_HYBRID | PROTOCOL_SSL | PROTOCOL_HYBRID_EX;
661
0
  WLog_Print(nego->log, WLOG_DEBUG, "Attempting NLA extended security");
662
663
0
  if (!nego_transport_connect(nego))
664
0
  {
665
0
    nego_set_state(nego, NEGO_STATE_FAIL);
666
0
    return;
667
0
  }
668
669
0
  if (!nego_send_negotiation_request(nego))
670
0
  {
671
0
    nego_set_state(nego, NEGO_STATE_FAIL);
672
0
    return;
673
0
  }
674
675
0
  if (!nego_recv_response(nego))
676
0
  {
677
0
    nego_set_state(nego, NEGO_STATE_FAIL);
678
0
    return;
679
0
  }
680
681
0
  WLog_Print(nego->log, WLOG_DEBUG, "state: %s", nego_state_string(nego_get_state(nego)));
682
683
0
  if (nego_get_state(nego) != NEGO_STATE_FINAL)
684
0
  {
685
0
    nego_transport_disconnect(nego);
686
687
0
    if (nego->EnabledProtocols[PROTOCOL_HYBRID])
688
0
      nego_set_state(nego, NEGO_STATE_NLA);
689
0
    else if (nego->EnabledProtocols[PROTOCOL_SSL])
690
0
      nego_set_state(nego, NEGO_STATE_TLS);
691
0
    else if (nego->EnabledProtocols[PROTOCOL_RDP])
692
0
      nego_set_state(nego, NEGO_STATE_RDP);
693
0
    else
694
0
      nego_set_state(nego, NEGO_STATE_FAIL);
695
0
  }
696
0
}
697
698
static void nego_attempt_nla(rdpNego* nego)
699
0
{
700
0
  WINPR_ASSERT(nego);
701
0
  nego->RequestedProtocols = PROTOCOL_HYBRID | PROTOCOL_SSL;
702
0
  WLog_Print(nego->log, WLOG_DEBUG, "Attempting NLA security");
703
704
0
  if (!nego_transport_connect(nego))
705
0
  {
706
0
    nego_set_state(nego, NEGO_STATE_FAIL);
707
0
    return;
708
0
  }
709
710
0
  if (!nego_send_negotiation_request(nego))
711
0
  {
712
0
    nego_set_state(nego, NEGO_STATE_FAIL);
713
0
    return;
714
0
  }
715
716
0
  if (!nego_recv_response(nego))
717
0
  {
718
0
    nego_set_state(nego, NEGO_STATE_FAIL);
719
0
    return;
720
0
  }
721
722
0
  WLog_Print(nego->log, WLOG_DEBUG, "state: %s", nego_state_string(nego_get_state(nego)));
723
724
0
  if (nego_get_state(nego) != NEGO_STATE_FINAL)
725
0
  {
726
0
    nego_transport_disconnect(nego);
727
728
0
    if (nego->EnabledProtocols[PROTOCOL_SSL])
729
0
      nego_set_state(nego, NEGO_STATE_TLS);
730
0
    else if (nego->EnabledProtocols[PROTOCOL_RDP])
731
0
      nego_set_state(nego, NEGO_STATE_RDP);
732
0
    else
733
0
      nego_set_state(nego, NEGO_STATE_FAIL);
734
0
  }
735
0
}
736
737
static void nego_attempt_tls(rdpNego* nego)
738
0
{
739
0
  WINPR_ASSERT(nego);
740
0
  nego->RequestedProtocols = PROTOCOL_SSL;
741
0
  WLog_Print(nego->log, WLOG_DEBUG, "Attempting TLS security");
742
743
0
  if (!nego_transport_connect(nego))
744
0
  {
745
0
    nego_set_state(nego, NEGO_STATE_FAIL);
746
0
    return;
747
0
  }
748
749
0
  if (!nego_send_negotiation_request(nego))
750
0
  {
751
0
    nego_set_state(nego, NEGO_STATE_FAIL);
752
0
    return;
753
0
  }
754
755
0
  if (!nego_recv_response(nego))
756
0
  {
757
0
    nego_set_state(nego, NEGO_STATE_FAIL);
758
0
    return;
759
0
  }
760
761
0
  if (nego_get_state(nego) != NEGO_STATE_FINAL)
762
0
  {
763
0
    nego_transport_disconnect(nego);
764
765
0
    if (nego->EnabledProtocols[PROTOCOL_RDP])
766
0
      nego_set_state(nego, NEGO_STATE_RDP);
767
0
    else
768
0
      nego_set_state(nego, NEGO_STATE_FAIL);
769
0
  }
770
0
}
771
772
static void nego_attempt_rdp(rdpNego* nego)
773
0
{
774
0
  WINPR_ASSERT(nego);
775
0
  nego->RequestedProtocols = PROTOCOL_RDP;
776
0
  WLog_Print(nego->log, WLOG_DEBUG, "Attempting RDP security");
777
778
0
  if (!nego_transport_connect(nego))
779
0
  {
780
0
    nego_set_state(nego, NEGO_STATE_FAIL);
781
0
    return;
782
0
  }
783
784
0
  if (!nego_send_negotiation_request(nego))
785
0
  {
786
0
    nego_set_state(nego, NEGO_STATE_FAIL);
787
0
    return;
788
0
  }
789
790
0
  if (!nego_recv_response(nego))
791
0
  {
792
0
    nego_set_state(nego, NEGO_STATE_FAIL);
793
0
    return;
794
0
  }
795
0
}
796
797
/**
798
 * Wait to receive a negotiation response
799
 *
800
 * @param nego A pointer to the NEGO struct
801
 *
802
 * @return \b TRUE for success, \b FALSE for failure
803
 */
804
805
BOOL nego_recv_response(rdpNego* nego)
806
0
{
807
0
  int status = 0;
808
0
  wStream* s = nullptr;
809
810
0
  WINPR_ASSERT(nego);
811
0
  s = Stream_New(nullptr, 1024);
812
813
0
  if (!s)
814
0
  {
815
0
    WLog_Print(nego->log, WLOG_ERROR, "Stream_New failed!");
816
0
    return FALSE;
817
0
  }
818
819
0
  status = transport_read_pdu(nego->transport, s);
820
821
0
  if (status < 0)
822
0
  {
823
0
    Stream_Free(s, TRUE);
824
0
    return FALSE;
825
0
  }
826
827
0
  status = nego_recv(nego->transport, s, nego);
828
0
  Stream_Free(s, TRUE);
829
830
0
  return (status >= 0);
831
0
}
832
833
/**
834
 * Receive protocol security negotiation message.
835
 * msdn{cc240501}
836
 *
837
 * @param transport The transport to read from
838
 * @param s A stream to read the received data from
839
 * @param extra nego pointer
840
 *
841
 * @return \b 0 for success, \b -1 for failure
842
 */
843
844
int nego_recv(WINPR_ATTR_UNUSED rdpTransport* transport, wStream* s, void* extra)
845
0
{
846
0
  BYTE li = 0;
847
0
  BYTE type = 0;
848
0
  UINT16 length = 0;
849
0
  rdpNego* nego = (rdpNego*)extra;
850
851
0
  WINPR_ASSERT(nego);
852
0
  if (!tpkt_read_header(s, &length))
853
0
    return -1;
854
855
0
  if (!tpdu_read_connection_confirm(s, &li, length))
856
0
    return -1;
857
858
0
  if (li > 6)
859
0
  {
860
    /* rdpNegData (optional) */
861
0
    Stream_Read_UINT8(s, type); /* Type */
862
863
0
    switch (type)
864
0
    {
865
0
      case TYPE_RDP_NEG_RSP:
866
0
        if (!nego_process_negotiation_response(nego, s))
867
0
          return -1;
868
0
        {
869
0
          char buffer[64] = WINPR_C_ARRAY_INIT;
870
0
          WLog_Print(
871
0
              nego->log, WLOG_DEBUG, "selected_protocol: %s",
872
0
              nego_protocol_to_str(nego->SelectedProtocol, buffer, sizeof(buffer)));
873
0
        }
874
875
        /* enhanced security selected ? */
876
877
0
        if (nego->SelectedProtocol)
878
0
        {
879
0
          const UINT32 flags[] = { PROTOCOL_RDP,    PROTOCOL_SSL,       PROTOCOL_HYBRID,
880
0
                                 PROTOCOL_RDSTLS, PROTOCOL_HYBRID_EX, PROTOCOL_RDSAAD };
881
882
0
          BOOL enabled = FALSE;
883
0
          for (size_t x = 0; x < ARRAYSIZE(flags); x++)
884
0
          {
885
0
            const UINT32 flag = flags[x];
886
0
            if ((nego->SelectedProtocol == flag) && (nego->EnabledProtocols[flag]))
887
0
              enabled = TRUE;
888
0
          }
889
0
          if (!enabled)
890
0
            nego_set_state(nego, NEGO_STATE_FAIL);
891
0
        }
892
0
        else if (!nego->EnabledProtocols[PROTOCOL_RDP])
893
0
        {
894
0
          nego_set_state(nego, NEGO_STATE_FAIL);
895
0
        }
896
897
0
        break;
898
899
0
      case TYPE_RDP_NEG_FAILURE:
900
0
        if (!nego_process_negotiation_failure(nego, s))
901
0
          return -1;
902
0
        break;
903
0
      default:
904
0
        return -1;
905
0
    }
906
0
  }
907
0
  else if (li == 6)
908
0
  {
909
0
    WLog_Print(nego->log, WLOG_DEBUG, "no rdpNegData");
910
911
0
    if (!nego->EnabledProtocols[PROTOCOL_RDP])
912
0
      nego_set_state(nego, NEGO_STATE_FAIL);
913
0
    else
914
0
      nego_set_state(nego, NEGO_STATE_FINAL);
915
0
  }
916
0
  else
917
0
  {
918
0
    WLog_Print(nego->log, WLOG_ERROR, "invalid negotiation response");
919
0
    nego_set_state(nego, NEGO_STATE_FAIL);
920
0
  }
921
922
0
  if (!tpkt_ensure_stream_consumed(nego->log, s, length))
923
0
    return -1;
924
0
  return 0;
925
0
}
926
927
/**
928
 * Read optional routing token or cookie of X.224 Connection Request PDU.
929
 * msdn{cc240470}
930
 */
931
WINPR_ATTR_NODISCARD
932
static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s)
933
0
{
934
  /* routingToken and cookie are optional and mutually exclusive!
935
   *
936
   * routingToken (variable): An optional and variable-length routing
937
   * token (used for load balancing) terminated by a 0x0D0A two-byte
938
   * sequence: (check [MSFT-SDLBTS] for details!)
939
   * Cookie:[space]msts=[ip address].[port].[reserved][\x0D\x0A]
940
   * tsv://MS Terminal Services Plugin.1.[\x0D\x0A]
941
   *
942
   * cookie (variable): An optional and variable-length ANSI character
943
   * string terminated by a 0x0D0A two-byte sequence:
944
   * Cookie:[space]mstshash=[ANSISTRING][\x0D\x0A]
945
   */
946
0
  UINT16 crlf = 0;
947
0
  BOOL result = FALSE;
948
0
  BOOL isToken = FALSE;
949
0
  size_t remain = Stream_GetRemainingLength(s);
950
951
0
  WINPR_ASSERT(nego);
952
953
0
  const char* str = Stream_ConstPointer(s);
954
0
  const size_t pos = Stream_GetPosition(s);
955
956
  /* minimum length for token is 15 */
957
0
  if (remain < 15)
958
0
    return TRUE;
959
960
0
  if ((remain < 17) || (memcmp(Stream_ConstPointer(s), "Cookie: mstshash=", 17) != 0))
961
0
  {
962
0
    if (memcmp(Stream_ConstPointer(s), "Cookie: msts=", 13) != 0)
963
0
    {
964
0
      if (memcmp(Stream_ConstPointer(s), "tsv:", 4) != 0)
965
0
      {
966
0
        if (memcmp(Stream_ConstPointer(s), "mth://", 6) != 0)
967
0
        {
968
          /* remaining bytes are neither a token nor a cookie */
969
0
          return TRUE;
970
0
        }
971
0
      }
972
0
    }
973
0
    isToken = TRUE;
974
0
  }
975
0
  else
976
0
  {
977
    /* not a token, minimum length for cookie is 19 */
978
0
    if (remain < 19)
979
0
      return TRUE;
980
981
0
    Stream_Seek(s, 17);
982
0
  }
983
984
0
  while (Stream_GetRemainingLength(s) >= 2)
985
0
  {
986
0
    Stream_Read_UINT16(s, crlf);
987
988
0
    if (crlf == 0x0A0D)
989
0
      break;
990
991
0
    Stream_Rewind(s, 1);
992
0
  }
993
994
0
  if (crlf == 0x0A0D)
995
0
  {
996
0
    Stream_Rewind(s, 2);
997
0
    const size_t len = Stream_GetPosition(s) - pos;
998
0
    Stream_Write_UINT16(s, 0);
999
1000
0
    if (len > UINT32_MAX)
1001
0
      return FALSE;
1002
1003
0
    if (strnlen(str, len) == len)
1004
0
    {
1005
      /* the token should not be multiline. */
1006
0
      if (winpr_strnstr(str, "\n", len) || winpr_strnstr(str, "\r", len))
1007
0
        return FALSE;
1008
1009
0
      if (isToken)
1010
0
        result = nego_set_routing_token(nego, str, (UINT32)len);
1011
0
      else
1012
0
        result = nego_set_cookie(nego, str);
1013
0
    }
1014
0
  }
1015
1016
0
  if (!result)
1017
0
  {
1018
0
    if (!Stream_SetPosition(s, pos))
1019
0
      return FALSE;
1020
0
    WLog_Print(nego->log, WLOG_ERROR, "invalid %s received",
1021
0
               isToken ? "routing token" : "cookie");
1022
0
  }
1023
0
  else
1024
0
  {
1025
0
    WLog_Print(nego->log, WLOG_DEBUG, "received %s [%s]", isToken ? "routing token" : "cookie",
1026
0
               str);
1027
0
  }
1028
1029
0
  return result;
1030
0
}
1031
1032
/**
1033
 * Read protocol security negotiation request message.
1034
 *
1035
 * @param nego A pointer to the NEGO struct
1036
 * @param s A stream to read from
1037
 *
1038
 * @return \b TRUE for success, \b FALSE for failure
1039
 */
1040
1041
BOOL nego_read_request(rdpNego* nego, wStream* s)
1042
0
{
1043
0
  BYTE li = 0;
1044
0
  BYTE type = 0;
1045
0
  UINT16 length = 0;
1046
1047
0
  WINPR_ASSERT(nego);
1048
0
  WINPR_ASSERT(s);
1049
1050
0
  if (!tpkt_read_header(s, &length))
1051
0
    return FALSE;
1052
1053
0
  if (!tpdu_read_connection_request(s, &li, length))
1054
0
    return FALSE;
1055
1056
0
  if (li != Stream_GetRemainingLength(s) + 6)
1057
0
  {
1058
0
    WLog_Print(nego->log, WLOG_ERROR, "Incorrect TPDU length indicator.");
1059
0
    return FALSE;
1060
0
  }
1061
1062
0
  if (!nego_read_request_token_or_cookie(nego, s))
1063
0
  {
1064
0
    WLog_Print(nego->log, WLOG_ERROR, "Failed to parse routing token or cookie.");
1065
0
    return FALSE;
1066
0
  }
1067
1068
0
  if (Stream_GetRemainingLength(s) >= 8)
1069
0
  {
1070
    /* rdpNegData (optional) */
1071
0
    Stream_Read_UINT8(s, type); /* Type */
1072
1073
0
    if (type != TYPE_RDP_NEG_REQ)
1074
0
    {
1075
0
      WLog_Print(nego->log, WLOG_ERROR, "Incorrect negotiation request type %" PRIu8 "",
1076
0
                 type);
1077
0
      return FALSE;
1078
0
    }
1079
1080
0
    if (!nego_process_negotiation_request(nego, s))
1081
0
      return FALSE;
1082
0
  }
1083
1084
0
  return tpkt_ensure_stream_consumed(nego->log, s, length);
1085
0
}
1086
1087
/**
1088
 * Send protocol security negotiation message.
1089
 *
1090
 * @param nego A pointer to the NEGO struct
1091
 */
1092
1093
void nego_send(rdpNego* nego)
1094
0
{
1095
0
  WINPR_ASSERT(nego);
1096
1097
0
  switch (nego_get_state(nego))
1098
0
  {
1099
0
    case NEGO_STATE_AAD:
1100
0
      nego_attempt_rdsaad(nego);
1101
0
      break;
1102
0
    case NEGO_STATE_RDSTLS:
1103
0
      nego_attempt_rdstls(nego);
1104
0
      break;
1105
0
    case NEGO_STATE_EXT:
1106
0
      nego_attempt_ext(nego);
1107
0
      break;
1108
0
    case NEGO_STATE_NLA:
1109
0
      nego_attempt_nla(nego);
1110
0
      break;
1111
0
    case NEGO_STATE_TLS:
1112
0
      nego_attempt_tls(nego);
1113
0
      break;
1114
0
    case NEGO_STATE_RDP:
1115
0
      nego_attempt_rdp(nego);
1116
0
      break;
1117
0
    default:
1118
0
      WLog_Print(nego->log, WLOG_ERROR, "invalid negotiation state for sending");
1119
0
      break;
1120
0
  }
1121
0
}
1122
1123
/**
1124
 * Send RDP Negotiation Request (RDP_NEG_REQ).
1125
 * msdn{cc240500}
1126
 * msdn{cc240470}
1127
 *
1128
 * @param nego A pointer to the NEGO struct
1129
 *
1130
 * @return \b TRUE for success, \b FALSE otherwise
1131
 */
1132
1133
BOOL nego_send_negotiation_request(rdpNego* nego)
1134
0
{
1135
0
  BOOL rc = FALSE;
1136
0
  wStream* s = Stream_New(nullptr, 512);
1137
1138
0
  WINPR_ASSERT(nego);
1139
0
  if (!s)
1140
0
  {
1141
0
    WLog_Print(nego->log, WLOG_ERROR, "Stream_New failed!");
1142
0
    return FALSE;
1143
0
  }
1144
1145
0
  const size_t bm = Stream_GetPosition(s);
1146
0
  if (!Stream_SafeZero(s, TPDU_CONNECTION_REQUEST_LENGTH))
1147
0
    goto fail;
1148
1149
0
  if (nego->RoutingToken)
1150
0
  {
1151
0
    if (!Stream_EnsureRemainingCapacity(s, nego->RoutingTokenLength))
1152
0
      goto fail;
1153
0
    Stream_Write(s, nego->RoutingToken, nego->RoutingTokenLength);
1154
1155
    /* Ensure Routing Token is correctly terminated - may already be present in string */
1156
1157
0
    if ((nego->RoutingTokenLength > 2) &&
1158
0
        (nego->RoutingToken[nego->RoutingTokenLength - 2] == 0x0D) &&
1159
0
        (nego->RoutingToken[nego->RoutingTokenLength - 1] == 0x0A))
1160
0
    {
1161
0
      WLog_Print(nego->log, WLOG_DEBUG,
1162
0
                 "Routing token looks correctly terminated - use verbatim");
1163
0
    }
1164
0
    else
1165
0
    {
1166
0
      WLog_Print(nego->log, WLOG_DEBUG, "Adding terminating CRLF to routing token");
1167
0
      if (!Stream_EnsureRemainingCapacity(s, 2))
1168
0
        goto fail;
1169
0
      Stream_Write_UINT8(s, 0x0D); /* CR */
1170
0
      Stream_Write_UINT8(s, 0x0A); /* LF */
1171
0
    }
1172
0
  }
1173
0
  else if (nego->cookie)
1174
0
  {
1175
0
    size_t cookie_length = strlen(nego->cookie);
1176
1177
0
    if (cookie_length > nego->CookieMaxLength)
1178
0
      cookie_length = nego->CookieMaxLength;
1179
1180
0
    if (!Stream_EnsureRemainingCapacity(s, 17))
1181
0
      goto fail;
1182
0
    Stream_Write(s, "Cookie: mstshash=", 17);
1183
0
    if (!Stream_EnsureRemainingCapacity(s, cookie_length))
1184
0
      goto fail;
1185
0
    Stream_Write(s, (BYTE*)nego->cookie, cookie_length);
1186
0
    if (!Stream_EnsureRemainingCapacity(s, 2))
1187
0
      goto fail;
1188
0
    Stream_Write_UINT8(s, 0x0D); /* CR */
1189
0
    Stream_Write_UINT8(s, 0x0A); /* LF */
1190
0
  }
1191
1192
0
  {
1193
0
    char buffer[64] = WINPR_C_ARRAY_INIT;
1194
0
    WLog_Print(nego->log, WLOG_DEBUG, "RequestedProtocols: %s",
1195
0
               nego_protocol_to_str(nego->RequestedProtocols, buffer, sizeof(buffer)));
1196
0
  }
1197
1198
0
  if ((nego->RequestedProtocols > PROTOCOL_RDP) || (nego->sendNegoData))
1199
0
  {
1200
0
    UINT8 flags = 0;
1201
1202
    /* RDP_NEG_DATA must be present for TLS and NLA */
1203
0
    if (nego->RestrictedAdminModeRequired)
1204
0
      flags |= RESTRICTED_ADMIN_MODE_REQUIRED;
1205
1206
0
    if (nego->RemoteCredsGuardRequired)
1207
0
      flags |= REDIRECTED_AUTHENTICATION_MODE_REQUIRED;
1208
1209
0
    if (!Stream_EnsureRemainingCapacity(s, 8))
1210
0
      goto fail;
1211
1212
0
    Stream_Write_UINT8(s, TYPE_RDP_NEG_REQ);
1213
0
    Stream_Write_UINT8(s, flags);
1214
0
    Stream_Write_UINT16(s, 8);                        /* RDP_NEG_DATA length (8) */
1215
0
    Stream_Write_UINT32(s, nego->RequestedProtocols); /* requestedProtocols */
1216
0
  }
1217
1218
0
  const size_t em = Stream_GetPosition(s);
1219
0
  if ((em < 5) || (em > UINT16_MAX))
1220
0
    goto fail;
1221
0
  if (!Stream_SetPosition(s, bm))
1222
0
    goto fail;
1223
0
  if (!tpkt_write_header(s, (UINT16)em))
1224
0
    goto fail;
1225
0
  if (!tpdu_write_connection_request(s, (UINT16)em - 5))
1226
0
    goto fail;
1227
0
  if (!Stream_SetPosition(s, em))
1228
0
    goto fail;
1229
0
  Stream_SealLength(s);
1230
0
  rc = (transport_write(nego->transport, s) >= 0);
1231
0
fail:
1232
0
  Stream_Free(s, TRUE);
1233
0
  return rc;
1234
0
}
1235
1236
WINPR_ATTR_NODISCARD
1237
static BOOL nego_process_correlation_info(WINPR_ATTR_UNUSED rdpNego* nego, wStream* s)
1238
0
{
1239
0
  UINT8 type = 0;
1240
0
  UINT8 flags = 0;
1241
0
  UINT16 length = 0;
1242
0
  BYTE correlationId[16] = WINPR_C_ARRAY_INIT;
1243
1244
0
  if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 36))
1245
0
  {
1246
0
    WLog_Print(nego->log, WLOG_ERROR,
1247
0
               "RDP_NEG_REQ::flags CORRELATION_INFO_PRESENT but data is missing");
1248
0
    return FALSE;
1249
0
  }
1250
1251
0
  Stream_Read_UINT8(s, type);
1252
0
  if (type != TYPE_RDP_CORRELATION_INFO)
1253
0
  {
1254
0
    WLog_Print(nego->log, WLOG_ERROR,
1255
0
               "(RDP_NEG_CORRELATION_INFO::type != TYPE_RDP_CORRELATION_INFO");
1256
0
    return FALSE;
1257
0
  }
1258
0
  Stream_Read_UINT8(s, flags);
1259
0
  if (flags != 0)
1260
0
  {
1261
0
    WLog_Print(nego->log, WLOG_ERROR, "(RDP_NEG_CORRELATION_INFO::flags != 0");
1262
0
    return FALSE;
1263
0
  }
1264
0
  Stream_Read_UINT16(s, length);
1265
0
  if (length != 36)
1266
0
  {
1267
0
    WLog_Print(nego->log, WLOG_ERROR, "(RDP_NEG_CORRELATION_INFO::length != 36");
1268
0
    return FALSE;
1269
0
  }
1270
1271
0
  Stream_Read(s, correlationId, sizeof(correlationId));
1272
0
  if ((correlationId[0] == 0x00) || (correlationId[0] == 0xF4))
1273
0
  {
1274
0
    WLog_Print(nego->log, WLOG_ERROR,
1275
0
               "(RDP_NEG_CORRELATION_INFO::correlationId[0] has invalid value 0x%02" PRIx8,
1276
0
               correlationId[0]);
1277
0
    return FALSE;
1278
0
  }
1279
0
  for (size_t x = 0; x < ARRAYSIZE(correlationId); x++)
1280
0
  {
1281
0
    if (correlationId[x] == 0x0D)
1282
0
    {
1283
0
      WLog_Print(nego->log, WLOG_ERROR,
1284
0
                 "(RDP_NEG_CORRELATION_INFO::correlationId[%" PRIuz
1285
0
                 "] has invalid value 0x%02" PRIx8,
1286
0
                 x, correlationId[x]);
1287
0
      return FALSE;
1288
0
    }
1289
0
  }
1290
0
  Stream_Seek(s, 16); /* skip reserved bytes */
1291
1292
0
  WLog_Print(nego->log, WLOG_INFO,
1293
0
             "RDP_NEG_CORRELATION_INFO::correlationId = { %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8
1294
0
             ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8
1295
0
             ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8
1296
0
             ", %02" PRIx8 " }",
1297
0
             correlationId[0], correlationId[1], correlationId[2], correlationId[3],
1298
0
             correlationId[4], correlationId[5], correlationId[6], correlationId[7],
1299
0
             correlationId[8], correlationId[9], correlationId[10], correlationId[11],
1300
0
             correlationId[12], correlationId[13], correlationId[14], correlationId[15]);
1301
0
  return TRUE;
1302
0
}
1303
1304
BOOL nego_process_negotiation_request(rdpNego* nego, wStream* s)
1305
0
{
1306
0
  BYTE flags = 0;
1307
0
  UINT16 length = 0;
1308
1309
0
  WINPR_ASSERT(nego);
1310
0
  WINPR_ASSERT(s);
1311
1312
0
  if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 7))
1313
0
    return FALSE;
1314
0
  Stream_Read_UINT8(s, flags);
1315
0
  if ((flags & ~(RESTRICTED_ADMIN_MODE_REQUIRED | REDIRECTED_AUTHENTICATION_MODE_REQUIRED |
1316
0
                 CORRELATION_INFO_PRESENT)) != 0)
1317
0
  {
1318
0
    WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_REQ::flags invalid value 0x%02" PRIx8, flags);
1319
0
    return FALSE;
1320
0
  }
1321
0
  if (flags & RESTRICTED_ADMIN_MODE_REQUIRED)
1322
0
  {
1323
0
    if (nego->RestrictedAdminModeSupported)
1324
0
    {
1325
0
      WLog_Print(nego->log, WLOG_INFO, "RDP_NEG_REQ::flags RESTRICTED_ADMIN_MODE_REQUIRED");
1326
0
    }
1327
0
    else
1328
0
    {
1329
0
      WLog_Print(nego->log, WLOG_ERROR,
1330
0
                 "RDP_NEG_REQ::flags RESTRICTED_ADMIN_MODE_REQUIRED but disabled");
1331
0
      return FALSE;
1332
0
    }
1333
0
  }
1334
1335
0
  if (flags & REDIRECTED_AUTHENTICATION_MODE_REQUIRED)
1336
0
  {
1337
0
    if (nego->RemoteCredsGuardSupported)
1338
0
    {
1339
0
      WLog_Print(nego->log, WLOG_INFO,
1340
0
                 "RDP_NEG_REQ::flags REDIRECTED_AUTHENTICATION_MODE_REQUIRED");
1341
0
      nego->RemoteCredsGuardActive = TRUE;
1342
0
    }
1343
0
    else
1344
0
    {
1345
      /* If both RESTRICTED_ADMIN_MODE_REQUIRED and REDIRECTED_AUTHENTICATION_MODE_REQUIRED
1346
       * are set, it means one or the other. In this case, don't fail if Remote Guard isn't
1347
       * available. */
1348
0
      if (flags & RESTRICTED_ADMIN_MODE_REQUIRED)
1349
0
      {
1350
0
        WLog_Print(nego->log, WLOG_INFO,
1351
0
                   "RDP_NEG_REQ::flags REDIRECTED_AUTHENTICATION_MODE_REQUIRED ignored.");
1352
0
      }
1353
0
      else
1354
0
      {
1355
0
        WLog_Print(
1356
0
            nego->log, WLOG_ERROR,
1357
0
            "RDP_NEG_REQ::flags REDIRECTED_AUTHENTICATION_MODE_REQUIRED but disabled");
1358
0
        return FALSE;
1359
0
      }
1360
0
    }
1361
0
  }
1362
1363
0
  Stream_Read_UINT16(s, length);
1364
0
  if (length != 8)
1365
0
  {
1366
0
    WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_REQ::length != 8");
1367
0
    return FALSE;
1368
0
  }
1369
0
  Stream_Read_UINT32(s, nego->RequestedProtocols);
1370
1371
0
  if (flags & CORRELATION_INFO_PRESENT)
1372
0
  {
1373
0
    if (!nego_process_correlation_info(nego, s))
1374
0
      return FALSE;
1375
0
  }
1376
1377
0
  {
1378
0
    char buffer[64] = WINPR_C_ARRAY_INIT;
1379
0
    WLog_Print(nego->log, WLOG_DEBUG, "RDP_NEG_REQ: RequestedProtocol: %s",
1380
0
               nego_protocol_to_str(nego->RequestedProtocols, buffer, sizeof(buffer)));
1381
0
  }
1382
0
  nego_set_state(nego, NEGO_STATE_FINAL);
1383
0
  return TRUE;
1384
0
}
1385
1386
WINPR_ATTR_NODISCARD
1387
static const char* nego_rdp_neg_rsp_flags_str(UINT32 flags)
1388
0
{
1389
0
  const uint32_t mask =
1390
0
      (EXTENDED_CLIENT_DATA_SUPPORTED | DYNVC_GFX_PROTOCOL_SUPPORTED | RDP_NEGRSP_RESERVED |
1391
0
       RESTRICTED_ADMIN_MODE_SUPPORTED | REDIRECTED_AUTHENTICATION_MODE_SUPPORTED);
1392
0
  static char buffer[1024] = WINPR_C_ARRAY_INIT;
1393
1394
0
  (void)_snprintf(buffer, ARRAYSIZE(buffer), "[0x%02" PRIx32 "] ", flags);
1395
0
  if (flags & EXTENDED_CLIENT_DATA_SUPPORTED)
1396
0
    winpr_str_append("EXTENDED_CLIENT_DATA_SUPPORTED", buffer, sizeof(buffer), "|");
1397
0
  if (flags & DYNVC_GFX_PROTOCOL_SUPPORTED)
1398
0
    winpr_str_append("DYNVC_GFX_PROTOCOL_SUPPORTED", buffer, sizeof(buffer), "|");
1399
0
  if (flags & RDP_NEGRSP_RESERVED)
1400
0
    winpr_str_append("RDP_NEGRSP_RESERVED", buffer, sizeof(buffer), "|");
1401
0
  if (flags & RESTRICTED_ADMIN_MODE_SUPPORTED)
1402
0
    winpr_str_append("RESTRICTED_ADMIN_MODE_SUPPORTED", buffer, sizeof(buffer), "|");
1403
0
  if (flags & REDIRECTED_AUTHENTICATION_MODE_SUPPORTED)
1404
0
    winpr_str_append("REDIRECTED_AUTHENTICATION_MODE_SUPPORTED", buffer, sizeof(buffer), "|");
1405
0
  if (flags & ~mask)
1406
0
  {
1407
0
    char buffer2[32] = WINPR_C_ARRAY_INIT;
1408
0
    (void)_snprintf(buffer2, sizeof(buffer2), "UNKNOWN[0x%04" PRIx32 "]", flags & ~mask);
1409
0
    winpr_str_append(buffer2, buffer, sizeof(buffer), "|");
1410
0
  }
1411
1412
0
  return buffer;
1413
0
}
1414
1415
BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s)
1416
0
{
1417
0
  UINT16 length = 0;
1418
1419
0
  WINPR_ASSERT(nego);
1420
0
  WINPR_ASSERT(s);
1421
1422
0
  if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 7))
1423
0
  {
1424
0
    nego_set_state(nego, NEGO_STATE_FAIL);
1425
0
    return FALSE;
1426
0
  }
1427
1428
0
  Stream_Read_UINT8(s, nego->flags);
1429
0
  WLog_Print(nego->log, WLOG_DEBUG, "RDP_NEG_RSP::flags = { %s }",
1430
0
             nego_rdp_neg_rsp_flags_str(nego->flags));
1431
1432
0
  if ((nego->flags & RESTRICTED_ADMIN_MODE_SUPPORTED) == 0)
1433
0
  {
1434
0
    if (nego->RestrictedAdminModeRequired)
1435
0
    {
1436
0
      WLog_Print(nego->log, WLOG_ERROR,
1437
0
                 "restricted-admin mode requested but not supported, terminating");
1438
0
      return -1;
1439
0
    }
1440
0
  }
1441
1442
0
  if ((nego->flags & REDIRECTED_AUTHENTICATION_MODE_SUPPORTED) == 0)
1443
0
  {
1444
0
    if (nego->RemoteCredsGuardRequired)
1445
0
    {
1446
0
      WLog_Print(nego->log, WLOG_ERROR,
1447
0
                 "remote credential guard requested but not supported, terminating");
1448
0
      return -1;
1449
0
    }
1450
0
  }
1451
1452
0
  Stream_Read_UINT16(s, length);
1453
0
  if (length != 8)
1454
0
  {
1455
0
    WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_RSP::length != 8");
1456
0
    nego_set_state(nego, NEGO_STATE_FAIL);
1457
0
    return FALSE;
1458
0
  }
1459
0
  UINT32 SelectedProtocol = 0;
1460
0
  Stream_Read_UINT32(s, SelectedProtocol);
1461
1462
0
  if (!nego_set_selected_protocol(nego, SelectedProtocol))
1463
0
    return FALSE;
1464
0
  return nego_set_state(nego, NEGO_STATE_FINAL);
1465
0
}
1466
1467
WINPR_ATTR_NODISCARD
1468
static const char* nego_rdp_neg_fail_str(uint32_t what)
1469
0
{
1470
0
  switch (what)
1471
0
  {
1472
0
    case SSL_REQUIRED_BY_SERVER:
1473
0
      return "SSL_REQUIRED_BY_SERVER";
1474
0
    case SSL_NOT_ALLOWED_BY_SERVER:
1475
0
      return "SSL_NOT_ALLOWED_BY_SERVER";
1476
0
    case SSL_CERT_NOT_ON_SERVER:
1477
0
      return "SSL_CERT_NOT_ON_SERVER";
1478
0
    case INCONSISTENT_FLAGS:
1479
0
      return "INCONSISTENT_FLAGS";
1480
0
    case HYBRID_REQUIRED_BY_SERVER:
1481
0
      return "HYBRID_REQUIRED_BY_SERVER";
1482
0
    case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER:
1483
0
      return "SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER";
1484
0
    default:
1485
0
      return "UNKNOWN";
1486
0
  }
1487
0
}
1488
1489
static void nego_disable_all_except(rdpNego* nego, uint32_t what)
1490
0
{
1491
0
  WINPR_ASSERT(nego);
1492
1493
0
  char buffer[32] = WINPR_C_ARRAY_INIT;
1494
0
  WLog_Print(nego->log, WLOG_DEBUG, "Disabling all modes except %s",
1495
0
             nego_protocol_to_str(what, buffer, sizeof(buffer)));
1496
1497
0
  for (size_t x = 0; x < ARRAYSIZE(nego->EnabledProtocols); x++)
1498
0
  {
1499
0
    if (x == what)
1500
0
      continue;
1501
0
    nego->EnabledProtocols[x] = FALSE;
1502
0
  }
1503
0
}
1504
1505
/**
1506
 * Process Negotiation Failure from Connection Confirm message.
1507
 * @param nego A pointer to the NEGO struct
1508
 * @param s The stream to read from
1509
 *
1510
 * @return \b TRUE for success, \b FALSE otherwise
1511
 */
1512
1513
BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s)
1514
0
{
1515
0
  BYTE flags = 0;
1516
0
  UINT16 length = 0;
1517
1518
0
  WINPR_ASSERT(nego);
1519
0
  WINPR_ASSERT(s);
1520
1521
0
  WLog_Print(nego->log, WLOG_DEBUG, "RDP_NEG_FAILURE");
1522
0
  if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 7))
1523
0
    return FALSE;
1524
1525
0
  Stream_Read_UINT8(s, flags);
1526
0
  if (flags != 0)
1527
0
  {
1528
0
    WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_FAILURE::flags = 0x%02" PRIx8, flags);
1529
0
    return FALSE;
1530
0
  }
1531
0
  Stream_Read_UINT16(s, length);
1532
0
  if (length != 8)
1533
0
  {
1534
0
    WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_FAILURE::length != 8");
1535
0
    return FALSE;
1536
0
  }
1537
0
  const uint32_t failureCode = Stream_Get_UINT32(s);
1538
0
  const char* failureStr = nego_rdp_neg_fail_str(failureCode);
1539
0
  DWORD level = WLOG_WARN;
1540
1541
  /* Remember why the server refused. The cases below fall back to another protocol, so
1542
   * this is only turned into an error once the negotiation has terminally failed. */
1543
0
  nego->failureCode = failureCode;
1544
1545
0
  switch (failureCode)
1546
0
  {
1547
0
    case SSL_REQUIRED_BY_SERVER:
1548
0
      nego_disable_all_except(nego, PROTOCOL_SSL);
1549
0
      break;
1550
1551
0
    case SSL_NOT_ALLOWED_BY_SERVER:
1552
0
      nego_disable_all_except(nego, PROTOCOL_RDP);
1553
0
      nego->sendNegoData = TRUE;
1554
0
      break;
1555
1556
0
    case SSL_CERT_NOT_ON_SERVER:
1557
0
      level = WLOG_ERROR;
1558
0
      nego->sendNegoData = TRUE;
1559
0
      break;
1560
1561
0
    case INCONSISTENT_FLAGS:
1562
0
      level = WLOG_ERROR;
1563
0
      break;
1564
1565
0
    case HYBRID_REQUIRED_BY_SERVER:
1566
0
      nego_disable_all_except(nego, PROTOCOL_HYBRID);
1567
0
      break;
1568
1569
0
    default:
1570
0
      level = WLOG_ERROR;
1571
0
      break;
1572
0
  }
1573
1574
0
  WLog_Print(nego->log, level, "Error: %s [0x%08" PRIx32 "]", failureStr, failureCode);
1575
0
  nego_set_state(nego, NEGO_STATE_FAIL);
1576
0
  return TRUE;
1577
0
}
1578
1579
/**
1580
 * Send RDP Negotiation Response (RDP_NEG_RSP).
1581
 * @param nego A pointer to the NEGO struct
1582
 */
1583
1584
BOOL nego_send_negotiation_response(rdpNego* nego)
1585
0
{
1586
0
  BOOL status = FALSE;
1587
0
  BYTE flags = 0;
1588
0
  rdpContext* context = nullptr;
1589
0
  rdpSettings* settings = nullptr;
1590
1591
0
  WINPR_ASSERT(nego);
1592
0
  context = transport_get_context(nego->transport);
1593
0
  WINPR_ASSERT(context);
1594
1595
0
  settings = context->settings;
1596
0
  WINPR_ASSERT(settings);
1597
1598
0
  wStream* s = Stream_New(nullptr, 512);
1599
1600
0
  if (!s)
1601
0
  {
1602
0
    WLog_Print(nego->log, WLOG_ERROR, "Stream_New failed!");
1603
0
    return FALSE;
1604
0
  }
1605
1606
0
  UINT16 length = TPDU_CONNECTION_CONFIRM_LENGTH;
1607
0
  const size_t bm = Stream_GetPosition(s);
1608
0
  if (!Stream_SafeZero(s, length))
1609
0
    goto fail;
1610
1611
0
  if (nego->SelectedProtocol & PROTOCOL_FAILED_NEGO)
1612
0
  {
1613
0
    UINT32 errorCode = (nego->SelectedProtocol & ~PROTOCOL_FAILED_NEGO);
1614
0
    flags = 0;
1615
0
    Stream_Write_UINT8(s, TYPE_RDP_NEG_FAILURE);
1616
0
    Stream_Write_UINT8(s, flags); /* flags */
1617
0
    Stream_Write_UINT16(s, 8);    /* RDP_NEG_DATA length (8) */
1618
0
    Stream_Write_UINT32(s, errorCode);
1619
0
    length += 8;
1620
0
  }
1621
0
  else
1622
0
  {
1623
0
    flags = EXTENDED_CLIENT_DATA_SUPPORTED;
1624
1625
0
    if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline))
1626
0
      flags |= DYNVC_GFX_PROTOCOL_SUPPORTED;
1627
1628
0
    if (nego->RestrictedAdminModeSupported)
1629
0
      flags |= RESTRICTED_ADMIN_MODE_SUPPORTED;
1630
1631
0
    if (nego->RemoteCredsGuardSupported)
1632
0
      flags |= REDIRECTED_AUTHENTICATION_MODE_SUPPORTED;
1633
1634
    /* RDP_NEG_DATA must be present for TLS, NLA, RDP and RDSTLS */
1635
0
    Stream_Write_UINT8(s, TYPE_RDP_NEG_RSP);
1636
0
    Stream_Write_UINT8(s, flags);                   /* flags */
1637
0
    Stream_Write_UINT16(s, 8);                      /* RDP_NEG_DATA length (8) */
1638
0
    Stream_Write_UINT32(s, nego->SelectedProtocol); /* selectedProtocol */
1639
0
    length += 8;
1640
0
  }
1641
1642
0
  const size_t em = Stream_GetPosition(s);
1643
0
  if (!Stream_SetPosition(s, bm))
1644
0
    goto fail;
1645
0
  if (!tpkt_write_header(s, length))
1646
0
    goto fail;
1647
1648
0
  if (!tpdu_write_connection_confirm(s, length - 5))
1649
0
    goto fail;
1650
1651
0
  if (!Stream_SetPosition(s, em))
1652
0
    goto fail;
1653
0
  Stream_SealLength(s);
1654
1655
0
  status = (transport_write(nego->transport, s) >= 0);
1656
1657
0
fail:
1658
0
  Stream_Free(s, TRUE);
1659
1660
0
  if (status)
1661
0
  {
1662
    /* update settings with negotiated protocol security */
1663
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_RequestedProtocols,
1664
0
                                     nego->RequestedProtocols))
1665
0
      return FALSE;
1666
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_SelectedProtocol,
1667
0
                                     nego->SelectedProtocol))
1668
0
      return FALSE;
1669
1670
0
    switch (nego->SelectedProtocol)
1671
0
    {
1672
0
      case PROTOCOL_RDP:
1673
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, FALSE))
1674
0
          return FALSE;
1675
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1676
0
          return FALSE;
1677
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
1678
0
          return FALSE;
1679
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
1680
0
          return FALSE;
1681
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, TRUE))
1682
0
          return FALSE;
1683
1684
0
        if (freerdp_settings_get_uint32(settings, FreeRDP_EncryptionLevel) ==
1685
0
            ENCRYPTION_LEVEL_NONE)
1686
0
        {
1687
          /**
1688
           * If the server implementation did not explicitly set a
1689
           * encryption level we default to client compatible
1690
           */
1691
0
          if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1692
0
                                           ENCRYPTION_LEVEL_CLIENT_COMPATIBLE))
1693
0
            return FALSE;
1694
0
        }
1695
1696
0
        if (freerdp_settings_get_bool(settings, FreeRDP_LocalConnection))
1697
0
        {
1698
          /**
1699
           * Note: This hack was firstly introduced in commit 95f5e115 to
1700
           * disable the unnecessary encryption with peers connecting to
1701
           * 127.0.0.1 or local unix sockets.
1702
           * This also affects connections via port tunnels! (e.g. ssh -L)
1703
           */
1704
0
          WLog_Print(nego->log, WLOG_INFO,
1705
0
                     "Turning off encryption for local peer with standard rdp security");
1706
0
          if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1707
0
            return FALSE;
1708
0
          if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1709
0
                                           ENCRYPTION_LEVEL_NONE))
1710
0
            return FALSE;
1711
0
        }
1712
0
        else if (!freerdp_settings_get_pointer(settings, FreeRDP_RdpServerRsaKey))
1713
0
        {
1714
0
          WLog_Print(nego->log, WLOG_ERROR, "Missing server certificate");
1715
0
          return FALSE;
1716
0
        }
1717
0
        break;
1718
0
      case PROTOCOL_SSL:
1719
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1720
0
          return FALSE;
1721
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1722
0
          return FALSE;
1723
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
1724
0
          return FALSE;
1725
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, FALSE))
1726
0
          return FALSE;
1727
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1728
0
          return FALSE;
1729
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1730
0
          return FALSE;
1731
1732
0
        if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1733
0
                                         ENCRYPTION_LEVEL_NONE))
1734
0
          return FALSE;
1735
0
        break;
1736
0
      case PROTOCOL_HYBRID:
1737
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1738
0
          return FALSE;
1739
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE))
1740
0
          return FALSE;
1741
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, TRUE))
1742
0
          return FALSE;
1743
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, FALSE))
1744
0
          return FALSE;
1745
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1746
0
          return FALSE;
1747
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1748
0
          return FALSE;
1749
1750
0
        if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1751
0
                                         ENCRYPTION_LEVEL_NONE))
1752
0
          return FALSE;
1753
0
        break;
1754
0
      case PROTOCOL_RDSTLS:
1755
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1756
0
          return FALSE;
1757
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1758
0
          return FALSE;
1759
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
1760
0
          return FALSE;
1761
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, TRUE))
1762
0
          return FALSE;
1763
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1764
0
          return FALSE;
1765
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1766
0
          return FALSE;
1767
1768
0
        if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1769
0
                                         ENCRYPTION_LEVEL_NONE))
1770
0
          return FALSE;
1771
0
        break;
1772
0
      default:
1773
0
        break;
1774
0
    }
1775
0
  }
1776
1777
0
  return status;
1778
0
}
1779
1780
/**
1781
 * Initialize NEGO state machine.
1782
 * @param nego A pointer to the NEGO struct
1783
 */
1784
1785
void nego_init(rdpNego* nego)
1786
21.4k
{
1787
21.4k
  WINPR_ASSERT(nego);
1788
21.4k
  nego_set_state(nego, NEGO_STATE_INITIAL);
1789
21.4k
  nego->RequestedProtocols = PROTOCOL_RDP;
1790
21.4k
  nego->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH;
1791
21.4k
  nego->sendNegoData = FALSE;
1792
21.4k
  nego->flags = 0;
1793
21.4k
  nego->failureCode = 0;
1794
21.4k
}
1795
1796
/**
1797
 * Create a new NEGO state machine instance.
1798
 *
1799
 * @param transport The transport to use
1800
 *
1801
 * @return A pointer to the allocated NEGO instance or nullptr
1802
 */
1803
1804
rdpNego* nego_new(rdpTransport* transport)
1805
21.4k
{
1806
21.4k
  rdpNego* nego = (rdpNego*)calloc(1, sizeof(rdpNego));
1807
1808
21.4k
  if (!nego)
1809
0
    return nullptr;
1810
1811
21.4k
  nego->log = WLog_Get(NEGO_TAG);
1812
21.4k
  WINPR_ASSERT(nego->log);
1813
21.4k
  nego->transport = transport;
1814
21.4k
  nego_init(nego);
1815
21.4k
  return nego;
1816
21.4k
}
1817
1818
/**
1819
 * Free NEGO state machine.
1820
 * @param nego A pointer to the NEGO struct
1821
 */
1822
1823
void nego_free(rdpNego* nego)
1824
21.4k
{
1825
21.4k
  if (nego)
1826
21.4k
  {
1827
21.4k
    free(nego->RoutingToken);
1828
21.4k
    free(nego->cookie);
1829
21.4k
    free(nego);
1830
21.4k
  }
1831
21.4k
}
1832
1833
/**
1834
 * Set target hostname and port.
1835
 * @param nego A pointer to the NEGO struct
1836
 * @param hostname The hostname to set
1837
 * @param port The port to set
1838
 *
1839
 * @return \b TRUE for success, \b FALSE otherwise
1840
 */
1841
1842
BOOL nego_set_target(rdpNego* nego, const char* hostname, UINT16 port)
1843
0
{
1844
0
  WINPR_ASSERT(nego);
1845
0
  WINPR_ASSERT(hostname);
1846
1847
0
  nego->hostname = hostname;
1848
0
  nego->port = port;
1849
0
  return TRUE;
1850
0
}
1851
1852
/**
1853
 * Enable security layer negotiation.
1854
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1855
 * @param NegotiateSecurityLayer whether to enable security layer negotiation (TRUE for enabled,
1856
 * FALSE for disabled)
1857
 */
1858
1859
void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer)
1860
0
{
1861
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling security layer negotiation: %s",
1862
0
             NegotiateSecurityLayer ? "TRUE" : "FALSE");
1863
0
  nego->NegotiateSecurityLayer = NegotiateSecurityLayer;
1864
0
}
1865
1866
/**
1867
 * Enable restricted admin mode.
1868
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1869
 * @param RestrictedAdminModeRequired whether to enable security layer negotiation (TRUE for
1870
 * enabled, FALSE for disabled)
1871
 */
1872
1873
void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired)
1874
0
{
1875
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling restricted admin mode: %s",
1876
0
             RestrictedAdminModeRequired ? "TRUE" : "FALSE");
1877
0
  nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired;
1878
0
}
1879
1880
void nego_set_restricted_admin_mode_supported(rdpNego* nego, BOOL enabled)
1881
0
{
1882
0
  WINPR_ASSERT(nego);
1883
1884
0
  nego->RestrictedAdminModeSupported = enabled;
1885
0
}
1886
1887
void nego_set_RCG_required(rdpNego* nego, BOOL enabled)
1888
0
{
1889
0
  WINPR_ASSERT(nego);
1890
1891
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling remoteCredentialGuards: %s",
1892
0
             enabled ? "TRUE" : "FALSE");
1893
0
  nego->RemoteCredsGuardRequired = enabled;
1894
0
}
1895
1896
void nego_set_RCG_supported(rdpNego* nego, BOOL enabled)
1897
0
{
1898
0
  WINPR_ASSERT(nego);
1899
1900
0
  nego->RemoteCredsGuardSupported = enabled;
1901
0
}
1902
1903
BOOL nego_get_remoteCredentialGuard(const rdpNego* nego)
1904
0
{
1905
0
  WINPR_ASSERT(nego);
1906
1907
0
  return nego->RemoteCredsGuardActive;
1908
0
}
1909
1910
void nego_set_childsession_enabled(rdpNego* nego, BOOL ChildSessionEnabled)
1911
0
{
1912
0
  WINPR_ASSERT(nego);
1913
0
  nego->ConnectChildSession = ChildSessionEnabled;
1914
0
}
1915
1916
void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled)
1917
0
{
1918
0
  nego->GatewayEnabled = GatewayEnabled;
1919
0
}
1920
1921
void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal)
1922
0
{
1923
0
  nego->GatewayBypassLocal = GatewayBypassLocal;
1924
0
}
1925
1926
/**
1927
 * Enable RDP security protocol.
1928
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1929
 * @param enable_rdp whether to enable normal RDP protocol (TRUE for enabled, FALSE for disabled)
1930
 */
1931
1932
void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp)
1933
0
{
1934
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDP security: %s", enable_rdp ? "TRUE" : "FALSE");
1935
0
  nego->EnabledProtocols[PROTOCOL_RDP] = enable_rdp;
1936
0
}
1937
1938
/**
1939
 * Enable TLS security protocol.
1940
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1941
 * @param enable_tls whether to enable TLS + RDP protocol (TRUE for enabled, FALSE for disabled)
1942
 */
1943
1944
void nego_enable_tls(rdpNego* nego, BOOL enable_tls)
1945
0
{
1946
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling TLS security: %s", enable_tls ? "TRUE" : "FALSE");
1947
0
  nego->EnabledProtocols[PROTOCOL_SSL] = enable_tls;
1948
0
}
1949
1950
/**
1951
 * Enable NLA security protocol.
1952
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1953
 * @param enable_nla whether to enable network level authentication protocol (TRUE for enabled,
1954
 * FALSE for disabled)
1955
 */
1956
1957
void nego_enable_nla(rdpNego* nego, BOOL enable_nla)
1958
0
{
1959
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling NLA security: %s", enable_nla ? "TRUE" : "FALSE");
1960
0
  nego->EnabledProtocols[PROTOCOL_HYBRID] = enable_nla;
1961
0
}
1962
1963
/**
1964
 * Enable RDSTLS security protocol.
1965
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1966
 * @param enable_rdstls whether to enable RDSTLS protocol (TRUE for enabled,
1967
 * FALSE for disabled)
1968
 */
1969
1970
void nego_enable_rdstls(rdpNego* nego, BOOL enable_rdstls)
1971
0
{
1972
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDSTLS security: %s",
1973
0
             enable_rdstls ? "TRUE" : "FALSE");
1974
0
  nego->EnabledProtocols[PROTOCOL_RDSTLS] = enable_rdstls;
1975
0
}
1976
1977
/**
1978
 * Enable NLA extended security protocol.
1979
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1980
 * @param enable_ext whether to enable network level authentication extended protocol (TRUE for
1981
 * enabled, FALSE for disabled)
1982
 */
1983
1984
void nego_enable_ext(rdpNego* nego, BOOL enable_ext)
1985
0
{
1986
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling NLA extended security: %s",
1987
0
             enable_ext ? "TRUE" : "FALSE");
1988
0
  nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = enable_ext;
1989
0
}
1990
1991
/**
1992
 * Enable RDS AAD security protocol.
1993
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1994
 * @param enable_aad whether to enable RDS AAD Auth protocol (TRUE for
1995
 * enabled, FALSE for disabled)
1996
 */
1997
1998
void nego_enable_aad(rdpNego* nego, BOOL enable_aad)
1999
0
{
2000
0
  WINPR_ASSERT(nego);
2001
0
  if (aad_is_supported())
2002
0
  {
2003
0
    WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDS AAD security: %s",
2004
0
               enable_aad ? "TRUE" : "FALSE");
2005
0
    nego->EnabledProtocols[PROTOCOL_RDSAAD] = enable_aad;
2006
0
  }
2007
0
  else
2008
0
  {
2009
0
    WLog_Print(nego->log, WLOG_WARN, "This build does not support AAD security, disabling.");
2010
0
  }
2011
0
}
2012
2013
/**
2014
 * Set routing token.
2015
 * @param nego A pointer to the NEGO struct
2016
 * @param RoutingToken A pointer to the routing token
2017
 * @param RoutingTokenLength The length of the routing token
2018
 *
2019
 * @return \b TRUE for success, \b FALSE otherwise
2020
 */
2021
2022
BOOL nego_set_routing_token(rdpNego* nego, const void* RoutingToken, DWORD RoutingTokenLength)
2023
0
{
2024
0
  if (RoutingTokenLength == 0)
2025
0
    return FALSE;
2026
2027
0
  free(nego->RoutingToken);
2028
0
  nego->RoutingTokenLength = RoutingTokenLength;
2029
0
  nego->RoutingToken = (BYTE*)malloc(nego->RoutingTokenLength);
2030
2031
0
  if (!nego->RoutingToken)
2032
0
    return FALSE;
2033
2034
0
  CopyMemory(nego->RoutingToken, RoutingToken, nego->RoutingTokenLength);
2035
0
  return TRUE;
2036
0
}
2037
2038
/**
2039
 * Set cookie.
2040
 * @param nego A pointer to the NEGO struct
2041
 * @param cookie A pointer to the cookie string
2042
 *
2043
 * @return \b TRUE for success, \b FALSE otherwise
2044
 */
2045
2046
BOOL nego_set_cookie(rdpNego* nego, const char* cookie)
2047
0
{
2048
0
  if (nego->cookie)
2049
0
  {
2050
0
    free(nego->cookie);
2051
0
    nego->cookie = nullptr;
2052
0
  }
2053
2054
0
  if (!cookie)
2055
0
    return TRUE;
2056
2057
0
  nego->cookie = _strdup(cookie);
2058
2059
0
  return (nego->cookie != nullptr);
2060
0
}
2061
2062
/**
2063
 * Set cookie maximum length
2064
 * @param nego A pointer to the NEGO struct
2065
 * @param CookieMaxLength the length to set
2066
 */
2067
2068
void nego_set_cookie_max_length(rdpNego* nego, UINT32 CookieMaxLength)
2069
0
{
2070
0
  nego->CookieMaxLength = CookieMaxLength;
2071
0
}
2072
2073
/**
2074
 * Enable / disable preconnection PDU.
2075
 * @param nego A pointer to the NEGO struct
2076
 * @param SendPreconnectionPdu The value to set
2077
 */
2078
2079
void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL SendPreconnectionPdu)
2080
0
{
2081
0
  nego->SendPreconnectionPdu = SendPreconnectionPdu;
2082
0
}
2083
2084
/**
2085
 * Set preconnection id.
2086
 * @param nego A pointer to the NEGO struct
2087
 * @param PreconnectionId the ID to set
2088
 */
2089
2090
void nego_set_preconnection_id(rdpNego* nego, UINT32 PreconnectionId)
2091
0
{
2092
0
  nego->PreconnectionId = PreconnectionId;
2093
0
}
2094
2095
/**
2096
 * Set preconnection blob.
2097
 * @param nego A pointer to the NEGO struct
2098
 * @param PreconnectionBlob A pointer to the blob to use
2099
 */
2100
2101
void nego_set_preconnection_blob(rdpNego* nego, const char* PreconnectionBlob)
2102
0
{
2103
0
  nego->PreconnectionBlob = PreconnectionBlob;
2104
0
}
2105
2106
UINT32 nego_get_selected_protocol(const rdpNego* nego)
2107
0
{
2108
0
  if (!nego)
2109
0
    return 0;
2110
2111
0
  return nego->SelectedProtocol;
2112
0
}
2113
2114
BOOL nego_set_selected_protocol(rdpNego* nego, UINT32 SelectedProtocol)
2115
0
{
2116
0
  WINPR_ASSERT(nego);
2117
0
  nego->SelectedProtocol = SelectedProtocol;
2118
0
  return TRUE;
2119
0
}
2120
2121
UINT32 nego_get_requested_protocols(const rdpNego* nego)
2122
0
{
2123
0
  if (!nego)
2124
0
    return 0;
2125
2126
0
  return nego->RequestedProtocols;
2127
0
}
2128
2129
BOOL nego_set_requested_protocols(rdpNego* nego, UINT32 RequestedProtocols)
2130
0
{
2131
0
  if (!nego)
2132
0
    return FALSE;
2133
2134
0
  nego->RequestedProtocols = RequestedProtocols;
2135
0
  return TRUE;
2136
0
}
2137
2138
NEGO_STATE nego_get_state(const rdpNego* nego)
2139
0
{
2140
0
  if (!nego)
2141
0
    return NEGO_STATE_FAIL;
2142
2143
0
  return nego->state;
2144
0
}
2145
2146
BOOL nego_set_state(rdpNego* nego, NEGO_STATE state)
2147
21.4k
{
2148
21.4k
  WINPR_ASSERT(nego);
2149
21.4k
  nego->state = state;
2150
21.4k
  return TRUE;
2151
21.4k
}
2152
2153
SEC_WINNT_AUTH_IDENTITY* nego_get_identity(rdpNego* nego)
2154
0
{
2155
0
  rdpNla* nla = nullptr;
2156
0
  if (!nego)
2157
0
    return nullptr;
2158
2159
0
  nla = transport_get_nla(nego->transport);
2160
0
  return nla_get_identity(nla);
2161
0
}
2162
2163
void nego_free_nla(rdpNego* nego)
2164
0
{
2165
0
  if (!nego || !nego->transport)
2166
0
    return;
2167
2168
0
  transport_set_nla(nego->transport, nullptr);
2169
0
}
2170
2171
const BYTE* nego_get_routing_token(const rdpNego* nego, DWORD* RoutingTokenLength)
2172
0
{
2173
0
  if (!nego)
2174
0
    return nullptr;
2175
0
  if (RoutingTokenLength)
2176
0
    *RoutingTokenLength = nego->RoutingTokenLength;
2177
0
  return nego->RoutingToken;
2178
0
}
2179
2180
const char* nego_protocol_to_str(UINT32 protocol, char* buffer, size_t size)
2181
0
{
2182
0
  const UINT32 mask = ~(PROTOCOL_SSL | PROTOCOL_HYBRID | PROTOCOL_RDSTLS | PROTOCOL_HYBRID_EX |
2183
0
                        PROTOCOL_RDSAAD | PROTOCOL_FAILED_NEGO);
2184
0
  char str[48] = WINPR_C_ARRAY_INIT;
2185
2186
0
  if (protocol & PROTOCOL_SSL)
2187
0
    (void)winpr_str_append("SSL", str, sizeof(str), "|");
2188
0
  if (protocol & PROTOCOL_HYBRID)
2189
0
    (void)winpr_str_append("HYBRID", str, sizeof(str), "|");
2190
0
  if (protocol & PROTOCOL_RDSTLS)
2191
0
    (void)winpr_str_append("RDSTLS", str, sizeof(str), "|");
2192
0
  if (protocol & PROTOCOL_HYBRID_EX)
2193
0
    (void)winpr_str_append("HYBRID_EX", str, sizeof(str), "|");
2194
0
  if (protocol & PROTOCOL_RDSAAD)
2195
0
    (void)winpr_str_append("RDSAAD", str, sizeof(str), "|");
2196
0
  if (protocol & PROTOCOL_FAILED_NEGO)
2197
0
    (void)winpr_str_append("NEGO FAILED", str, sizeof(str), "|");
2198
2199
0
  if (protocol == PROTOCOL_RDP)
2200
0
    (void)winpr_str_append("RDP", str, sizeof(str), "");
2201
0
  else if ((protocol & mask) != 0)
2202
0
    (void)winpr_str_append("UNKNOWN", str, sizeof(str), "|");
2203
2204
0
  (void)_snprintf(buffer, size, "[%s][0x%08" PRIx32 "]", str, protocol);
2205
0
  return buffer;
2206
0
}