Coverage Report

Created: 2025-10-10 06:50

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
17.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
  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
  const uint32_t mask =
1325
0
      (EXTENDED_CLIENT_DATA_SUPPORTED | DYNVC_GFX_PROTOCOL_SUPPORTED | RDP_NEGRSP_RESERVED |
1326
0
       RESTRICTED_ADMIN_MODE_SUPPORTED | REDIRECTED_AUTHENTICATION_MODE_SUPPORTED);
1327
0
  static char buffer[1024] = { 0 };
1328
1329
0
  (void)_snprintf(buffer, ARRAYSIZE(buffer), "[0x%02" PRIx32 "] ", flags);
1330
0
  if (flags & EXTENDED_CLIENT_DATA_SUPPORTED)
1331
0
    winpr_str_append("EXTENDED_CLIENT_DATA_SUPPORTED", buffer, sizeof(buffer), "|");
1332
0
  if (flags & DYNVC_GFX_PROTOCOL_SUPPORTED)
1333
0
    winpr_str_append("DYNVC_GFX_PROTOCOL_SUPPORTED", buffer, sizeof(buffer), "|");
1334
0
  if (flags & RDP_NEGRSP_RESERVED)
1335
0
    winpr_str_append("RDP_NEGRSP_RESERVED", buffer, sizeof(buffer), "|");
1336
0
  if (flags & RESTRICTED_ADMIN_MODE_SUPPORTED)
1337
0
    winpr_str_append("RESTRICTED_ADMIN_MODE_SUPPORTED", buffer, sizeof(buffer), "|");
1338
0
  if (flags & REDIRECTED_AUTHENTICATION_MODE_SUPPORTED)
1339
0
    winpr_str_append("REDIRECTED_AUTHENTICATION_MODE_SUPPORTED", buffer, sizeof(buffer), "|");
1340
0
  if (flags & ~mask)
1341
0
  {
1342
0
    char buffer2[32] = { 0 };
1343
0
    (void)_snprintf(buffer2, sizeof(buffer2), "UNKNOWN[0x%04" PRIx32 "]", flags & ~mask);
1344
0
    winpr_str_append(buffer2, buffer, sizeof(buffer), "|");
1345
0
  }
1346
1347
0
  return buffer;
1348
0
}
1349
1350
BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s)
1351
0
{
1352
0
  UINT16 length = 0;
1353
1354
0
  WINPR_ASSERT(nego);
1355
0
  WINPR_ASSERT(s);
1356
1357
0
  if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 7))
1358
0
  {
1359
0
    nego_set_state(nego, NEGO_STATE_FAIL);
1360
0
    return FALSE;
1361
0
  }
1362
1363
0
  Stream_Read_UINT8(s, nego->flags);
1364
0
  WLog_Print(nego->log, WLOG_DEBUG, "RDP_NEG_RSP::flags = { %s }",
1365
0
             nego_rdp_neg_rsp_flags_str(nego->flags));
1366
1367
0
  Stream_Read_UINT16(s, length);
1368
0
  if (length != 8)
1369
0
  {
1370
0
    WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_RSP::length != 8");
1371
0
    nego_set_state(nego, NEGO_STATE_FAIL);
1372
0
    return FALSE;
1373
0
  }
1374
0
  UINT32 SelectedProtocol = 0;
1375
0
  Stream_Read_UINT32(s, SelectedProtocol);
1376
1377
0
  if (!nego_set_selected_protocol(nego, SelectedProtocol))
1378
0
    return FALSE;
1379
0
  return nego_set_state(nego, NEGO_STATE_FINAL);
