Coverage Report

Created: 2025-07-11 06:46

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