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