1380
0
}
1381
1382
static const char* nego_rdp_neg_fail_str(uint32_t what)
1383
0
{
1384
0
  switch (what)
1385
0
  {
1386
0
    case SSL_REQUIRED_BY_SERVER:
1387
0
      return "SSL_REQUIRED_BY_SERVER";
1388
0
    case SSL_NOT_ALLOWED_BY_SERVER:
1389
0
      return "SSL_NOT_ALLOWED_BY_SERVER";
1390
0
    case SSL_CERT_NOT_ON_SERVER:
1391
0
      return "SSL_CERT_NOT_ON_SERVER";
1392
0
    case INCONSISTENT_FLAGS:
1393
0
      return "INCONSISTENT_FLAGS";
1394
0
    case HYBRID_REQUIRED_BY_SERVER:
1395
0
      return "HYBRID_REQUIRED_BY_SERVER";
1396
0
    case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER:
1397
0
      return "SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER";
1398
0
    default:
1399
0
      return "UNKNOWN";
1400
0
  }
1401
0
}
1402
1403
/**
1404
 * Process Negotiation Failure from Connection Confirm message.
1405
 * @param nego A pointer to the NEGO struct
1406
 * @param s The stream to read from
1407
 *
1408
 * @return \b TRUE for success, \b FALSE otherwise
1409
 */
1410
1411
BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s)
1412
0
{
1413
0
  BYTE flags = 0;
1414
0
  UINT16 length = 0;
1415
1416
0
  WINPR_ASSERT(nego);
1417
0
  WINPR_ASSERT(s);
1418
1419
0
  WLog_Print(nego->log, WLOG_DEBUG, "RDP_NEG_FAILURE");
1420
0
  if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 7))
1421
0
    return FALSE;
1422
1423
0
  Stream_Read_UINT8(s, flags);
1424
0
  if (flags != 0)
1425
0
  {
1426
0
    WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_FAILURE::flags = 0x%02" PRIx8, flags);
1427
0
    return FALSE;
1428
0
  }
1429
0
  Stream_Read_UINT16(s, length);
1430
0
  if (length != 8)
1431
0
  {
1432
0
    WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_FAILURE::length != 8");
1433
0
    return FALSE;
1434
0
  }
1435
0
  const uint32_t failureCode = Stream_Get_UINT32(s);
1436
0
  const char* failureStr = nego_rdp_neg_fail_str(failureCode);
1437
0
  DWORD level = WLOG_WARN;
1438
0
  switch (failureCode)
1439
0
  {
1440
0
    case SSL_REQUIRED_BY_SERVER:
1441
0
      break;
1442
1443
0
    case SSL_NOT_ALLOWED_BY_SERVER:
1444
0
      nego->sendNegoData = TRUE;
1445
0
      break;
1446
1447
0
    case SSL_CERT_NOT_ON_SERVER:
1448
0
      level = WLOG_ERROR;
1449
0
      nego->sendNegoData = TRUE;
1450
0
      break;
1451
1452
0
    case INCONSISTENT_FLAGS:
1453
0
      level = WLOG_ERROR;
1454
0
      break;
1455
1456
0
    case HYBRID_REQUIRED_BY_SERVER:
1457
0
      break;
1458
1459
0
    default:
1460
0
      level = WLOG_ERROR;
1461
0
      break;
1462
0
  }
1463
1464
0
  WLog_Print(nego->log, level, "Error: %s [0x%08" PRIx32 "]", failureStr, failureCode);
1465
0
  nego_set_state(nego, NEGO_STATE_FAIL);
1466
0
  return TRUE;
1467
0
}
1468
1469
/**
1470
 * Send RDP Negotiation Response (RDP_NEG_RSP).
1471
 * @param nego A pointer to the NEGO struct
1472
 */
