Coverage Report

Created: 2024-09-08 06:20

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