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