1473
1474
BOOL nego_send_negotiation_response(rdpNego* nego)
1475
0
{
1476
0
  UINT16 length = 0;
1477
0
  size_t bm = 0;
1478
0
  size_t em = 0;
1479
0
  BOOL status = 0;
1480
0
  wStream* s = NULL;
1481
0
  BYTE flags = 0;
1482
0
  rdpContext* context = NULL;
1483
0
  rdpSettings* settings = NULL;
1484
1485
0
  WINPR_ASSERT(nego);
1486
0
  context = transport_get_context(nego->transport);
1487
0
  WINPR_ASSERT(context);
1488
1489
0
  settings = context->settings;
1490
0
  WINPR_ASSERT(settings);
1491
1492
0
  s = Stream_New(NULL, 512);
1493
1494
0
  if (!s)
1495
0
  {
1496
0
    WLog_Print(nego->log, WLOG_ERROR, "Stream_New failed!");
1497
0
    return FALSE;
1498
0
  }
1499
1500
0
  length = TPDU_CONNECTION_CONFIRM_LENGTH;
1501
0
  bm = Stream_GetPosition(s);
1502
0
  Stream_Seek(s, length);
1503
1504
0
  if (nego->SelectedProtocol & PROTOCOL_FAILED_NEGO)
1505
0
  {
1506
0
    UINT32 errorCode = (nego->SelectedProtocol & ~PROTOCOL_FAILED_NEGO);
1507
0
    flags = 0;
1508
0
    Stream_Write_UINT8(s, TYPE_RDP_NEG_FAILURE);
1509
0
    Stream_Write_UINT8(s, flags); /* flags */
1510
0
    Stream_Write_UINT16(s, 8);    /* RDP_NEG_DATA length (8) */
1511
0
    Stream_Write_UINT32(s, errorCode);
1512
0
    length += 8;
1513
0
  }
1514
0
  else
1515
0
  {
1516
0
    flags = EXTENDED_CLIENT_DATA_SUPPORTED;
1517
1518
0
    if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline))
1519
0
      flags |= DYNVC_GFX_PROTOCOL_SUPPORTED;
1520
1521
0
    if (nego->RestrictedAdminModeSupported)
1522
0
      flags |= RESTRICTED_ADMIN_MODE_SUPPORTED;
1523
1524
0
    if (nego->RemoteCredsGuardSupported)
1525
0
      flags |= REDIRECTED_AUTHENTICATION_MODE_SUPPORTED;
1526
1527
    /* RDP_NEG_DATA must be present for TLS, NLA, RDP and RDSTLS */
1528
0
    Stream_Write_UINT8(s, TYPE_RDP_NEG_RSP);
1529
0
    Stream_Write_UINT8(s, flags);                   /* flags */
1530
0
    Stream_Write_UINT16(s, 8);                      /* RDP_NEG_DATA length (8) */
1531
0
    Stream_Write_UINT32(s, nego->SelectedProtocol); /* selectedProtocol */
1532
0
    length += 8;
1533
0
  }
1534
1535
0
  em = Stream_GetPosition(s);
1536
0
  Stream_SetPosition(s, bm);
1537
0
  status = tpkt_write_header(s, length);
1538
0
  if (status)
1539
0
  {
1540
0
    tpdu_write_connection_confirm(s, length - 5);
1541
0
    Stream_SetPosition(s, em);
1542
0
    Stream_SealLength(s);
1543
1544
0
    status = (transport_write(nego->transport, s) >= 0);
1545
0
  }
1546
0
  Stream_Free(s, TRUE);
1547
1548
0
  if (status)
1549
0
  {
1550
    /* update settings with negotiated protocol security */
1551
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_RequestedProtocols,
1552
0
                                     nego->RequestedProtocols))
1553
0
      return FALSE;
1554
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_SelectedProtocol,
1555
0
                                     nego->SelectedProtocol))
1556
0
      return FALSE;
1557
1558
0
    switch (nego->SelectedProtocol)
1559
0
    {
1560
0
      case PROTOCOL_RDP:
1561
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, FALSE))
1562
0
          return FALSE;
1563
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1564
0
          return FALSE;
1565
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
1566
0
          return FALSE;
1567
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, TRUE))
1568
0
          return FALSE;
1569
1570
0
        if (freerdp_settings_get_uint32(settings, FreeRDP_EncryptionLevel) ==
1571
0
            ENCRYPTION_LEVEL_NONE)
