22#include <freerdp/config.h>
27#include <winpr/string.h>
28#include <freerdp/log.h>
29#include <freerdp/crypto/certificate.h>
30#include <freerdp/redirection.h>
31#include <freerdp/utils/string.h>
33#include "../crypto/certificate.h"
34#include "redirection.h"
37#define TAG FREERDP_TAG("core.redirection")
48 UINT32 PasswordLength;
50 BYTE* LoadBalanceInfo;
51 UINT32 LoadBalanceInfoLength;
52 char* TargetNetBiosName;
53 char* TargetNetAddress;
54 UINT32 TargetNetAddressesCount;
55 char** TargetNetAddresses;
56 UINT32 RedirectionGuidLength;
57 BYTE* RedirectionGuid;
59 rdpCertificate* TargetCertificate;
62static void redirection_free_array(
char*** what, UINT32* count)
69 for (UINT32 x = 0; x < *count; x++)
78static void redirection_free_string(
char** str)
85static void redirection_free_data(BYTE** str, UINT32* length)
94static BOOL redirection_copy_string(
char** dst,
const char* str)
96 redirection_free_string(dst);
101 return *dst !=
nullptr;
104static BOOL redirection_copy_data(BYTE** dst, UINT32* plen,
const BYTE* str,
size_t len)
106 redirection_free_data(dst, plen);
108 if (!str || (len == 0))
110 if (len > UINT32_MAX)
116 memcpy(*dst, str, len);
118 return *dst !=
nullptr;
121static BOOL redirection_copy_array(
char*** dst, UINT32* plen,
const char** str,
size_t len)
123 redirection_free_array(dst, plen);
125 if (len > UINT32_MAX)
127 if (!str || (len == 0))
130 *dst = (
char**)calloc(len,
sizeof(
char*));
135 for (
size_t x = 0; x < len; x++)
138 (*dst)[x] = _strdup(str[x]);
142 redirection_free_array(dst, plen);
147 return *dst !=
nullptr;
150static BOOL rdp_redirection_get_data(
wStream* s, UINT32* pLength,
const BYTE** pData)
152 WINPR_ASSERT(pLength);
155 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
158 Stream_Read_UINT32(s, *pLength);
160 if (!Stream_CheckAndLogRequiredLength(TAG, s, *pLength))
163 *pData = Stream_ConstPointer(s);
164 Stream_Seek(s, *pLength);
169static BOOL rdp_redirection_read_unicode_string(
wStream* s,
char** str,
size_t maxLength)
172 const BYTE* data =
nullptr;
174 if (!rdp_redirection_get_data(s, &length, &data))
177 if ((length % 2) || (length < 2) || (length > maxLength))
179 WLog_ERR(TAG,
"failure: invalid unicode string length: %" PRIu32
"", length);
183 WCHAR wstr[513] = WINPR_C_ARRAY_INIT;
184 WINPR_ASSERT(ARRAYSIZE(wstr) > maxLength);
185 memcpy(wstr, data, length);
187 if (wstr[length / 2 - 1])
189 WLog_ERR(TAG,
"failure: unterminated unicode string");
193 redirection_free_string(str);
194 *str = ConvertWCharNToUtf8Alloc(wstr, length /
sizeof(WCHAR),
nullptr);
197 WLog_ERR(TAG,
"failure: string conversion failed");
204static BOOL rdp_redirection_write_data(
wStream* s,
size_t length,
const void* data)
206 WINPR_ASSERT(data || (length == 0));
207 WINPR_ASSERT(length <= UINT32_MAX);
209 if (!Stream_EnsureRemainingCapacity(s, 4))
212 Stream_Write_UINT32(s, (UINT32)length);
214 if (!Stream_EnsureRemainingCapacity(s, length))
217 Stream_Write(s, data, length);
221static BOOL rdp_redirection_write_base64_wchar(WINPR_ATTR_UNUSED UINT32 flag,
wStream* s,
222 size_t length,
const void* data)
227 char* base64 = crypto_base64_encode_len(data, length, &olen);
231 size_t wbase64len = 0;
232 WCHAR* wbase64 = ConvertUtf8NToWCharAlloc(base64, olen, &wbase64len);
237 rc = rdp_redirection_write_data(s, wbase64len *
sizeof(WCHAR), wbase64);
242static BOOL rdp_redirection_read_base64_wchar(UINT32 flag,
wStream* s, UINT32* pLength,
246 char buffer[64] = WINPR_C_ARRAY_INIT;
247 const BYTE* ptr =
nullptr;
249 if (!rdp_redirection_get_data(s, pLength, &ptr))
251 const WCHAR* wchar = WINPR_PACKED_ALIGN_CAST(
const WCHAR*, ptr);
254 char* utf8 = ConvertWCharNToUtf8Alloc(wchar, *pLength /
sizeof(WCHAR), &utf8_len);
258 redirection_free_data(pData,
nullptr);
260 utf8_len = strnlen(utf8, utf8_len);
263 *pData = calloc(utf8_len,
sizeof(BYTE));
268 size_t rlen = utf8_len;
270 char* saveptr =
nullptr;
271 char* tok = strtok_s(utf8,
"\r\n", &saveptr);
274 const size_t len = strnlen(tok, rlen);
278 BYTE* bptr =
nullptr;
279 crypto_base64_decode(tok, len, &bptr, &bplen);
282 memcpy(&(*pData)[wpos], bptr, bplen);
286 tok = strtok_s(
nullptr,
"\r\n", &saveptr);
288 if (wpos > UINT32_MAX)
291 *pLength = (UINT32)wpos;
293 WLog_DBG(TAG,
"%s:", rdp_redirection_flags_to_string(flag, buffer,
sizeof(buffer)));
299 WLog_ERR(TAG,
"failed to read base64 data");
304static BOOL rdp_target_cert_get_element(
wStream* s, UINT32* pType, UINT32* pEncoding,
305 const BYTE** ptr,
size_t* pLength)
308 WINPR_ASSERT(pEncoding);
310 WINPR_ASSERT(pLength);
312 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
317 UINT32 elementSize = 0;
319 Stream_Read_UINT32(s, type);
320 Stream_Read_UINT32(s, encoding);
321 Stream_Read_UINT32(s, elementSize);
323 if (!Stream_CheckAndLogRequiredLength(TAG, s, elementSize))
326 *ptr = Stream_ConstPointer(s);
327 *pLength = elementSize;
328 Stream_Seek(s, elementSize);
331 *pEncoding = encoding;
335static BOOL rdp_target_cert_write_element(
wStream* s, UINT32 Type, UINT32 Encoding,
336 const BYTE* data,
size_t length)
338 WINPR_ASSERT(data || (length == 0));
339 WINPR_ASSERT(length <= UINT32_MAX);
341 if (!Stream_EnsureRemainingCapacity(s, 12))
344 Stream_Write_UINT32(s, Type);
345 Stream_Write_UINT32(s, Encoding);
346 Stream_Write_UINT32(s, (UINT32)length);
348 if (!Stream_EnsureRemainingCapacity(s, length))
351 Stream_Write(s, data, length);
355BOOL rdp_redirection_read_target_cert(rdpCertificate** ptargetCertificate,
const BYTE* data,
358 WINPR_ASSERT(ptargetCertificate);
360 wStream sbuffer = WINPR_C_ARRAY_INIT;
361 wStream* s = Stream_StaticConstInit(&sbuffer, data, length);
363 freerdp_certificate_free(*ptargetCertificate);
364 *ptargetCertificate =
nullptr;
367 const BYTE* ptr =
nullptr;
368 while (Stream_GetRemainingLength(s) > 0)
372 if (!rdp_target_cert_get_element(s, &type, &encoding, &ptr, &plength))
377 case CERT_cert_file_element:
378 if (encoding == ENCODING_TYPE_ASN1_DER)
380 if (*ptargetCertificate)
381 WLog_WARN(TAG,
"Duplicate TargetCertificate in data detected!");
384 *ptargetCertificate = freerdp_certificate_new_from_der(ptr, plength);
385 if (!*ptargetCertificate)
386 WLog_ERR(TAG,
"TargetCertificate parsing DER data failed");
392 "TargetCertificate data in unknown encoding %" PRIu32
" detected!",
398 "Unknown TargetCertificate field type %" PRIu32
", encoding %" PRIu32
399 " of length %" PRIuz,
400 type, encoding, plength);
405 return *ptargetCertificate !=
nullptr;
408static BOOL rdp_redirection_write_target_cert(
wStream* s,
const rdpRedirection* redirection)
411 WINPR_ASSERT(redirection);
413 const rdpCertificate* cert = redirection->TargetCertificate;
419 BYTE* der = freerdp_certificate_get_der(cert, &derlen);
420 if (!rdp_target_cert_write_element(s, CERT_cert_file_element, ENCODING_TYPE_ASN1_DER, der,
431static BOOL rdp_redireciton_write_target_cert_stream(
wStream* s,
const rdpRedirection* redirection)
434 wStream* serialized = Stream_New(
nullptr, 2048);
438 if (!rdp_redirection_write_target_cert(serialized, redirection))
441 rc = rdp_redirection_write_base64_wchar(
442 LB_TARGET_CERTIFICATE, s, Stream_GetPosition(serialized), Stream_Buffer(serialized));
445 Stream_Free(serialized, TRUE);
449static BOOL rdp_redirection_read_target_cert_stream(
wStream* s, rdpRedirection* redirection)
454 WINPR_ASSERT(redirection);
457 if (rdp_redirection_read_base64_wchar(LB_TARGET_CERTIFICATE, s, &length, &ptr))
458 rc = rdp_redirection_read_target_cert(&redirection->TargetCertificate, ptr, length);
463BOOL rdp_set_target_certificate(rdpSettings* settings,
const rdpCertificate* tcert)
465 rdpCertificate* cert = freerdp_certificate_clone(tcert);
471 char* pem = freerdp_certificate_get_pem(cert, &length);
472 if (pem && (length <= UINT32_MAX))
484int rdp_redirection_apply_settings(rdpRdp* rdp)
486 rdpSettings* settings =
nullptr;
487 rdpRedirection* redirection =
nullptr;
489 if (!rdp_reset_runtime_settings(rdp))
492 settings = rdp->settings;
493 WINPR_ASSERT(settings);
495 redirection = rdp->redirection;
496 WINPR_ASSERT(redirection);
498 settings->RedirectionFlags = redirection->flags;
499 settings->RedirectedSessionId = redirection->sessionID;
501 if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESS)
504 redirection->TargetNetAddress))
508 if (settings->RedirectionFlags & LB_USERNAME)
511 redirection->Username))
515 if (settings->RedirectionFlags & LB_DOMAIN)
521 if (settings->RedirectionFlags & LB_PASSWORD)
525 redirection->Password, redirection->PasswordLength))
529 if (settings->RedirectionFlags & LB_DONTSTOREUSERNAME)
534 if (settings->RedirectionFlags & LB_SMARTCARD_LOGON)
539 if (settings->RedirectionFlags & LB_NOREDIRECT)
544 if (settings->RedirectionFlags & LB_TARGET_FQDN)
547 redirection->TargetFQDN))
551 if (settings->RedirectionFlags & LB_TARGET_NETBIOS_NAME)
554 redirection->TargetNetBiosName))
558 if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESSES)
560 if (!freerdp_target_net_addresses_copy(settings, redirection->TargetNetAddresses,
561 redirection->TargetNetAddressesCount))
565 if (settings->RedirectionFlags & LB_CLIENT_TSV_URL)
569 redirection->TsvUrl, redirection->TsvUrlLength))
580 ConvertWCharNToUtf8Alloc(WINPR_PACKED_ALIGN_CAST(
const WCHAR*, redirection->TsvUrl),
581 redirection->TsvUrlLength /
sizeof(WCHAR), &tsvlen);
584 else if (tsvlen != lblen)
586 else if (memcmp(tsv, lb, lblen) != 0)
592 "[redirection] Expected TsvUrl '%s' [%" PRIuz
"], but got '%s' [%" PRIuz
594 lb, lblen, tsv, tsvlen);
603 if (settings->RedirectionFlags & LB_SERVER_TSV_CAPABLE)
608 if (settings->RedirectionFlags & LB_LOAD_BALANCE_INFO)
612 redirection->LoadBalanceInfo,
613 redirection->LoadBalanceInfoLength))
626 if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED)
631 if (settings->RedirectionFlags & LB_REDIRECTION_GUID)
634 redirection->RedirectionGuid,
635 redirection->RedirectionGuidLength))
639 if (settings->RedirectionFlags & LB_TARGET_CERTIFICATE)
641 if (!rdp_set_target_certificate(settings, redirection->TargetCertificate))
648static BOOL rdp_redirection_read_data(UINT32 flag,
wStream* s, UINT32* pLength, BYTE** pData)
650 char buffer[64] = WINPR_C_ARRAY_INIT;
651 const BYTE* ptr =
nullptr;
653 const char* msg = rdp_redirection_flags_to_string(flag, buffer,
sizeof(buffer));
655 if (!rdp_redirection_get_data(s, pLength, &ptr))
657 WLog_ERR(TAG,
"Reading %s failed", msg);
661 redirection_free_data(pData,
nullptr);
662 *pData = (BYTE*)malloc(*pLength);
666 WLog_ERR(TAG,
"Allocating %" PRIu32
" for %s failed", *pLength, msg);
669 memcpy(*pData, ptr, *pLength);
671 WLog_DBG(TAG,
"%s:", msg);
676static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp,
wStream* s)
678 char buffer[256] = WINPR_C_ARRAY_INIT;
681 rdpRedirection* redirection = rdp->redirection;
683 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
684 return STATE_RUN_FAILED;
686 Stream_Read_UINT16(s, flags);
687 if (flags != SEC_REDIRECTION_PKT)
689 char buffer1[1024] = WINPR_C_ARRAY_INIT;
690 char buffer2[1024] = WINPR_C_ARRAY_INIT;
691 WLog_ERR(TAG,
"received invalid flags=%s, expected %s",
692 rdp_security_flag_string(flags, buffer1,
sizeof(buffer1)),
693 rdp_security_flag_string(SEC_REDIRECTION_PKT, buffer2,
sizeof(buffer2)));
694 return STATE_RUN_FAILED;
696 Stream_Read_UINT16(s, length);
697 Stream_Read_UINT32(s, redirection->sessionID);
698 Stream_Read_UINT32(s, redirection->flags);
700 "flags: 0x%04" PRIX16
", length: %" PRIu16
", sessionID: 0x%08" PRIX32
701 ", redirFlags: %s [0x%08" PRIX32
"]",
702 flags, length, redirection->sessionID,
703 rdp_redirection_flags_to_string(redirection->flags, buffer,
sizeof(buffer)),
718 if (redirection->flags & LB_TARGET_NET_ADDRESS)
720 if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddress), 80) ||
721 (!utils_is_valid_ip(redirection->TargetNetAddress) &&
722 !winpr_str_is_valid_hostname(redirection->TargetNetAddress)))
724 WLog_ERR(TAG,
"TargetNetAddress %s invalid", redirection->TargetNetAddress);
725 return STATE_RUN_FAILED;
727 WLog_DBG(TAG,
"TargetNetAddress %s", redirection->TargetNetAddress);
730 if (redirection->flags & LB_LOAD_BALANCE_INFO)
738 if (!rdp_redirection_read_data(LB_LOAD_BALANCE_INFO, s, &redirection->LoadBalanceInfoLength,
739 &redirection->LoadBalanceInfo))
741 WLog_ERR(TAG,
"LoadBalanceInfo(%" PRIu32
") invalid",
742 redirection->LoadBalanceInfoLength);
743 return STATE_RUN_FAILED;
747 if (redirection->flags & LB_USERNAME)
749 if (!rdp_redirection_read_unicode_string(s, &(redirection->Username), 512) ||
750 winpr_str_has_newlines(redirection->Username))
752 WLog_ERR(TAG,
"Username: %s invalid", redirection->Username);
753 return STATE_RUN_FAILED;
755 WLog_DBG(TAG,
"Username: %s", redirection->Username);
758 if (redirection->flags & LB_DOMAIN)
760 if (!rdp_redirection_read_unicode_string(s, &(redirection->Domain), 52) ||
761 winpr_str_has_newlines(redirection->Domain))
763 WLog_ERR(TAG,
"Domain: %s invalid", redirection->Domain);
764 return STATE_RUN_FAILED;
766 WLog_DBG(TAG,
"Domain: %s", redirection->Domain);
769 if (redirection->flags & LB_PASSWORD)
792 if (!rdp_redirection_read_data(LB_PASSWORD, s, &redirection->PasswordLength,
793 &redirection->Password))
794 return STATE_RUN_FAILED;
800 if ((redirection->flags & LB_PASSWORD_IS_PK_ENCRYPTED) == 0)
802 const size_t charLen = redirection->PasswordLength /
sizeof(WCHAR);
803 if (redirection->PasswordLength > LB_PASSWORD_MAX_LENGTH)
805 WLog_ERR(TAG,
"LB_PASSWORD: %" PRIuz
" exceeds limit of %d", charLen,
806 LB_PASSWORD_MAX_LENGTH);
807 return STATE_RUN_FAILED;
811 if (_wcsnlen(WINPR_PACKED_ALIGN_CAST(
const WCHAR*, redirection->Password), charLen) ==
814 WLog_ERR(TAG,
"LB_PASSWORD: missing '\\0' termination");
815 return STATE_RUN_FAILED;
820 if (redirection->flags & LB_TARGET_FQDN)
822 if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetFQDN), 512) ||
823 !winpr_str_is_valid_hostname(redirection->TargetFQDN))
825 WLog_ERR(TAG,
"TargetFQDN: %s invalid", redirection->TargetFQDN);
826 return STATE_RUN_FAILED;
828 WLog_DBG(TAG,
"TargetFQDN: %s", redirection->TargetFQDN);
831 if (redirection->flags & LB_TARGET_NETBIOS_NAME)
833 if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetBiosName), 32) ||
834 !winpr_str_is_valid_hostname(redirection->TargetNetBiosName))
836 WLog_ERR(TAG,
"TargetNetBiosName: %s invalid", redirection->TargetNetBiosName);
837 return STATE_RUN_FAILED;
839 WLog_DBG(TAG,
"TargetNetBiosName: %s", redirection->TargetNetBiosName);
842 if (redirection->flags & LB_CLIENT_TSV_URL)
844 if (!rdp_redirection_read_data(LB_CLIENT_TSV_URL, s, &redirection->TsvUrlLength,
845 &redirection->TsvUrl))
847 WLog_ERR(TAG,
"Client TSV URL invalid");
848 return STATE_RUN_FAILED;
852 if (redirection->flags & LB_REDIRECTION_GUID)
854 if (!rdp_redirection_read_data(LB_REDIRECTION_GUID, s, &redirection->RedirectionGuidLength,
855 &redirection->RedirectionGuid))
857 WLog_ERR(TAG,
"Redirection GUID invalid");
858 return STATE_RUN_FAILED;
862 if (redirection->flags & LB_TARGET_CERTIFICATE)
864 if (!rdp_redirection_read_target_cert_stream(s, redirection))
866 WLog_ERR(TAG,
"TargetCertificate invalid");
867 return STATE_RUN_FAILED;
871 if (redirection->flags & LB_TARGET_NET_ADDRESSES)
873 UINT32 targetNetAddressesLength = 0;
874 UINT32 TargetNetAddressesCount = 0;
876 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
877 return STATE_RUN_FAILED;
879 Stream_Read_UINT32(s, targetNetAddressesLength);
880 Stream_Read_UINT32(s, TargetNetAddressesCount);
885 const size_t size = TargetNetAddressesCount *
sizeof(WCHAR);
886 if ((size > Stream_GetRemainingLength(s)) || (size > targetNetAddressesLength))
889 "Invalid RDP_SERVER_REDIRECTION_PACKET::TargetNetAddressLength %" PRIuz
890 ", sanity limit is %" PRIuz,
891 TargetNetAddressesCount *
sizeof(WCHAR), Stream_GetRemainingLength(s));
892 return STATE_RUN_FAILED;
895 redirection_free_array(&redirection->TargetNetAddresses,
896 &redirection->TargetNetAddressesCount);
897 if (TargetNetAddressesCount > 0)
899 redirection->TargetNetAddresses =
900 (
char**)calloc(TargetNetAddressesCount,
sizeof(
char*));
902 if (!redirection->TargetNetAddresses)
904 WLog_ERR(TAG,
"TargetNetAddresses %" PRIu32
" failed to allocate",
905 TargetNetAddressesCount);
906 return STATE_RUN_FAILED;
909 redirection->TargetNetAddressesCount = TargetNetAddressesCount;
911 WLog_DBG(TAG,
"TargetNetAddressesCount: %" PRIu32
"", TargetNetAddressesCount);
913 for (UINT32 i = 0; i < TargetNetAddressesCount; i++)
915 if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddresses[i]),
917 (!utils_is_valid_ip(redirection->TargetNetAddresses[i]) &&
918 !winpr_str_is_valid_hostname(redirection->TargetNetAddresses[i])))
920 WLog_ERR(TAG,
"TargetNetAddresses[%" PRIu32
"]: %s invalid", i,
921 redirection->TargetNetAddresses[i]);
922 return STATE_RUN_FAILED;
924 WLog_DBG(TAG,
"TargetNetAddresses[%" PRIu32
"]: %s", i,
925 redirection->TargetNetAddresses[i]);
929 if (Stream_GetRemainingLength(s) >= 8)
935 if (redirection->flags & LB_NOREDIRECT)
936 return STATE_RUN_SUCCESS;
938 return STATE_RUN_REDIRECT;
941state_run_t rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp,
wStream* s)
943 state_run_t status = STATE_RUN_SUCCESS;
945 if (!Stream_SafeSeek(s, 2))
946 return STATE_RUN_FAILED;
948 status = rdp_recv_server_redirection_pdu(rdp, s);
950 if (state_run_failed(status))
952 WLog_Print(rdp->log, WLOG_ERROR,
"redirection packet invalid, aborting");
956 if (Stream_GetRemainingLength(s) >= 1)
965rdpRedirection* redirection_new(
void)
967 rdpRedirection* redirection = (rdpRedirection*)calloc(1,
sizeof(rdpRedirection));
976void redirection_free(rdpRedirection* redirection)
980 redirection_free_data(&redirection->TsvUrl, &redirection->TsvUrlLength);
981 redirection_free_string(&redirection->Username);
982 redirection_free_string(&redirection->Domain);
983 redirection_free_string(&redirection->TargetFQDN);
984 redirection_free_string(&redirection->TargetNetBiosName);
985 redirection_free_string(&redirection->TargetNetAddress);
986 redirection_free_data(&redirection->LoadBalanceInfo, &redirection->LoadBalanceInfoLength);
987 redirection_free_data(&redirection->Password, &redirection->PasswordLength);
988 redirection_free_data(&redirection->RedirectionGuid, &redirection->RedirectionGuidLength);
989 freerdp_certificate_free(redirection->TargetCertificate);
990 redirection_free_array(&redirection->TargetNetAddresses,
991 &redirection->TargetNetAddressesCount);
997static SSIZE_T redir_write_string(WINPR_ATTR_UNUSED UINT32 flag,
wStream* s,
const char* str)
999 const SSIZE_T devNameWLen = ConvertUtf8ToWChar(str,
nullptr, 0);
1000 if (devNameWLen < 0)
1002 const size_t length = WINPR_ASSERTING_INT_CAST(
size_t, devNameWLen) + 1;
1003 const size_t slen = strlen(str);
1004 if (!Stream_EnsureRemainingCapacity(s, 4ull + length *
sizeof(WCHAR)))
1007 const size_t pos = Stream_GetPosition(s);
1008 Stream_Write_UINT32(s, (UINT32)length *
sizeof(WCHAR));
1009 if (Stream_Write_UTF16_String_From_UTF8(s, length, str, slen, TRUE) < 0)
1011 return (SSIZE_T)(Stream_GetPosition(s) - pos);
1014static BOOL redir_write_data(WINPR_ATTR_UNUSED UINT32 flag,
wStream* s, UINT32 length,
1017 if (!Stream_EnsureRemainingCapacity(s, 4ull + length))
1020 Stream_Write_UINT32(s, length);
1021 Stream_Write(s, data, length);
1025BOOL rdp_write_enhanced_security_redirection_packet(
wStream* s,
const rdpRedirection* redirection)
1030 WINPR_ASSERT(redirection);
1032 if (!Stream_EnsureRemainingCapacity(s, 14))
1035 Stream_Write_UINT16(s, 0);
1038 const size_t start = Stream_GetPosition(s);
1039 Stream_Write_UINT16(s, SEC_REDIRECTION_PKT);
1040 const size_t lengthOffset = Stream_GetPosition(s);
1041 Stream_Seek_UINT16(s);
1043 if (redirection->sessionID)
1044 Stream_Write_UINT32(s, redirection->sessionID);
1046 Stream_Write_UINT32(s, 0);
1048 Stream_Write_UINT32(s, redirection->flags);
1050 if (redirection->flags & LB_TARGET_NET_ADDRESS)
1052 if (redir_write_string(LB_TARGET_NET_ADDRESS, s, redirection->TargetNetAddress) < 0)
1056 if (redirection->flags & LB_LOAD_BALANCE_INFO)
1058 const UINT32 length = 13 + redirection->LoadBalanceInfoLength + 2;
1059 if (!Stream_EnsureRemainingCapacity(s, length))
1061 Stream_Write_UINT32(s, length);
1062 Stream_Write(s,
"Cookie: msts=", 13);
1063 Stream_Write(s, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength);
1064 Stream_Write_UINT8(s, 0x0d);
1065 Stream_Write_UINT8(s, 0x0a);
1068 if (redirection->flags & LB_USERNAME)
1070 if (redir_write_string(LB_USERNAME, s, redirection->Username) < 0)
1074 if (redirection->flags & LB_DOMAIN)
1076 if (redir_write_string(LB_DOMAIN, s, redirection->Domain) < 0)
1080 if (redirection->flags & LB_PASSWORD)
1083 if (!redir_write_data(LB_PASSWORD, s, redirection->PasswordLength,
1084 redirection->Password))
1088 if (redirection->flags & LB_TARGET_FQDN)
1090 if (redir_write_string(LB_TARGET_FQDN, s, redirection->TargetFQDN) < 0)
1094 if (redirection->flags & LB_TARGET_NETBIOS_NAME)
1096 if (redir_write_string(LB_TARGET_NETBIOS_NAME, s, redirection->TargetNetBiosName) < 0)
1100 if (redirection->flags & LB_CLIENT_TSV_URL)
1102 if (!redir_write_data(LB_CLIENT_TSV_URL, s, redirection->TsvUrlLength,
1103 redirection->TsvUrl))
1107 if (redirection->flags & LB_REDIRECTION_GUID)
1109 if (!redir_write_data(LB_REDIRECTION_GUID, s, redirection->RedirectionGuidLength,
1110 redirection->RedirectionGuid))
1114 if (redirection->flags & LB_TARGET_CERTIFICATE)
1116 if (!rdp_redireciton_write_target_cert_stream(s, redirection))
1120 if (redirection->flags & LB_TARGET_NET_ADDRESSES)
1122 UINT32 length =
sizeof(UINT32);
1124 if (!Stream_EnsureRemainingCapacity(s, 2ull *
sizeof(UINT32)))
1127 const size_t lstart = Stream_GetPosition(s);
1128 Stream_Seek_UINT32(s);
1129 Stream_Write_UINT32(s, redirection->TargetNetAddressesCount);
1130 for (UINT32 i = 0; i < redirection->TargetNetAddressesCount; i++)
1132 const SSIZE_T rcc = redir_write_string(LB_TARGET_NET_ADDRESSES, s,
1133 redirection->TargetNetAddresses[i]);
1136 length += (UINT32)rcc;
1140 const size_t lend = Stream_GetPosition(s);
1141 if (!Stream_SetPosition(s, lstart))
1143 Stream_Write_UINT32(s, length);
1144 if (!Stream_SetPosition(s, lend))
1149 if (!Stream_EnsureRemainingCapacity(s, 8))
1154 const size_t end = Stream_GetPosition(s);
1155 if (!Stream_SetPosition(s, lengthOffset))
1157 Stream_Write_UINT16(s, (UINT16)(end - start));
1158 if (!Stream_SetPosition(s, end))
1168BOOL redirection_settings_are_valid(rdpRedirection* redirection, UINT32* pFlags)
1172 WINPR_ASSERT(redirection);
1174 if (redirection->flags & LB_CLIENT_TSV_URL)
1176 if (!redirection->TsvUrl || (redirection->TsvUrlLength == 0))
1177 flags |= LB_CLIENT_TSV_URL;
1180 if (redirection->flags & LB_SERVER_TSV_CAPABLE)
1182 if ((redirection->flags & LB_CLIENT_TSV_URL) == 0)
1183 flags |= LB_SERVER_TSV_CAPABLE;
1186 if (redirection->flags & LB_USERNAME)
1188 if (utils_str_is_empty(redirection->Username))
1189 flags |= LB_USERNAME;
1192 if (redirection->flags & LB_DOMAIN)
1194 if (utils_str_is_empty(redirection->Domain))
1198 if (redirection->flags & LB_PASSWORD)
1200 if (!redirection->Password || (redirection->PasswordLength == 0))
1201 flags |= LB_PASSWORD;
1204 if (redirection->flags & LB_TARGET_FQDN)
1206 if (utils_str_is_empty(redirection->TargetFQDN))
1207 flags |= LB_TARGET_FQDN;
1210 if (redirection->flags & LB_LOAD_BALANCE_INFO)
1212 if (!redirection->LoadBalanceInfo || (redirection->LoadBalanceInfoLength == 0))
1213 flags |= LB_LOAD_BALANCE_INFO;
1216 if (redirection->flags & LB_TARGET_NETBIOS_NAME)
1218 if (utils_str_is_empty(redirection->TargetNetBiosName))
1219 flags |= LB_TARGET_NETBIOS_NAME;
1222 if (redirection->flags & LB_TARGET_NET_ADDRESS)
1224 if (utils_str_is_empty(redirection->TargetNetAddress))
1225 flags |= LB_TARGET_NET_ADDRESS;
1228 if (redirection->flags & LB_TARGET_NET_ADDRESSES)
1230 if (!redirection->TargetNetAddresses || (redirection->TargetNetAddressesCount == 0))
1231 flags |= LB_TARGET_NET_ADDRESSES;
1234 for (UINT32 x = 0; x < redirection->TargetNetAddressesCount; x++)
1236 if (!redirection->TargetNetAddresses[x])
1237 flags |= LB_TARGET_NET_ADDRESSES;
1242 if (redirection->flags & LB_REDIRECTION_GUID)
1244 if (!redirection->RedirectionGuid || (redirection->RedirectionGuidLength == 0))
1245 flags |= LB_REDIRECTION_GUID;
1248 if (redirection->flags & LB_TARGET_CERTIFICATE)
1250 if (!redirection->TargetCertificate)
1251 flags |= LB_TARGET_CERTIFICATE;
1259BOOL redirection_set_flags(rdpRedirection* redirection, UINT32 flags)
1261 WINPR_ASSERT(redirection);
1262 redirection->flags = flags;
1266BOOL redirection_set_session_id(rdpRedirection* redirection, UINT32 session_id)
1268 WINPR_ASSERT(redirection);
1269 redirection->sessionID = session_id;
1273static BOOL redirection_unsupported(
const char* fkt, UINT32 flag, UINT32 mask)
1275 char buffer[1024] = WINPR_C_ARRAY_INIT;
1276 char buffer2[1024] = WINPR_C_ARRAY_INIT;
1277 WLog_WARN(TAG,
"[%s] supported flags are {%s}, have {%s}", fkt,
1278 rdp_redirection_flags_to_string(mask, buffer,
sizeof(buffer)),
1279 rdp_redirection_flags_to_string(flag, buffer2,
sizeof(buffer2)));
1283BOOL redirection_set_byte_option(rdpRedirection* redirection, UINT32 flag,
const BYTE* data,
1286 WINPR_ASSERT(redirection);
1289 case LB_CLIENT_TSV_URL:
1290 return redirection_copy_data(&redirection->TsvUrl, &redirection->TsvUrlLength, data,
1293 return redirection_copy_data(&redirection->Password, &redirection->PasswordLength, data,
1295 case LB_LOAD_BALANCE_INFO:
1296 return redirection_copy_data(&redirection->LoadBalanceInfo,
1297 &redirection->LoadBalanceInfoLength, data, length);
1298 case LB_REDIRECTION_GUID:
1299 return redirection_copy_data(&redirection->RedirectionGuid,
1300 &redirection->RedirectionGuidLength, data, length);
1301 case LB_TARGET_CERTIFICATE:
1302 return rdp_redirection_read_target_cert(&redirection->TargetCertificate, data, length);
1304 return redirection_unsupported(__func__, flag,
1305 LB_CLIENT_TSV_URL | LB_PASSWORD | LB_LOAD_BALANCE_INFO |
1306 LB_REDIRECTION_GUID | LB_TARGET_CERTIFICATE);
1310BOOL redirection_set_string_option(rdpRedirection* redirection, UINT32 flag,
const char* str)
1312 WINPR_ASSERT(redirection);
1316 return redirection_copy_string(&redirection->Username, str);
1318 return redirection_copy_string(&redirection->Domain, str);
1319 case LB_TARGET_FQDN:
1320 return redirection_copy_string(&redirection->TargetFQDN, str);
1321 case LB_TARGET_NETBIOS_NAME:
1322 return redirection_copy_string(&redirection->TargetNetBiosName, str);
1323 case LB_TARGET_NET_ADDRESS:
1324 return redirection_copy_string(&redirection->TargetNetAddress, str);
1326 return redirection_unsupported(__func__, flag,
1327 LB_USERNAME | LB_DOMAIN | LB_TARGET_FQDN |
1328 LB_TARGET_NETBIOS_NAME | LB_TARGET_NET_ADDRESS);
1332BOOL redirection_set_array_option(rdpRedirection* redirection, UINT32 flag,
const char** str,
1335 WINPR_ASSERT(redirection);
1338 case LB_TARGET_NET_ADDRESSES:
1339 return redirection_copy_array(&redirection->TargetNetAddresses,
1340 &redirection->TargetNetAddressesCount, str, count);
1342 return redirection_unsupported(__func__, flag, LB_TARGET_NET_ADDRESSES);
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_pointer(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *val)
Set a pointer to value val.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string_len(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val, size_t len)
Sets a string settings value. The val is copied.
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 BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
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_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.