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 /* the token should not be multiline. */
1006 if (winpr_strnstr(str, "\n", len) || winpr_strnstr(str, "\r", len))
1007 return FALSE;
1008
1009 if (isToken)
1010 result = nego_set_routing_token(nego, str, (UINT32)len);
1011 else
1012 result = nego_set_cookie(nego, str);
1013 }
1014 }
1015
1016 if (!result)
1017 {
1018 if (!Stream_SetPosition(s, pos))
1019 return FALSE;
1020 WLog_Print(nego->log, WLOG_ERROR, "invalid %s received",
1021 isToken ? "routing token" : "cookie");
1022 }
1023 else
1024 {
1025 WLog_Print(nego->log, WLOG_DEBUG, "received %s [%s]", isToken ? "routing token" : "cookie",
1026 str);
1027 }
1028
1029 return result;
1030}
1031
1041BOOL nego_read_request(rdpNego* nego, wStream* s)
1042{
1043 BYTE li = 0;
1044 BYTE type = 0;
1045 UINT16 length = 0;
1046
1047 WINPR_ASSERT(nego);
1048 WINPR_ASSERT(s);
1049
1050 if (!tpkt_read_header(s, &length))
1051 return FALSE;
1052
1053 if (!tpdu_read_connection_request(s, &li, length))
1054 return FALSE;
1055
1056 if (li != Stream_GetRemainingLength(s) + 6)
1057 {
1058 WLog_Print(nego->log, WLOG_ERROR, "Incorrect TPDU length indicator.");
1059 return FALSE;
1060 }
1061
1062 if (!nego_read_request_token_or_cookie(nego, s))
1063 {
1064 WLog_Print(nego->log, WLOG_ERROR, "Failed to parse routing token or cookie.");
1065 return FALSE;
1066 }
1067
1068 if (Stream_GetRemainingLength(s) >= 8)
1069 {
1070 /* rdpNegData (optional) */
1071 Stream_Read_UINT8(s, type); /* Type */
1072
1073 if (type != TYPE_RDP_NEG_REQ)
1074 {
1075 WLog_Print(nego->log, WLOG_ERROR, "Incorrect negotiation request type %" PRIu8 "",
1076 type);
1077 return FALSE;
1078 }
1079
1080 if (!nego_process_negotiation_request(nego, s))
1081 return FALSE;
1082 }
1083
1084 return tpkt_ensure_stream_consumed(nego->log, s, length);
1085}
1086
1093void nego_send(rdpNego* nego)
1094{
1095 WINPR_ASSERT(nego);
1096
1097 switch (nego_get_state(nego))
1098 {
1099 case NEGO_STATE_AAD:
1100 nego_attempt_rdsaad(nego);
1101 break;
1102 case NEGO_STATE_RDSTLS:
1103 nego_attempt_rdstls(nego);
1104 break;
1105 case NEGO_STATE_EXT:
1106 nego_attempt_ext(nego);
1107 break;
1108 case NEGO_STATE_NLA:
1109 nego_attempt_nla(nego);
1110 break;
1111 case NEGO_STATE_TLS:
1112 nego_attempt_tls(nego);
1113 break;
1114 case NEGO_STATE_RDP:
1115 nego_attempt_rdp(nego);
1116 break;
1117 default:
1118 WLog_Print(nego->log, WLOG_ERROR, "invalid negotiation state for sending");
1119 break;
1120 }
1121}
1122
1133BOOL nego_send_negotiation_request(rdpNego* nego)
1134{
1135 BOOL rc = FALSE;
1136 wStream* s = Stream_New(nullptr, 512);
1137
1138 WINPR_ASSERT(nego);
1139 if (!s)
1140 {
1141 WLog_Print(nego->log, WLOG_ERROR, "Stream_New failed!");
1142 return FALSE;
1143 }
1144
1145 const size_t bm = Stream_GetPosition(s);
1146 if (!Stream_SafeZero(s, TPDU_CONNECTION_REQUEST_LENGTH))
1147 goto fail;
1148
1149 if (nego->RoutingToken)
1150 {
1151 if (!Stream_EnsureRemainingCapacity(s, nego->RoutingTokenLength))
1152 goto fail;
1153 Stream_Write(s, nego->RoutingToken, nego->RoutingTokenLength);
1154
1155 /* Ensure Routing Token is correctly terminated - may already be present in string */
1156
1157 if ((nego->RoutingTokenLength > 2) &&
1158 (nego->RoutingToken[nego->RoutingTokenLength - 2] == 0x0D) &&
1159 (nego->RoutingToken[nego->RoutingTokenLength - 1] == 0x0A))
1160 {
1161 WLog_Print(nego->log, WLOG_DEBUG,
1162 "Routing token looks correctly terminated - use verbatim");
1163 }
1164 else
1165 {
1166 WLog_Print(nego->log, WLOG_DEBUG, "Adding terminating CRLF to routing token");
1167 if (!Stream_EnsureRemainingCapacity(s, 2))
1168 goto fail;
1169 Stream_Write_UINT8(s, 0x0D); /* CR */
1170 Stream_Write_UINT8(s, 0x0A); /* LF */
1171 }
1172 }
1173 else if (nego->cookie)
1174 {
1175 size_t cookie_length = strlen(nego->cookie);
1176
1177 if (cookie_length > nego->CookieMaxLength)
1178 cookie_length = nego->CookieMaxLength;
1179
1180 if (!Stream_EnsureRemainingCapacity(s, 17))
1181 goto fail;
1182 Stream_Write(s, "Cookie: mstshash=", 17);
1183 if (!Stream_EnsureRemainingCapacity(s, cookie_length))
1184 goto fail;
1185 Stream_Write(s, (BYTE*)nego->cookie, cookie_length);
1186 if (!Stream_EnsureRemainingCapacity(s, 2))
1187 goto fail;
1188 Stream_Write_UINT8(s, 0x0D); /* CR */
1189 Stream_Write_UINT8(s, 0x0A); /* LF */
1190 }
1191
1192 {
1193 char buffer[64] = WINPR_C_ARRAY_INIT;
1194 WLog_Print(nego->log, WLOG_DEBUG, "RequestedProtocols: %s",
1195 nego_protocol_to_str(nego->RequestedProtocols, buffer, sizeof(buffer)));
1196 }
1197
1198 if ((nego->RequestedProtocols > PROTOCOL_RDP) || (nego->sendNegoData))
1199 {
1200 UINT8 flags = 0;
1201
1202 /* RDP_NEG_DATA must be present for TLS and NLA */
1203 if (nego->RestrictedAdminModeRequired)
1204 flags |= RESTRICTED_ADMIN_MODE_REQUIRED;
1205
1206 if (nego->RemoteCredsGuardRequired)
1207 flags |= REDIRECTED_AUTHENTICATION_MODE_REQUIRED;
1208
1209 if (!Stream_EnsureRemainingCapacity(s, 8))
1210 goto fail;
1211
1212 Stream_Write_UINT8(s, TYPE_RDP_NEG_REQ);
1213 Stream_Write_UINT8(s, flags);
1214 Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */
1215 Stream_Write_UINT32(s, nego->RequestedProtocols); /* requestedProtocols */
1216 }
1217
1218 const size_t em = Stream_GetPosition(s);
1219 if ((em < 5) || (em > UINT16_MAX))
1220 goto fail;
1221 if (!Stream_SetPosition(s, bm))
1222 goto fail;
1223 if (!tpkt_write_header(s, (UINT16)em))
1224 goto fail;
1225 if (!tpdu_write_connection_request(s, (UINT16)em - 5))
1226 goto fail;
1227 if (!Stream_SetPosition(s, em))
1228 goto fail;
1229 Stream_SealLength(s);
1230 rc = (transport_write(nego->transport, s) >= 0);
1231fail:
1232 Stream_Free(s, TRUE);
1233 return rc;
1234}
1235
1236WINPR_ATTR_NODISCARD
1237static BOOL nego_process_correlation_info(WINPR_ATTR_UNUSED rdpNego* nego, wStream* s)
1238{
1239 UINT8 type = 0;
1240 UINT8 flags = 0;
1241 UINT16 length = 0;
1242 BYTE correlationId[16] = WINPR_C_ARRAY_INIT;
1243
1244 if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 36))
1245 {
1246 WLog_Print(nego->log, WLOG_ERROR,
1247 "RDP_NEG_REQ::flags CORRELATION_INFO_PRESENT but data is missing");
1248 return FALSE;
1249 }
1250
1251 Stream_Read_UINT8(s, type);
1252 if (type != TYPE_RDP_CORRELATION_INFO)
1253 {
1254 WLog_Print(nego->log, WLOG_ERROR,
1255 "(RDP_NEG_CORRELATION_INFO::type != TYPE_RDP_CORRELATION_INFO");
1256 return FALSE;
1257 }
1258 Stream_Read_UINT8(s, flags);
1259 if (flags != 0)
1260 {
1261 WLog_Print(nego->log, WLOG_ERROR, "(RDP_NEG_CORRELATION_INFO::flags != 0");
1262 return FALSE;
1263 }
1264 Stream_Read_UINT16(s, length);
1265 if (length != 36)
1266 {
1267 WLog_Print(nego->log, WLOG_ERROR, "(RDP_NEG_CORRELATION_INFO::length != 36");
1268 return FALSE;
1269 }
1270
1271 Stream_Read(s, correlationId, sizeof(correlationId));
1272 if ((correlationId[0] == 0x00) || (correlationId[0] == 0xF4))
1273 {
1274 WLog_Print(nego->log, WLOG_ERROR,
1275 "(RDP_NEG_CORRELATION_INFO::correlationId[0] has invalid value 0x%02" PRIx8,
1276 correlationId[0]);
1277 return FALSE;
1278 }
1279 for (size_t x = 0; x < ARRAYSIZE(correlationId); x++)
1280 {
1281 if (correlationId[x] == 0x0D)
1282 {
1283 WLog_Print(nego->log, WLOG_ERROR,
1284 "(RDP_NEG_CORRELATION_INFO::correlationId[%" PRIuz
1285 "] has invalid value 0x%02" PRIx8,
1286 x, correlationId[x]);
1287 return FALSE;
1288 }
1289 }
1290 Stream_Seek(s, 16); /* skip reserved bytes */
1291
1292 WLog_Print(nego->log, WLOG_INFO,
1293 "RDP_NEG_CORRELATION_INFO::correlationId = { %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8
1294 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8
1295 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8 ", %02" PRIx8
1296 ", %02" PRIx8 " }",
1297 correlationId[0], correlationId[1], correlationId[2], correlationId[3],
1298 correlationId[4], correlationId[5], correlationId[6], correlationId[7],
1299 correlationId[8], correlationId[9], correlationId[10], correlationId[11],
1300 correlationId[12], correlationId[13], correlationId[14], correlationId[15]);
1301 return TRUE;
1302}
1303
1304BOOL nego_process_negotiation_request(rdpNego* nego, wStream* s)
1305{
1306 BYTE flags = 0;
1307 UINT16 length = 0;
1308
1309 WINPR_ASSERT(nego);
1310 WINPR_ASSERT(s);
1311
1312 if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 7))
1313 return FALSE;
1314 Stream_Read_UINT8(s, flags);
1315 if ((flags & ~(RESTRICTED_ADMIN_MODE_REQUIRED | REDIRECTED_AUTHENTICATION_MODE_REQUIRED |
1316 CORRELATION_INFO_PRESENT)) != 0)
1317 {
1318 WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_REQ::flags invalid value 0x%02" PRIx8, flags);
1319 return FALSE;
1320 }
1321 if (flags & RESTRICTED_ADMIN_MODE_REQUIRED)
1322 {
1323 if (nego->RestrictedAdminModeSupported)
1324 {
1325 WLog_Print(nego->log, WLOG_INFO, "RDP_NEG_REQ::flags RESTRICTED_ADMIN_MODE_REQUIRED");
1326 }
1327 else
1328 {
1329 WLog_Print(nego->log, WLOG_ERROR,
1330 "RDP_NEG_REQ::flags RESTRICTED_ADMIN_MODE_REQUIRED but disabled");
1331 return FALSE;
1332 }
1333 }
1334
1335 if (flags & REDIRECTED_AUTHENTICATION_MODE_REQUIRED)
1336 {
1337 if (nego->RemoteCredsGuardSupported)
1338 {
1339 WLog_Print(nego->log, WLOG_INFO,
1340 "RDP_NEG_REQ::flags REDIRECTED_AUTHENTICATION_MODE_REQUIRED");
1341 nego->RemoteCredsGuardActive = TRUE;
1342 }
1343 else
1344 {
1345 /* If both RESTRICTED_ADMIN_MODE_REQUIRED and REDIRECTED_AUTHENTICATION_MODE_REQUIRED
1346 * are set, it means one or the other. In this case, don't fail if Remote Guard isn't
1347 * available. */
1348 if (flags & RESTRICTED_ADMIN_MODE_REQUIRED)
1349 {
1350 WLog_Print(nego->log, WLOG_INFO,
1351 "RDP_NEG_REQ::flags REDIRECTED_AUTHENTICATION_MODE_REQUIRED ignored.");
1352 }
1353 else
1354 {
1355 WLog_Print(
1356 nego->log, WLOG_ERROR,
1357 "RDP_NEG_REQ::flags REDIRECTED_AUTHENTICATION_MODE_REQUIRED but disabled");
1358 return FALSE;
1359 }
1360 }
1361 }
1362
1363 Stream_Read_UINT16(s, length);
1364 if (length != 8)
1365 {
1366 WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_REQ::length != 8");
1367 return FALSE;
1368 }
1369 Stream_Read_UINT32(s, nego->RequestedProtocols);
1370
1371 if (flags & CORRELATION_INFO_PRESENT)
1372 {
1373 if (!nego_process_correlation_info(nego, s))
1374 return FALSE;
1375 }
1376
1377 {
1378 char buffer[64] = WINPR_C_ARRAY_INIT;
1379 WLog_Print(nego->log, WLOG_DEBUG, "RDP_NEG_REQ: RequestedProtocol: %s",
1380 nego_protocol_to_str(nego->RequestedProtocols, buffer, sizeof(buffer)));
1381 }
1382 nego_set_state(nego, NEGO_STATE_FINAL);
1383 return TRUE;
1384}
1385
1386WINPR_ATTR_NODISCARD
1387static const char* nego_rdp_neg_rsp_flags_str(UINT32 flags)
1388{
1389 const uint32_t mask =
1390 (EXTENDED_CLIENT_DATA_SUPPORTED | DYNVC_GFX_PROTOCOL_SUPPORTED | RDP_NEGRSP_RESERVED |
1391 RESTRICTED_ADMIN_MODE_SUPPORTED | REDIRECTED_AUTHENTICATION_MODE_SUPPORTED);
1392 static char buffer[1024] = WINPR_C_ARRAY_INIT;
1393
1394 (void)_snprintf(buffer, ARRAYSIZE(buffer), "[0x%02" PRIx32 "] ", flags);
1395 if (flags & EXTENDED_CLIENT_DATA_SUPPORTED)
1396 winpr_str_append("EXTENDED_CLIENT_DATA_SUPPORTED", buffer, sizeof(buffer), "|");
1397 if (flags & DYNVC_GFX_PROTOCOL_SUPPORTED)
1398 winpr_str_append("DYNVC_GFX_PROTOCOL_SUPPORTED", buffer, sizeof(buffer), "|");
1399 if (flags & RDP_NEGRSP_RESERVED)
1400 winpr_str_append("RDP_NEGRSP_RESERVED", buffer, sizeof(buffer), "|");
1401 if (flags & RESTRICTED_ADMIN_MODE_SUPPORTED)
1402 winpr_str_append("RESTRICTED_ADMIN_MODE_SUPPORTED", buffer, sizeof(buffer), "|");
1403 if (flags & REDIRECTED_AUTHENTICATION_MODE_SUPPORTED)
1404 winpr_str_append("REDIRECTED_AUTHENTICATION_MODE_SUPPORTED", buffer, sizeof(buffer), "|");
1405 if (flags & ~mask)
1406 {
1407 char buffer2[32] = WINPR_C_ARRAY_INIT;
1408 (void)_snprintf(buffer2, sizeof(buffer2), "UNKNOWN[0x%04" PRIx32 "]", flags & ~mask);
1409 winpr_str_append(buffer2, buffer, sizeof(buffer), "|");
1410 }
1411
1412 return buffer;
1413}
1414
1415BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s)
1416{
1417 UINT16 length = 0;
1418
1419 WINPR_ASSERT(nego);
1420 WINPR_ASSERT(s);
1421
1422 if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 7))
1423 {
1424 nego_set_state(nego, NEGO_STATE_FAIL);
1425 return FALSE;
1426 }
1427
1428 Stream_Read_UINT8(s, nego->flags);
1429 WLog_Print(nego->log, WLOG_DEBUG, "RDP_NEG_RSP::flags = { %s }",
1430 nego_rdp_neg_rsp_flags_str(nego->flags));
1431
1432 if ((nego->flags & RESTRICTED_ADMIN_MODE_SUPPORTED) == 0)
1433 {
1434 if (nego->RestrictedAdminModeRequired)
1435 {
1436 WLog_Print(nego->log, WLOG_ERROR,
1437 "restricted-admin mode requested but not supported, terminating");
1438 return -1;
1439 }
1440 }
1441
1442 if ((nego->flags & REDIRECTED_AUTHENTICATION_MODE_SUPPORTED) == 0)
1443 {
1444 if (nego->RemoteCredsGuardRequired)
1445 {
1446 WLog_Print(nego->log, WLOG_ERROR,
1447 "remote credential guard requested but not supported, terminating");
1448 return -1;
1449 }
1450 }
1451
1452 Stream_Read_UINT16(s, length);
1453 if (length != 8)
1454 {
1455 WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_RSP::length != 8");
1456 nego_set_state(nego, NEGO_STATE_FAIL);
1457 return FALSE;
1458 }
1459 UINT32 SelectedProtocol = 0;
1460 Stream_Read_UINT32(s, SelectedProtocol);
1461
1462 if (!nego_set_selected_protocol(nego, SelectedProtocol))
1463 return FALSE;
1464 return nego_set_state(nego, NEGO_STATE_FINAL);
1465}
1466
1467WINPR_ATTR_NODISCARD
1468static const char* nego_rdp_neg_fail_str(uint32_t what)
1469{
1470 switch (what)
1471 {
1472 case SSL_REQUIRED_BY_SERVER:
1473 return "SSL_REQUIRED_BY_SERVER";
1474 case SSL_NOT_ALLOWED_BY_SERVER:
1475 return "SSL_NOT_ALLOWED_BY_SERVER";
1476 case SSL_CERT_NOT_ON_SERVER:
1477 return "SSL_CERT_NOT_ON_SERVER";
1478 case INCONSISTENT_FLAGS:
1479 return "INCONSISTENT_FLAGS";
1480 case HYBRID_REQUIRED_BY_SERVER:
1481 return "HYBRID_REQUIRED_BY_SERVER";
1482 case SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER:
1483 return "SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER";
1484 default:
1485 return "UNKNOWN";
1486 }
1487}
1488
1489static void nego_disable_all_except(rdpNego* nego, uint32_t what)
1490{
1491 WINPR_ASSERT(nego);
1492
1493 char buffer[32] = WINPR_C_ARRAY_INIT;
1494 WLog_Print(nego->log, WLOG_DEBUG, "Disabling all modes except %s",
1495 nego_protocol_to_str(what, buffer, sizeof(buffer)));
1496
1497 for (size_t x = 0; x < ARRAYSIZE(nego->EnabledProtocols); x++)
1498 {
1499 if (x == what)
1500 continue;
1501 nego->EnabledProtocols[x] = FALSE;
1502 }
1503}
1504
1513BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s)
1514{
1515 BYTE flags = 0;
1516 UINT16 length = 0;
1517
1518 WINPR_ASSERT(nego);
1519 WINPR_ASSERT(s);
1520
1521 WLog_Print(nego->log, WLOG_DEBUG, "RDP_NEG_FAILURE");
1522 if (!Stream_CheckAndLogRequiredLengthWLog(nego->log, s, 7))
1523 return FALSE;
1524
1525 Stream_Read_UINT8(s, flags);
1526 if (flags != 0)
1527 {
1528 WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_FAILURE::flags = 0x%02" PRIx8, flags);
1529 return FALSE;
1530 }
1531 Stream_Read_UINT16(s, length);
1532 if (length != 8)
1533 {
1534 WLog_Print(nego->log, WLOG_ERROR, "RDP_NEG_FAILURE::length != 8");
1535 return FALSE;
1536 }
1537 const uint32_t failureCode = Stream_Get_UINT32(s);
1538 const char* failureStr = nego_rdp_neg_fail_str(failureCode);
1539 DWORD level = WLOG_WARN;
1540
1541 /* Remember why the server refused. The cases below fall back to another protocol, so
1542 * this is only turned into an error once the negotiation has terminally failed. */
1543 nego->failureCode = failureCode;
1544
1545 switch (failureCode)
1546 {
1547 case SSL_REQUIRED_BY_SERVER:
1548 nego_disable_all_except(nego, PROTOCOL_SSL);
1549 break;
1550
1551 case SSL_NOT_ALLOWED_BY_SERVER:
1552 nego_disable_all_except(nego, PROTOCOL_RDP);
1553 nego->sendNegoData = TRUE;
1554 break;
1555
1556 case SSL_CERT_NOT_ON_SERVER:
1557 level = WLOG_ERROR;
1558 nego->sendNegoData = TRUE;
1559 break;
1560
1561 case INCONSISTENT_FLAGS:
1562 level = WLOG_ERROR;
1563 break;
1564
1565 case HYBRID_REQUIRED_BY_SERVER:
1566 nego_disable_all_except(nego, PROTOCOL_HYBRID);
1567 break;
1568
1569 default:
1570 level = WLOG_ERROR;
1571 break;
1572 }
1573
1574 WLog_Print(nego->log, level, "Error: %s [0x%08" PRIx32 "]", failureStr, failureCode);
1575 nego_set_state(nego, NEGO_STATE_FAIL);
1576 return TRUE;
1577}
1578
1584BOOL nego_send_negotiation_response(rdpNego* nego)
1585{
1586 BOOL status = FALSE;
1587 BYTE flags = 0;
1588 rdpContext* context = nullptr;
1589 rdpSettings* settings = nullptr;
1590
1591 WINPR_ASSERT(nego);
1592 context = transport_get_context(nego->transport);
1593 WINPR_ASSERT(context);
1594
1595 settings = context->settings;
1596 WINPR_ASSERT(settings);
1597
1598 wStream* s = Stream_New(nullptr, 512);
1599
1600 if (!s)
1601 {
1602 WLog_Print(nego->log, WLOG_ERROR, "Stream_New failed!");
1603 return FALSE;
1604 }
1605
1606 UINT16 length = TPDU_CONNECTION_CONFIRM_LENGTH;
1607 const size_t bm = Stream_GetPosition(s);
1608 if (!Stream_SafeZero(s, length))
1609 goto fail;
1610
1611 if (nego->SelectedProtocol & PROTOCOL_FAILED_NEGO)
1612 {
1613 UINT32 errorCode = (nego->SelectedProtocol & ~PROTOCOL_FAILED_NEGO);
1614 flags = 0;
1615 Stream_Write_UINT8(s, TYPE_RDP_NEG_FAILURE);
1616 Stream_Write_UINT8(s, flags); /* flags */
1617 Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */
1618 Stream_Write_UINT32(s, errorCode);
1619 length += 8;
1620 }
1621 else
1622 {
1623 flags = EXTENDED_CLIENT_DATA_SUPPORTED;
1624
1625 if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline))
1626 flags |= DYNVC_GFX_PROTOCOL_SUPPORTED;
1627
1628 if (nego->RestrictedAdminModeSupported)
1629 flags |= RESTRICTED_ADMIN_MODE_SUPPORTED;
1630
1631 if (nego->RemoteCredsGuardSupported)
1632 flags |= REDIRECTED_AUTHENTICATION_MODE_SUPPORTED;
1633
1634 /* RDP_NEG_DATA must be present for TLS, NLA, RDP and RDSTLS */
1635 Stream_Write_UINT8(s, TYPE_RDP_NEG_RSP);
1636 Stream_Write_UINT8(s, flags); /* flags */
1637 Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */
1638 Stream_Write_UINT32(s, nego->SelectedProtocol); /* selectedProtocol */
1639 length += 8;
1640 }
1641
1642 const size_t em = Stream_GetPosition(s);
1643 if (!Stream_SetPosition(s, bm))
1644 goto fail;
1645 if (!tpkt_write_header(s, length))
1646 goto fail;
1647
1648 if (!tpdu_write_connection_confirm(s, length - 5))
1649 goto fail;
1650
1651 if (!Stream_SetPosition(s, em))
1652 goto fail;
1653 Stream_SealLength(s);
1654
1655 status = (transport_write(nego->transport, s) >= 0);
1656
1657fail:
1658 Stream_Free(s, TRUE);
1659
1660 if (status)
1661 {
1662 /* update settings with negotiated protocol security */
1663 if (!freerdp_settings_set_uint32(settings, FreeRDP_RequestedProtocols,
1664 nego->RequestedProtocols))
1665 return FALSE;
1666 if (!freerdp_settings_set_uint32(settings, FreeRDP_SelectedProtocol,
1667 nego->SelectedProtocol))
1668 return FALSE;
1669
1670 switch (nego->SelectedProtocol)
1671 {
1672 case PROTOCOL_RDP:
1673 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, FALSE))
1674 return FALSE;
1675 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1676 return FALSE;
1677 if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
1678 return FALSE;
1679 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
1680 return FALSE;
1681 if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, TRUE))
1682 return FALSE;
1683
1684 if (freerdp_settings_get_uint32(settings, FreeRDP_EncryptionLevel) ==
1685 ENCRYPTION_LEVEL_NONE)
1686 {
1691 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1692 ENCRYPTION_LEVEL_CLIENT_COMPATIBLE))
1693 return FALSE;
1694 }
1695
1696 if (freerdp_settings_get_bool(settings, FreeRDP_LocalConnection))
1697 {
1704 WLog_Print(nego->log, WLOG_INFO,
1705 "Turning off encryption for local peer with standard rdp security");
1706 if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1707 return FALSE;
1708 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1709 ENCRYPTION_LEVEL_NONE))
1710 return FALSE;
1711 }
1712 else if (!freerdp_settings_get_pointer(settings, FreeRDP_RdpServerRsaKey))
1713 {
1714 WLog_Print(nego->log, WLOG_ERROR, "Missing server certificate");
1715 return FALSE;
1716 }
1717 break;
1718 case PROTOCOL_SSL:
1719 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1720 return FALSE;
1721 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1722 return FALSE;
1723 if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
1724 return FALSE;
1725 if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, FALSE))
1726 return FALSE;
1727 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1728 return FALSE;
1729 if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1730 return FALSE;
1731
1732 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1733 ENCRYPTION_LEVEL_NONE))
1734 return FALSE;
1735 break;
1736 case PROTOCOL_HYBRID:
1737 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1738 return FALSE;
1739 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, TRUE))
1740 return FALSE;
1741 if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, TRUE))
1742 return FALSE;
1743 if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, FALSE))
1744 return FALSE;
1745 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1746 return FALSE;
1747 if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1748 return FALSE;
1749
1750 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1751 ENCRYPTION_LEVEL_NONE))
1752 return FALSE;
1753 break;
1754 case PROTOCOL_RDSTLS:
1755 if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
1756 return FALSE;
1757 if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
1758 return FALSE;
1759 if (!freerdp_settings_set_bool(settings, FreeRDP_ExtSecurity, FALSE))
1760 return FALSE;
1761 if (!freerdp_settings_set_bool(settings, FreeRDP_RdstlsSecurity, TRUE))
1762 return FALSE;
1763 if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, FALSE))
1764 return FALSE;
1765 if (!freerdp_settings_set_bool(settings, FreeRDP_UseRdpSecurityLayer, FALSE))
1766 return FALSE;
1767
1768 if (!freerdp_settings_set_uint32(settings, FreeRDP_EncryptionLevel,
1769 ENCRYPTION_LEVEL_NONE))
1770 return FALSE;
1771 break;
1772 default:
1773 break;
1774 }
1775 }
1776
1777 return status;
1778}
1779
1785void nego_init(rdpNego* nego)
1786{
1787 WINPR_ASSERT(nego);
1788 nego_set_state(nego, NEGO_STATE_INITIAL);
1789 nego->RequestedProtocols = PROTOCOL_RDP;
1790 nego->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH;
1791 nego->sendNegoData = FALSE;
1792 nego->flags = 0;
1793 nego->failureCode = 0;
1794}
1795
1804rdpNego* nego_new(rdpTransport* transport)
1805{
1806 rdpNego* nego = (rdpNego*)calloc(1, sizeof(rdpNego));
1807
1808 if (!nego)
1809 return nullptr;
1810
1811 nego->log = WLog_Get(NEGO_TAG);
1812 WINPR_ASSERT(nego->log);
1813 nego->transport = transport;
1814 nego_init(nego);
1815 return nego;
1816}
1817
1823void nego_free(rdpNego* nego)
1824{
1825 if (nego)
1826 {
1827 free(nego->RoutingToken);
1828 free(nego->cookie);
1829 free(nego);
1830 }
1831}
1832
1842BOOL nego_set_target(rdpNego* nego, const char* hostname, UINT16 port)
1843{
1844 WINPR_ASSERT(nego);
1845 WINPR_ASSERT(hostname);
1846
1847 nego->hostname = hostname;
1848 nego->port = port;
1849 return TRUE;
1850}
1851
1859void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer)
1860{
1861 WLog_Print(nego->log, WLOG_DEBUG, "Enabling security layer negotiation: %s",
1862 NegotiateSecurityLayer ? "TRUE" : "FALSE");
1863 nego->NegotiateSecurityLayer = NegotiateSecurityLayer;
1864}
1865
1873void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired)
1874{
1875 WLog_Print(nego->log, WLOG_DEBUG, "Enabling restricted admin mode: %s",
1876 RestrictedAdminModeRequired ? "TRUE" : "FALSE");
1877 nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired;
1878}
1879
1880void nego_set_restricted_admin_mode_supported(rdpNego* nego, BOOL enabled)
1881{
1882 WINPR_ASSERT(nego);
1883
1884 nego->RestrictedAdminModeSupported = enabled;
1885}
1886
1887void nego_set_RCG_required(rdpNego* nego, BOOL enabled)
1888{
1889 WINPR_ASSERT(nego);
1890
1891 WLog_Print(nego->log, WLOG_DEBUG, "Enabling remoteCredentialGuards: %s",
1892 enabled ? "TRUE" : "FALSE");
1893 nego->RemoteCredsGuardRequired = enabled;
1894}
1895
1896void nego_set_RCG_supported(rdpNego* nego, BOOL enabled)
1897{
1898 WINPR_ASSERT(nego);
1899
1900 nego->RemoteCredsGuardSupported = enabled;
1901}
1902
1903BOOL nego_get_remoteCredentialGuard(const rdpNego* nego)
1904{
1905 WINPR_ASSERT(nego);
1906
1907 return nego->RemoteCredsGuardActive;
1908}
1909
1910void nego_set_childsession_enabled(rdpNego* nego, BOOL ChildSessionEnabled)
1911{
1912 WINPR_ASSERT(nego);
1913 nego->ConnectChildSession = ChildSessionEnabled;
1914}
1915
1916void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled)
1917{
1918 nego->GatewayEnabled = GatewayEnabled;
1919}
1920
1921void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal)
1922{
1923 nego->GatewayBypassLocal = GatewayBypassLocal;
1924}
1925
1932void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp)
1933{
1934 WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDP security: %s", enable_rdp ? "TRUE" : "FALSE");
1935 nego->EnabledProtocols[PROTOCOL_RDP] = enable_rdp;
1936}
1937
1944void nego_enable_tls(rdpNego* nego, BOOL enable_tls)
1945{
1946 WLog_Print(nego->log, WLOG_DEBUG, "Enabling TLS security: %s", enable_tls ? "TRUE" : "FALSE");
1947 nego->EnabledProtocols[PROTOCOL_SSL] = enable_tls;
1948}
1949
1957void nego_enable_nla(rdpNego* nego, BOOL enable_nla)
1958{
1959 WLog_Print(nego->log, WLOG_DEBUG, "Enabling NLA security: %s", enable_nla ? "TRUE" : "FALSE");
1960 nego->EnabledProtocols[PROTOCOL_HYBRID] = enable_nla;
1961}
1962
1970void nego_enable_rdstls(rdpNego* nego, BOOL enable_rdstls)
1971{
1972 WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDSTLS security: %s",
1973 enable_rdstls ? "TRUE" : "FALSE");
1974 nego->EnabledProtocols[PROTOCOL_RDSTLS] = enable_rdstls;
1975}
1976
1984void nego_enable_ext(rdpNego* nego, BOOL enable_ext)
1985{
1986 WLog_Print(nego->log, WLOG_DEBUG, "Enabling NLA extended security: %s",
1987 enable_ext ? "TRUE" : "FALSE");
1988 nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = enable_ext;
1989}
1990
1998void nego_enable_aad(rdpNego* nego, BOOL enable_aad)
1999{
2000 WINPR_ASSERT(nego);
2001 if (aad_is_supported())
2002 {
2003 WLog_Print(nego->log, WLOG_DEBUG, "Enabling RDS AAD security: %s",
2004 enable_aad ? "TRUE" : "FALSE");
2005 nego->EnabledProtocols[PROTOCOL_RDSAAD] = enable_aad;
2006 }
2007 else
2008 {
2009 WLog_Print(nego->log, WLOG_WARN, "This build does not support AAD security, disabling.");
2010 }
2011}
2012
2022BOOL nego_set_routing_token(rdpNego* nego, const void* RoutingToken, DWORD RoutingTokenLength)
2023{
2024 if (RoutingTokenLength == 0)
2025 return FALSE;
2026
2027 free(nego->RoutingToken);
2028 nego->RoutingTokenLength = RoutingTokenLength;
2029 nego->RoutingToken = (BYTE*)malloc(nego->RoutingTokenLength);
2030
2031 if (!nego->RoutingToken)
2032 return FALSE;
2033
2034 CopyMemory(nego->RoutingToken, RoutingToken, nego->RoutingTokenLength);
2035 return TRUE;
2036}
2037
2046BOOL nego_set_cookie(rdpNego* nego, const char* cookie)
2047{
2048 if (nego->cookie)
2049 {
2050 free(nego->cookie);
2051 nego->cookie = nullptr;
2052 }
2053
2054 if (!cookie)
2055 return TRUE;
2056
2057 nego->cookie = _strdup(cookie);
2058
2059 return (nego->cookie != nullptr);
2060}
2061
2068void nego_set_cookie_max_length(rdpNego* nego, UINT32 CookieMaxLength)
2069{
2070 nego->CookieMaxLength = CookieMaxLength;
2071}
2072
2079void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL SendPreconnectionPdu)
2080{
2081 nego->SendPreconnectionPdu = SendPreconnectionPdu;
2082}
2083
2090void nego_set_preconnection_id(rdpNego* nego, UINT32 PreconnectionId)
2091{
2092 nego->PreconnectionId = PreconnectionId;
2093}
2094
2101void nego_set_preconnection_blob(rdpNego* nego, const char* PreconnectionBlob)
2102{
2103 nego->PreconnectionBlob = PreconnectionBlob;
2104}
2105
2106UINT32 nego_get_selected_protocol(const rdpNego* nego)
2107{
2108 if (!nego)
2109 return 0;
2110
2111 return nego->SelectedProtocol;
2112}
2113
2114BOOL nego_set_selected_protocol(rdpNego* nego, UINT32 SelectedProtocol)
2115{
2116 WINPR_ASSERT(nego);
2117 nego->SelectedProtocol = SelectedProtocol;
2118 return TRUE;
2119}
2120
2121UINT32 nego_get_requested_protocols(const rdpNego* nego)
2122{
2123 if (!nego)
2124 return 0;
2125
2126 return nego->RequestedProtocols;
2127}
2128
2129BOOL nego_set_requested_protocols(rdpNego* nego, UINT32 RequestedProtocols)
2130{
2131 if (!nego)
2132 return FALSE;
2133
2134 nego->RequestedProtocols = RequestedProtocols;
2135 return TRUE;
2136}
2137
2138NEGO_STATE nego_get_state(const rdpNego* nego)
2139{
2140 if (!nego)
2141 return NEGO_STATE_FAIL;
2142
2143 return nego->state;
2144}
2145
2146BOOL nego_set_state(rdpNego* nego, NEGO_STATE state)
2147{
2148 WINPR_ASSERT(nego);
2149 nego->state = state;
2150 return TRUE;
2151}
2152
2153SEC_WINNT_AUTH_IDENTITY* nego_get_identity(rdpNego* nego)
2154{
2155 rdpNla* nla = nullptr;
2156 if (!nego)
2157 return nullptr;
2158
2159 nla = transport_get_nla(nego->transport);
2160 return nla_get_identity(nla);
2161}
2162
2163void nego_free_nla(rdpNego* nego)
2164{
2165 if (!nego || !nego->transport)
2166 return;
2167
2168 transport_set_nla(nego->transport, nullptr);
2169}
2170
2171const BYTE* nego_get_routing_token(const rdpNego* nego, DWORD* RoutingTokenLength)
2172{
2173 if (!nego)
2174 return nullptr;
2175 if (RoutingTokenLength)
2176 *RoutingTokenLength = nego->RoutingTokenLength;
2177 return nego->RoutingToken;
2178}
2179
2180const char* nego_protocol_to_str(UINT32 protocol, char* buffer, size_t size)
2181{
2182 const UINT32 mask = ~(PROTOCOL_SSL | PROTOCOL_HYBRID | PROTOCOL_RDSTLS | PROTOCOL_HYBRID_EX |
2183 PROTOCOL_RDSAAD | PROTOCOL_FAILED_NEGO);
2184 char str[48] = WINPR_C_ARRAY_INIT;
2185
2186 if (protocol & PROTOCOL_SSL)
2187 (void)winpr_str_append("SSL", str, sizeof(str), "|");
2188 if (protocol & PROTOCOL_HYBRID)
2189 (void)winpr_str_append("HYBRID", str, sizeof(str), "|");
2190 if (protocol & PROTOCOL_RDSTLS)
2191 (void)winpr_str_append("RDSTLS", str, sizeof(str), "|");
2192 if (protocol & PROTOCOL_HYBRID_EX)
2193 (void)winpr_str_append("HYBRID_EX", str, sizeof(str), "|");
2194 if (protocol & PROTOCOL_RDSAAD)
2195 (void)winpr_str_append("RDSAAD", str, sizeof(str), "|");
2196 if (protocol & PROTOCOL_FAILED_NEGO)
2197 (void)winpr_str_append("NEGO FAILED", str, sizeof(str), "|");
2198
2199 if (protocol == PROTOCOL_RDP)
2200 (void)winpr_str_append("RDP", str, sizeof(str), "");
2201 else if ((protocol & mask) != 0)
2202 (void)winpr_str_append("UNKNOWN", str, sizeof(str), "|");
2203
2204 (void)_snprintf(buffer, size, "[%s][0x%08" PRIx32 "]", str, protocol);
2205 return buffer;
2206}
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.