1572
0
        {
1573
          /**
1574
           * If the server implementation did not explicitly set a
1575
           * encryption level we default to client compatible
1576
           */
1577
0
          if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1578
0
                                           ENCRYPTION_LEVEL_CLIENT_COMPATIBLE))
1579
0
            return FALSE;
1580
0
        }
1581
1582
0
        if (freerdp_settings_get_bool(settings, FreeRDP_LocalConnection))
1583
0
        {
1584
          /**
1585
           * Note: This hack was firstly introduced in commit 95f5e115 to
1586
           * disable the unnecessary encryption with peers connecting to
1587
           * 127.0.0.1 or local unix sockets.
1588
           * This also affects connections via port tunnels! (e.g. ssh -L)
1589
           */
1590
0
          WLog_Print(nego->log, WLOG_INFO,
1591
0
                     "Turning off encryption for local peer with standard rdp security");
1592
0
          if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1593
0
            return FALSE;
1594
0
          if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1595
0
                                           ENCRYPTION_LEVEL_NONE))
1596
0
            return FALSE;
1597
0
        }
1598
0
        else if (!freerdp_settings_get_pointer(settings, FreeRDP_RdpServerRsaKey))
1599
0
        {
1600
0
          WLog_Print(nego->log, WLOG_ERROR, "Missing server certificate");
1601
0
          return FALSE;
1602
0
        }
1603
0
        break;
1604
0
      case PROTOCOL_SSL:
1605
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1606
0
          return FALSE;
1607
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1608
0
          return FALSE;
1609
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, FALSE))
1610
0
          return FALSE;
1611
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1612
0
          return FALSE;
1613
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1614
0
          return FALSE;
1615
1616
0
        if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1617
0
                                         ENCRYPTION_LEVEL_NONE))
1618
0
          return FALSE;
1619
0
        break;
1620
0
      case PROTOCOL_HYBRID:
1621
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1622
0
          return FALSE;
1623
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE))
1624
0
          return FALSE;
1625
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, FALSE))
1626
0
          return FALSE;
1627
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1628
0
          return FALSE;
1629
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1630
0
          return FALSE;
1631
1632
0
        if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1633
0
                                         ENCRYPTION_LEVEL_NONE))
1634
0
          return FALSE;
1635
0
        break;
1636
0
      case PROTOCOL_RDSTLS:
1637
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1638
0
          return FALSE;
1639
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1640
0
          return FALSE;
1641
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, TRUE))
1642
0
          return FALSE;
1643
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1644
0
          return FALSE;
1645
0
        if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1646
0
          return FALSE;
1647
1648
0
        if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1649
0
                                         ENCRYPTION_LEVEL_NONE))
1650
0
          return FALSE;
1651
0
        break;
1652
0
      default:
1653
0
        break;
1654
0
    }
1655
0
  }
1656
1657
0
  return status;
1658
0
}
1659
1660
/**
1661
 * Initialize NEGO state machine.
1662
 * @param nego A pointer to the NEGO struct
1663
 */
1664
1665
void nego_init(rdpNego* nego)
1666
17.4k
{
1667
17.4k
  WINPR_ASSERT(nego);
1668
17.4k
  nego_set_state(nego, NEGO_STATE_INITIAL);
1669
17.4k
  nego->RequestedProtocols = PROTOCOL_RDP;
1670
17.4k
  nego->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH;
1671
17.4k
  nego->sendNegoData = FALSE;
1672
17.4k
  nego->flags = 0;
1673
17.4k
}
1674
1675
/**
1676
 * Create a new NEGO state machine instance.
1677
 *
1678
 * @param transport The transport to use
1679
 *
1680
 * @return A pointer to the allocated NEGO instance or NULL
1681
 */
1682
1683
rdpNego* nego_new(rdpTransport* transport)
1684
17.4k
{
1685
17.4k
  rdpNego* nego = (rdpNego*)calloc(1, sizeof(rdpNego));
1686
1687
17.4k
  if (!nego)
1688
0
    return NULL;
1689
1690
17.4k
  nego->log = WLog_Get(NEGO_TAG);
1691
17.4k
  WINPR_ASSERT(nego->log);
1692
17.4k
  nego->transport = transport;
1693
17.4k
  nego_init(nego);
1694
17.4k
  return nego;
1695
17.4k
}
1696
1697
/**
1698
 * Free NEGO state machine.
1699
 * @param nego A pointer to the NEGO struct
1700
 */
1701
1702
void nego_free(rdpNego* nego)
1703
17.4k
{
1704
17.4k
  if (nego)
1705
17.4k
  {
1706
17.4k
    free(nego->RoutingToken);
1707
17.4k
    free(nego->cookie);
1708
17.4k
    free(nego);
1709
17.4k
  }
1710
17.4k
}
1711
1712
/**
1713
 * Set target hostname and port.
1714
 * @param nego A pointer to the NEGO struct
1715
 * @param hostname The hostname to set
1716
 * @param port The port to set
1717
 *
1718
 * @return \b TRUE for success, \b FALSE otherwise
1719
 */
1720
1721
BOOL nego_set_target(rdpNego* nego, const char* hostname, UINT16 port)
1722
0
{
1723
0
  if (!nego || !hostname)
1724
0
    return FALSE;
1725
1726
0
  nego->hostname = hostname;
1727
0
  nego->port = port;
1728
0
  return TRUE;
1729
0
}
1730
1731
/**
1732
 * Enable security layer negotiation.
1733
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1734
 * @param NegotiateSecurityLayer whether to enable security layer negotiation (TRUE for enabled,
1735
 * FALSE for disabled)
1736
 */
1737
1738
void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer)
1739
0
{
1740
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling security layer negotiation: %s",
1741
0
             NegotiateSecurityLayer ? "TRUE" : "FALSE");
1742
0
  nego->NegotiateSecurityLayer = NegotiateSecurityLayer;
1743
0
}
1744
1745
/**
1746
 * Enable restricted admin mode.
1747
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1748
 * @param RestrictedAdminModeRequired whether to enable security layer negotiation (TRUE for
1749
 * enabled, FALSE for disabled)
1750
 */
1751
1752
void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired)
1753
0
{
1754
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling restricted admin mode: %s",
1755
0
             RestrictedAdminModeRequired ? "TRUE" : "FALSE");
1756
0
  nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired;
1757
0
}
1758
1759
void nego_set_restricted_admin_mode_supported(rdpNego* nego, BOOL enabled)
1760
0
{
1761
0
  WINPR_ASSERT(nego);
1762
1763
0
  nego->RestrictedAdminModeSupported = enabled;
1764
0
}
1765
1766
void nego_set_RCG_required(rdpNego* nego, BOOL enabled)
1767
0
{
1768
0
  WINPR_ASSERT(nego);
1769
1770
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling remoteCredentialGuards: %s",
1771
0
             enabled ? "TRUE" : "FALSE");
1772
0
  nego->RemoteCredsGuardRequired = enabled;
1773
0
}
1774
1775
void nego_set_RCG_supported(rdpNego* nego, BOOL enabled)
1776
0
{
1777
0
  WINPR_ASSERT(nego);
1778
1779
0
  nego->RemoteCredsGuardSupported = enabled;
1780
0
}
1781
1782
BOOL nego_get_remoteCredentialGuard(const rdpNego* nego)
1783
0
{
1784
0
  WINPR_ASSERT(nego);
1785
1786
0
  return nego->RemoteCredsGuardActive;
1787
0
}
1788
1789
void nego_set_childsession_enabled(rdpNego* nego, BOOL ChildSessionEnabled)
1790
0
{
1791
0
  WINPR_ASSERT(nego);
1792
0
  nego->ConnectChildSession = ChildSessionEnabled;
1793
0
}
1794
1795
void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled)
1796
0
{
1797
0
  nego->GatewayEnabled = GatewayEnabled;
1798
0
}
1799
1800
void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal)
1801
0
{
1802
0
  nego->GatewayBypassLocal = GatewayBypassLocal;
1803
0
}
1804
1805
/**
1806
 * Enable RDP security protocol.
1807
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1808
 * @param enable_rdp whether to enable normal RDP protocol (TRUE for enabled, FALSE for disabled)
1809
 */
1810
1811
void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp)
1812
0
{
1813
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDP security: %s", enable_rdp ? "TRUE" : "FALSE");
1814
0
  nego->EnabledProtocols[PROTOCOL_RDP] = enable_rdp;
1815
0
}
1816
1817
/**
1818
 * Enable TLS security protocol.
1819
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1820
 * @param enable_tls whether to enable TLS + RDP protocol (TRUE for enabled, FALSE for disabled)
1821
 */
1822
1823
void nego_enable_tls(rdpNego* nego, BOOL enable_tls)
1824
0
{
1825
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling TLS security: %s", enable_tls ? "TRUE" : "FALSE");
1826
0
  nego->EnabledProtocols[PROTOCOL_SSL] = enable_tls;
1827
0
}
1828
1829
/**
1830
 * Enable NLA security protocol.
1831
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1832
 * @param enable_nla whether to enable network level authentication protocol (TRUE for enabled,
1833
 * FALSE for disabled)
1834
 */
1835
1836
void nego_enable_nla(rdpNego* nego, BOOL enable_nla)
1837
0
{
1838
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling NLA security: %s", enable_nla ? "TRUE" : "FALSE");
1839
0
  nego->EnabledProtocols[PROTOCOL_HYBRID] = enable_nla;
1840
0
}
1841
1842
/**
1843
 * Enable RDSTLS security protocol.
1844
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1845
 * @param enable_rdstls whether to enable RDSTLS protocol (TRUE for enabled,
1846
 * FALSE for disabled)
1847
 */
1848
1849
void nego_enable_rdstls(rdpNego* nego, BOOL enable_rdstls)
1850
0
{
1851
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDSTLS security: %s",
1852
0
             enable_rdstls ? "TRUE" : "FALSE");
1853
0
  nego->EnabledProtocols[PROTOCOL_RDSTLS] = enable_rdstls;
1854
0
}
1855
1856
/**
1857
 * Enable NLA extended security protocol.
1858
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1859
 * @param enable_ext whether to enable network level authentication extended protocol (TRUE for
1860
 * enabled, FALSE for disabled)
1861
 */
1862
1863
void nego_enable_ext(rdpNego* nego, BOOL enable_ext)
1864
0
{
1865
0
  WLog_Print(nego->log, WLOG_DEBUG, "Enabling NLA extended security: %s",
1866
0
             enable_ext ? "TRUE" : "FALSE");
1867
0
  nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = enable_ext;
1868
0
}
1869
1870
/**
1871
 * Enable RDS AAD security protocol.
1872
 * @param nego A pointer to the NEGO struct pointer to the negotiation structure
1873
 * @param enable_aad whether to enable RDS AAD Auth protocol (TRUE for
1874
 * enabled, FALSE for disabled)
1875
 */
1876
1877
void nego_enable_aad(rdpNego* nego, BOOL enable_aad)
1878
0
{
1879
0
  WINPR_ASSERT(nego);
1880
0
  if (aad_is_supported())
1881
0
  {
1882
0
    WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDS AAD security: %s",
1883
0
               enable_aad ? "TRUE" : "FALSE");
1884
0
    nego->EnabledProtocols[PROTOCOL_RDSAAD] = enable_aad;
1885
0
  }
1886
0
  else
1887
0
  {
1888
0
    WLog_Print(nego->log, WLOG_WARN, "This build does not support AAD security, disabling.");
1889
0
  }
1890
0
}
1891
1892
/**
1893
 * Set routing token.
1894
 * @param nego A pointer to the NEGO struct
1895
 * @param RoutingToken A pointer to the routing token
1896
 * @param RoutingTokenLength The length of the routing token
1897
 *
1898
 * @return \b TRUE for success, \b FALSE otherwise
1899
 */
1900
1901
BOOL nego_set_routing_token(rdpNego* nego, const void* RoutingToken, DWORD RoutingTokenLength)
1902
0
{
1903
0
  if (RoutingTokenLength == 0)
1904
0
    return FALSE;
1905
1906
0
  free(nego->RoutingToken);
1907
0
  nego->RoutingTokenLength = RoutingTokenLength;
1908
0
  nego->RoutingToken = (BYTE*)malloc(nego->RoutingTokenLength);
1909
1910
0
  if (!nego->RoutingToken)
1911
0
    return FALSE;
1912
1913
0
  CopyMemory(nego->RoutingToken, RoutingToken, nego->RoutingTokenLength);
1914
0
  return TRUE;
1915
0
}
1916
1917
/**
1918
 * Set cookie.
1919
 * @param nego A pointer to the NEGO struct
1920
 * @param cookie A pointer to the cookie string
1921
 *
1922
 * @return \b TRUE for success, \b FALSE otherwise
1923
 */
1924
1925
BOOL nego_set_cookie(rdpNego* nego, const char* cookie)
1926
0
{
1927
0
  if (nego->cookie)
1928
0
  {
1929
0
    free(nego->cookie);
1930
0
    nego->cookie = NULL;
1931
0
  }
1932
1933
0
  if (!cookie)
1934
0
    return TRUE;
1935
1936
0
  nego->cookie = _strdup(cookie);
1937
1938
0
  if (!nego->cookie)
1939
0
    return FALSE;
1940
1941
0
  return TRUE;
1942
0
}
1943
1944
/**
1945
 * Set cookie maximum length
1946
 * @param nego A pointer to the NEGO struct
1947
 * @param CookieMaxLength the length to set
1948
 */
1949
1950
void nego_set_cookie_max_length(rdpNego* nego, UINT32 CookieMaxLength)
1951
0
{
1952
0
  nego->CookieMaxLength = CookieMaxLength;
1953
0
}
1954
1955
/**
1956
 * Enable / disable preconnection PDU.
1957
 * @param nego A pointer to the NEGO struct
1958
 * @param SendPreconnectionPdu The value to set
1959
 */
1960
1961
void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL SendPreconnectionPdu)
1962
0
{
1963
0
  nego->SendPreconnectionPdu = SendPreconnectionPdu;
1964
0
}
1965
1966
/**
1967
 * Set preconnection id.
1968
 * @param nego A pointer to the NEGO struct
1969
 * @param PreconnectionId the ID to set
1970
 */
1971
1972
void nego_set_preconnection_id(rdpNego* nego, UINT32 PreconnectionId)
1973
0
{
1974
0
  nego->PreconnectionId = PreconnectionId;
1975
0
}
1976
1977
/**
1978
 * Set preconnection blob.
1979
 * @param nego A pointer to the NEGO struct
1980
 * @param PreconnectionBlob A pointer to the blob to use
1981
 */
1982
1983
void nego_set_preconnection_blob(rdpNego* nego, const char* PreconnectionBlob)
1984
0
{
1985
0
  nego->PreconnectionBlob = PreconnectionBlob;
1986
0
}
1987
1988
UINT32 nego_get_selected_protocol(const rdpNego* nego)
1989
0
{
1990
0
  if (!nego)
1991
0
    return 0;
1992
1993
0
  return nego->SelectedProtocol;
1994
0
}
1995
1996
BOOL nego_set_selected_protocol(rdpNego* nego, UINT32 SelectedProtocol)
1997
0
{
1998
0
  WINPR_ASSERT(nego);
1999
0
  nego->SelectedProtocol = SelectedProtocol;
2000
0
  return TRUE;
2001
0
}
2002
2003
UINT32 nego_get_requested_protocols(const rdpNego* nego)
2004
0
{
2005
0
  if (!nego)
2006
0
    return 0;
2007
2008
0
  return nego->RequestedProtocols;
2009
0
}
2010
2011
BOOL nego_set_requested_protocols(rdpNego* nego, UINT32 RequestedProtocols)
2012
0
{
2013
0
  if (!nego)
2014
0
    return FALSE;
2015
2016
0
  nego->RequestedProtocols = RequestedProtocols;
2017
0
  return TRUE;
2018
0
}
2019
2020
NEGO_STATE nego_get_state(const rdpNego* nego)
2021
0
{
2022
0
  if (!nego)
2023
0
    return NEGO_STATE_FAIL;
2024
2025
0
  return nego->state;
2026
0
}
2027
2028
BOOL nego_set_state(rdpNego* nego, NEGO_STATE state)
2029
17.4k
{
2030
17.4k
  if (!nego)
2031
0
    return FALSE;
2032
2033
17.4k
  nego->state = state;
2034
17.4k
  return TRUE;
2035
17.4k
}
2036
2037
SEC_WINNT_AUTH_IDENTITY* nego_get_identity(rdpNego* nego)
2038
0
{
2039
0
  rdpNla* nla = NULL;
2040
0
  if (!nego)
2041
0
    return NULL;
2042
2043
0
  nla = transport_get_nla(nego->transport);
2044
0
  return nla_get_identity(nla);
2045
0
}
2046
2047
void nego_free_nla(rdpNego* nego)
2048
0
{
2049
0
  if (!nego || !nego->transport)
2050
0
    return;
2051
2052
0
  transport_set_nla(nego->transport, NULL);
2053
0
}
2054
2055
const BYTE* nego_get_routing_token(const rdpNego* nego, DWORD* RoutingTokenLength)
2056
0
{
2057
0
  if (!nego)
2058
0
    return NULL;
2059
0
  if (RoutingTokenLength)
2060
0
    *RoutingTokenLength = nego->RoutingTokenLength;
2061
0
  return nego->RoutingToken;
2062
0
}
2063
2064
const char* nego_protocol_to_str(UINT32 protocol, char* buffer, size_t size)
2065
0
{
2066
0
  const UINT32 mask = ~(PROTOCOL_SSL | PROTOCOL_HYBRID | PROTOCOL_RDSTLS | PROTOCOL_HYBRID_EX |
2067
0
                        PROTOCOL_RDSAAD | PROTOCOL_FAILED_NEGO);
2068
0
  char str[48] = { 0 };
2069
2070
0
  if (protocol & PROTOCOL_SSL)
2071
0
    (void)winpr_str_append("SSL", str, sizeof(str), "|");
2072
0
  if (protocol & PROTOCOL_HYBRID)
2073
0
    (void)winpr_str_append("HYBRID", str, sizeof(str), "|");
2074
0
  if (protocol & PROTOCOL_RDSTLS)
2075
0
    (void)winpr_str_append("RDSTLS", str, sizeof(str), "|");
2076
0
  if (protocol & PROTOCOL_HYBRID_EX)
2077
0
    (void)winpr_str_append("HYBRID_EX", str, sizeof(str), "|");
2078
0
  if (protocol & PROTOCOL_RDSAAD)
2079
0
    (void)winpr_str_append("RDSAAD", str, sizeof(str), "|");
2080
0
  if (protocol & PROTOCOL_FAILED_NEGO)
2081
0
    (void)winpr_str_append("NEGO FAILED", str, sizeof(str), "|");
2082
2083
0
  if (protocol == PROTOCOL_RDP)
2084
0
    (void)winpr_str_append("RDP", str, sizeof(str), "");
2085
0
  else if ((protocol & mask) != 0)
2086
0
    (void)winpr_str_append("UNKNOWN", str, sizeof(str), "|");
2087
2088
0
  (void)_snprintf(buffer, size, "[%s][0x%08" PRIx32 "]", str, protocol);
2089
0
  return buffer;
2090
0
}