22#include <freerdp/config.h>
27#include <winpr/assert.h>
29#include <freerdp/crypto/crypto.h>
30#include <freerdp/log.h>
31#include <freerdp/session.h>
38#define TAG FREERDP_TAG("core.info")
40#define logonInfoV2Size (2u + 4u + 4u + 4u + 4u)
41#define logonInfoV2ReservedSize 558u
42#define logonInfoV2TotalSize (logonInfoV2Size + logonInfoV2ReservedSize)
44static const char* INFO_TYPE_LOGON_STRINGS[4] = {
"Logon Info V1",
"Logon Info V2",
45 "Logon Plain Notify",
"Logon Extended Info" };
48#define MAX_LABEL_LENGTH 40
55static const struct info_flags_t info_flags[] = {
56 { INFO_MOUSE,
"INFO_MOUSE" },
57 { INFO_DISABLECTRLALTDEL,
"INFO_DISABLECTRLALTDEL" },
58 { INFO_AUTOLOGON,
"INFO_AUTOLOGON" },
59 { INFO_UNICODE,
"INFO_UNICODE" },
60 { INFO_MAXIMIZESHELL,
"INFO_MAXIMIZESHELL" },
61 { INFO_LOGONNOTIFY,
"INFO_LOGONNOTIFY" },
62 { INFO_COMPRESSION,
"INFO_COMPRESSION" },
63 { INFO_ENABLEWINDOWSKEY,
"INFO_ENABLEWINDOWSKEY" },
64 { INFO_REMOTECONSOLEAUDIO,
"INFO_REMOTECONSOLEAUDIO" },
65 { INFO_FORCE_ENCRYPTED_CS_PDU,
"INFO_FORCE_ENCRYPTED_CS_PDU" },
66 { INFO_RAIL,
"INFO_RAIL" },
67 { INFO_LOGONERRORS,
"INFO_LOGONERRORS" },
68 { INFO_MOUSE_HAS_WHEEL,
"INFO_MOUSE_HAS_WHEEL" },
69 { INFO_PASSWORD_IS_SC_PIN,
"INFO_PASSWORD_IS_SC_PIN" },
70 { INFO_NOAUDIOPLAYBACK,
"INFO_NOAUDIOPLAYBACK" },
71 { INFO_USING_SAVED_CREDS,
"INFO_USING_SAVED_CREDS" },
72 { INFO_AUDIOCAPTURE,
"INFO_AUDIOCAPTURE" },
73 { INFO_VIDEO_DISABLE,
"INFO_VIDEO_DISABLE" },
74 { INFO_HIDEF_RAIL_SUPPORTED,
"INFO_HIDEF_RAIL_SUPPORTED" },
77static BOOL rdp_read_info_null_string(rdpSettings* settings, FreeRDP_Settings_Keys_String
id,
78 const char* what, UINT32 flags,
wStream* s,
size_t cbLen,
81 const BOOL unicode = (flags & INFO_UNICODE) != 0;
86 if (!Stream_CheckAndLogRequiredLength(TAG, s, (
size_t)(cbLen)))
91 if ((cbLen > max) || (unicode && ((cbLen % 2) != 0)))
93 WLog_ERR(TAG,
"protocol error: %s has invalid value: %" PRIuz
"", what, cbLen);
99 const WCHAR* domain = Stream_PointerAs(s, WCHAR);
101 cbLen /
sizeof(WCHAR)))
103 WLog_ERR(TAG,
"protocol error: no data to read for %s [expected %" PRIuz
"]", what,
110 const char* domain = Stream_ConstPointer(s);
115 Stream_Seek(s, cbLen);
120static char* rdp_info_package_flags_description(UINT32 flags)
122 char* result =
nullptr;
123 size_t maximum_size = 1 + MAX_LABEL_LENGTH * ARRAYSIZE(info_flags);
125 result = calloc(maximum_size,
sizeof(
char));
130 for (
size_t i = 0; i < ARRAYSIZE(info_flags); i++)
132 const struct info_flags_t* cur = &info_flags[i];
133 if (cur->flag & flags)
135 winpr_str_append(cur->label, result, maximum_size,
"|");
142static BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp)
144 BYTE ClientRandom[CLIENT_RANDOM_LENGTH] = WINPR_C_ARRAY_INIT;
145 BYTE AutoReconnectRandom[32] = WINPR_C_ARRAY_INIT;
150 rdpSettings* settings = rdp->settings;
151 WINPR_ASSERT(settings);
153 serverCookie = settings->ServerAutoReconnectCookie;
154 clientCookie = settings->ClientAutoReconnectCookie;
155 clientCookie->cbLen = 28;
156 clientCookie->version = serverCookie->version;
157 clientCookie->logonId = serverCookie->logonId;
158 ZeroMemory(clientCookie->securityVerifier,
sizeof(clientCookie->securityVerifier));
159 CopyMemory(AutoReconnectRandom, serverCookie->arcRandomBits,
160 sizeof(serverCookie->arcRandomBits));
162 if (settings->SelectedProtocol == PROTOCOL_RDP)
163 CopyMemory(ClientRandom, settings->ClientRandom, settings->ClientRandomLength);
167 if (!winpr_HMAC(WINPR_MD_MD5, AutoReconnectRandom, 16, ClientRandom,
sizeof(ClientRandom),
168 clientCookie->securityVerifier,
sizeof(clientCookie->securityVerifier)))
179static BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp,
wStream* s, logon_info_ex* info)
183 rdpSettings* settings = rdp->settings;
184 autoReconnectCookie = settings->ServerAutoReconnectCookie;
186 if (!Stream_CheckAndLogRequiredLength(TAG, s, 28))
189 Stream_Read_UINT32(s, autoReconnectCookie->cbLen);
191 if (autoReconnectCookie->cbLen != 28)
193 WLog_ERR(TAG,
"ServerAutoReconnectCookie.cbLen != 28");
197 Stream_Read_UINT32(s, autoReconnectCookie->version);
198 Stream_Read_UINT32(s, autoReconnectCookie->logonId);
199 Stream_Read(s, autoReconnectCookie->arcRandomBits, 16);
200 p = autoReconnectCookie->arcRandomBits;
202 "ServerAutoReconnectCookie: Version: %" PRIu32
" LogonId: %" PRIu32
203 " SecurityVerifier: "
204 "%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
206 "%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
208 autoReconnectCookie->version, autoReconnectCookie->logonId, p[0], p[1], p[2], p[3],
209 p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
210 info->LogonId = autoReconnectCookie->logonId;
211 CopyMemory(info->ArcRandomBits, p, 16);
213 if ((settings->PrintReconnectCookie))
215 char* base64 =
nullptr;
217 WLog_INFO(TAG,
"Reconnect-cookie: %s", base64);
229static BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp,
wStream* s)
232 rdpSettings* settings = rdp->settings;
233 autoReconnectCookie = settings->ClientAutoReconnectCookie;
235 if (!Stream_CheckAndLogRequiredLength(TAG, s, 28))
238 Stream_Read_UINT32(s, autoReconnectCookie->cbLen);
239 Stream_Read_UINT32(s, autoReconnectCookie->version);
240 Stream_Read_UINT32(s, autoReconnectCookie->logonId);
241 Stream_Read(s, autoReconnectCookie->securityVerifier, 16);
250static BOOL rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp,
wStream* s)
254 rdpSettings* settings =
nullptr;
258 settings = rdp->settings;
259 WINPR_ASSERT(settings);
261 autoReconnectCookie = settings->ClientAutoReconnectCookie;
262 WINPR_ASSERT(autoReconnectCookie);
264 p = autoReconnectCookie->securityVerifier;
268 "ClientAutoReconnectCookie: Version: %" PRIu32
" LogonId: %" PRIu32
" ArcRandomBits: "
269 "%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
271 "%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
"%02" PRIX8
273 autoReconnectCookie->version, autoReconnectCookie->logonId, p[0], p[1], p[2], p[3],
274 p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
275 if (!Stream_EnsureRemainingCapacity(s, 12ull + 16ull))
277 Stream_Write_UINT32(s, autoReconnectCookie->cbLen);
278 Stream_Write_UINT32(s, autoReconnectCookie->version);
279 Stream_Write_UINT32(s, autoReconnectCookie->logonId);
280 Stream_Write(s, autoReconnectCookie->securityVerifier, 16);
289static size_t rdp_get_client_address_max_size(
const rdpRdp* rdp)
292 rdpSettings* settings =
nullptr;
296 settings = rdp->settings;
297 WINPR_ASSERT(settings);
300 if (version < RDP_VERSION_10_0)
310static BOOL rdp_read_extended_info_packet(rdpRdp* rdp,
wStream* s)
312 UINT16 clientAddressFamily = 0;
313 UINT16 cbClientAddress = 0;
314 UINT16 cbClientDir = 0;
315 UINT16 cbAutoReconnectLen = 0;
319 rdpSettings* settings = rdp->settings;
320 WINPR_ASSERT(settings);
322 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
325 Stream_Read_UINT16(s, clientAddressFamily);
326 Stream_Read_UINT16(s, cbClientAddress);
328 settings->IPv6Enabled = ((clientAddressFamily == ADDRESS_FAMILY_INET6));
330 if (!rdp_read_info_null_string(settings, FreeRDP_ClientAddress,
"cbClientAddress", INFO_UNICODE,
331 s, cbClientAddress, rdp_get_client_address_max_size(rdp)))
334 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
337 Stream_Read_UINT16(s, cbClientDir);
347 if (!rdp_read_info_null_string(settings, FreeRDP_ClientDir,
"cbClientDir", INFO_UNICODE, s,
357 if (Stream_GetRemainingLength(s) == 0)
360 if (!rdp_read_client_time_zone(s, settings))
364 if (Stream_GetRemainingLength(s) == 0)
366 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
369 Stream_Read_UINT32(s, settings->ClientSessionId);
372 if (Stream_GetRemainingLength(s) == 0)
375 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
378 Stream_Read_UINT32(s, settings->PerformanceFlags);
379 freerdp_performance_flags_split(settings);
382 if (Stream_GetRemainingLength(s) == 0)
385 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
388 Stream_Read_UINT16(s, cbAutoReconnectLen);
392 if (cbAutoReconnectLen > 0)
394 if (!rdp_read_client_auto_reconnect_cookie(rdp, s))
399 if (Stream_GetRemainingLength(s) == 0)
402 if (!Stream_SafeSeek(s, 2))
405 if (Stream_GetRemainingLength(s) == 0)
408 if (!Stream_SafeSeek(s, 2))
411 if (Stream_GetRemainingLength(s) == 0)
414 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
419 UINT16 cbDynamicDSTTimeZoneKeyName = 0;
421 Stream_Read_UINT16(s, cbDynamicDSTTimeZoneKeyName);
423 if (!rdp_read_info_null_string(settings, FreeRDP_DynamicDSTTimeZoneKeyName,
424 "cbDynamicDSTTimeZoneKeyName", INFO_UNICODE, s,
425 cbDynamicDSTTimeZoneKeyName, 254))
428 if (Stream_GetRemainingLength(s) == 0)
431 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
433 UINT16 DynamicDaylightTimeDisabled = 0;
434 Stream_Read_UINT16(s, DynamicDaylightTimeDisabled);
435 if (DynamicDaylightTimeDisabled > 1)
438 "[MS-RDPBCGR] 2.2.1.11.1.1.1 Extended Info Packet "
439 "(TS_EXTENDED_INFO_PACKET)::dynamicDaylightTimeDisabled value %d"
440 " not allowed in [0,1]",
441 settings->DynamicDaylightTimeDisabled);
445 DynamicDaylightTimeDisabled != 0))
447 DEBUG_TIMEZONE(
"DynamicTimeZone=%s [%s]",
463static BOOL rdp_write_extended_info_packet(rdpRdp* rdp,
wStream* s)
466 size_t cbClientAddress = 0;
467 const size_t cbClientAddressMax = rdp_get_client_address_max_size(rdp);
468 WCHAR* clientDir =
nullptr;
469 size_t cbClientDir = 0;
470 const size_t cbClientDirMax = 512;
471 UINT16 cbAutoReconnectCookie = 0;
475 rdpSettings* settings = rdp->settings;
476 WINPR_ASSERT(settings);
478 UINT16 clientAddressFamily = ADDRESS_FAMILY_INET;
479 if (settings->ConnectChildSession)
480 clientAddressFamily = 0x0000;
481 else if (settings->IPv6Enabled)
482 clientAddressFamily = ADDRESS_FAMILY_INET6;
484 WCHAR* clientAddress = ConvertUtf8ToWCharAlloc(settings->ClientAddress, &cbClientAddress);
486 if (cbClientAddress > (UINT16_MAX /
sizeof(WCHAR)))
488 WLog_ERR(TAG,
"cbClientAddress > UINT16_MAX");
492 if (cbClientAddress > 0)
494 cbClientAddress = (cbClientAddress + 1) *
sizeof(WCHAR);
495 if (cbClientAddress > cbClientAddressMax)
498 "the client address %s [%" PRIuz
"] exceeds the limit of %" PRIuz
500 settings->ClientAddress, cbClientAddress, cbClientAddressMax);
502 clientAddress[(cbClientAddressMax /
sizeof(WCHAR)) - 1] =
'\0';
503 cbClientAddress = cbClientAddressMax;
507 clientDir = ConvertUtf8ToWCharAlloc(settings->ClientDir, &cbClientDir);
508 if (cbClientDir > (UINT16_MAX /
sizeof(WCHAR)))
510 WLog_ERR(TAG,
"cbClientDir > UINT16_MAX");
516 cbClientDir = (cbClientDir + 1) *
sizeof(WCHAR);
517 if (cbClientDir > cbClientDirMax)
520 "the client dir %s [%" PRIuz
"] exceeds the limit of %" PRIuz
", truncating.",
521 settings->ClientDir, cbClientDir, cbClientDirMax);
523 clientDir[(cbClientDirMax /
sizeof(WCHAR)) - 1] =
'\0';
524 cbClientDir = cbClientDirMax;
528 if (settings->ServerAutoReconnectCookie->cbLen > UINT16_MAX)
530 WLog_ERR(TAG,
"ServerAutoreconnectCookie::cbLen > UINT16_MAX");
534 cbAutoReconnectCookie = (UINT16)settings->ServerAutoReconnectCookie->cbLen;
536 if (!Stream_EnsureRemainingCapacity(s, 4ull + cbClientAddress + 2ull + cbClientDir))
539 Stream_Write_UINT16(s, clientAddressFamily);
540 Stream_Write_UINT16(s, (UINT16)cbClientAddress);
542 Stream_Write(s, clientAddress, cbClientAddress);
544 Stream_Write_UINT16(s, (UINT16)cbClientDir);
546 Stream_Write(s, clientDir, cbClientDir);
548 if (!rdp_write_client_time_zone(s, settings))
551 if (!Stream_EnsureRemainingCapacity(s, 10ull))
555 Stream_Write_UINT32(s, settings->ClientSessionId);
556 freerdp_performance_flags_make(settings);
557 Stream_Write_UINT32(s, settings->PerformanceFlags);
558 Stream_Write_UINT16(s, cbAutoReconnectCookie);
560 if (cbAutoReconnectCookie > 0)
562 if (!rdp_compute_client_auto_reconnect_cookie(rdp))
564 if (!rdp_write_client_auto_reconnect_cookie(rdp, s))
570 if (!Stream_EnsureRemainingCapacity(s, 8 + 254 *
sizeof(WCHAR)))
573 Stream_Write_UINT16(s, 0);
574 Stream_Write_UINT16(s, 0);
581 rstrlen = strnlen(tz, 254);
582 const SSIZE_T wlen = ConvertUtf8NToWChar(tz, rstrlen,
nullptr, 0);
585 rlen = WINPR_ASSERTING_INT_CAST(
size_t, wlen);
587 Stream_Write_UINT16(s, (UINT16)rlen *
sizeof(WCHAR));
588 if (Stream_Write_UTF16_String_From_UTF8(s, rlen, tz, rstrlen, FALSE) < 0)
590 Stream_Write_UINT16(s, settings->DynamicDaylightTimeDisabled ? 0x01 : 0x00);
600static BOOL rdp_read_info_string(rdpSettings* settings, FreeRDP_Settings_Keys_String
id,
601 UINT32 flags,
wStream* s,
size_t cbLenNonNull,
size_t max)
610 const BOOL unicode = (flags & INFO_UNICODE) != 0;
611 const size_t nullSize = unicode ?
sizeof(WCHAR) : sizeof(CHAR);
616 if (!Stream_CheckAndLogRequiredLength(TAG, s, (
size_t)(cbLenNonNull + nullSize)))
619 if (cbLenNonNull > 0)
625 if ((cbLenNonNull % 2) || (cbLenNonNull > (max - nullSize)))
627 WLog_ERR(TAG,
"protocol error: invalid value: %" PRIuz
"", cbLenNonNull);
633 const WCHAR* domain = Stream_PointerAs(s, WCHAR);
635 cbLenNonNull /
sizeof(WCHAR)))
640 const char* domain = Stream_PointerAs(s,
char);
646 Stream_Seek(s, cbLenNonNull);
648 terminator.w = L
'\0';
649 Stream_Read(s, terminator.b, nullSize);
651 if (terminator.w != L
'\0')
653 WLog_ERR(TAG,
"protocol error: Domain must be null terminated");
655 WLog_ERR(TAG,
"freerdp_settings_set_string(settings, id=%d, nullptr) failed",
id);
668static BOOL rdp_read_info_packet(rdpRdp* rdp,
wStream* s, UINT16 tpktlength)
670 BOOL smallsize = FALSE;
673 UINT16 cbUserName = 0;
674 UINT16 cbPassword = 0;
675 UINT16 cbAlternateShell = 0;
676 UINT16 cbWorkingDir = 0;
677 UINT32 CompressionLevel = 0;
678 rdpSettings* settings = rdp->settings;
680 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 18))
683 Stream_Read_UINT32(s, settings->KeyboardCodePage);
684 Stream_Read_UINT32(s, flags);
685 settings->AudioCapture = ((flags & INFO_AUDIOCAPTURE) != 0);
686 settings->AudioPlayback = (!(flags & INFO_NOAUDIOPLAYBACK));
687 settings->AutoLogonEnabled = ((flags & INFO_AUTOLOGON) != 0);
688 settings->RemoteApplicationMode = ((flags & INFO_RAIL) != 0);
689 settings->HiDefRemoteApp = ((flags & INFO_HIDEF_RAIL_SUPPORTED) != 0);
690 settings->RemoteConsoleAudio = ((flags & INFO_REMOTECONSOLEAUDIO) != 0);
691 settings->CompressionEnabled = ((flags & INFO_COMPRESSION) != 0);
692 settings->LogonNotify = ((flags & INFO_LOGONNOTIFY) != 0);
693 settings->MouseHasWheel = ((flags & INFO_MOUSE_HAS_WHEEL) != 0);
694 settings->DisableCtrlAltDel = ((flags & INFO_DISABLECTRLALTDEL) != 0);
695 settings->ForceEncryptedCsPdu = ((flags & INFO_FORCE_ENCRYPTED_CS_PDU) != 0);
696 settings->PasswordIsSmartcardPin = ((flags & INFO_PASSWORD_IS_SC_PIN) != 0);
698 if (flags & INFO_COMPRESSION)
700 CompressionLevel = ((flags & 0x00001E00) >> 9);
701 settings->CompressionLevel = CompressionLevel;
705 settings->CompressionLevel = 0;
709 if (settings->RdpVersion < RDP_VERSION_5_PLUS)
712 Stream_Read_UINT16(s, cbDomain);
713 Stream_Read_UINT16(s, cbUserName);
714 Stream_Read_UINT16(s, cbPassword);
715 Stream_Read_UINT16(s, cbAlternateShell);
716 Stream_Read_UINT16(s, cbWorkingDir);
718 if (!rdp_read_info_string(settings, FreeRDP_Domain, flags, s, cbDomain, smallsize ? 52 : 512))
721 if (!rdp_read_info_string(settings, FreeRDP_Username, flags, s, cbUserName,
722 smallsize ? 44 : 512))
725 if (!rdp_read_info_string(settings, FreeRDP_Password, flags, s, cbPassword,
726 smallsize ? 32 : 512))
729 if (!rdp_read_info_string(settings, FreeRDP_AlternateShell, flags, s, cbAlternateShell, 512))
732 if (!rdp_read_info_string(settings, FreeRDP_ShellWorkingDirectory, flags, s, cbWorkingDir, 512))
735 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
737 if (!rdp_read_extended_info_packet(rdp, s))
741 const size_t xrem = Stream_GetRemainingLength(s);
742 if (!tpkt_ensure_stream_consumed(rdp->log, s, tpktlength))
743 Stream_Seek(s, xrem);
752static BOOL rdp_write_info_packet(rdpRdp* rdp,
wStream* s)
756 WCHAR* domainW =
nullptr;
758 WCHAR* userNameW =
nullptr;
759 size_t cbUserName = 0;
760 WCHAR* passwordW =
nullptr;
761 size_t cbPassword = 0;
762 WCHAR* alternateShellW =
nullptr;
763 size_t cbAlternateShell = 0;
764 WCHAR* workingDirW =
nullptr;
765 size_t cbWorkingDir = 0;
766 BOOL usedPasswordCookie = FALSE;
767 rdpSettings* settings =
nullptr;
770 settings = rdp->settings;
771 WINPR_ASSERT(settings);
773 flags = INFO_MOUSE | INFO_UNICODE | INFO_LOGONERRORS | INFO_MAXIMIZESHELL |
774 INFO_ENABLEWINDOWSKEY | INFO_DISABLECTRLALTDEL | INFO_MOUSE_HAS_WHEEL |
775 INFO_FORCE_ENCRYPTED_CS_PDU;
777 if (settings->SmartcardLogon)
779 flags |= INFO_AUTOLOGON;
780 flags |= INFO_PASSWORD_IS_SC_PIN;
783 if (settings->AudioCapture)
784 flags |= INFO_AUDIOCAPTURE;
786 if (!settings->AudioPlayback)
787 flags |= INFO_NOAUDIOPLAYBACK;
789 if (settings->VideoDisable)
790 flags |= INFO_VIDEO_DISABLE;
792 if (settings->AutoLogonEnabled)
793 flags |= INFO_AUTOLOGON;
795 if (settings->RemoteApplicationMode)
797 if (settings->HiDefRemoteApp)
799 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
800 flags |= INFO_HIDEF_RAIL_SUPPORTED;
806 if (settings->RemoteConsoleAudio)
807 flags |= INFO_REMOTECONSOLEAUDIO;
809 if (settings->CompressionEnabled)
811 flags |= INFO_COMPRESSION;
812 flags |= ((settings->CompressionLevel << 9) & 0x00001E00);
815 if (settings->LogonNotify)
816 flags |= INFO_LOGONNOTIFY;
818 if (settings->PasswordIsSmartcardPin)
819 flags |= INFO_PASSWORD_IS_SC_PIN;
822 char* flags_description = rdp_info_package_flags_description(flags);
824 if (flags_description)
826 WLog_DBG(TAG,
"Client Info Packet Flags = %s", flags_description);
827 free(flags_description);
832 if (cbDomain > UINT16_MAX /
sizeof(WCHAR))
834 WLog_ERR(TAG,
"cbDomain > UINT16_MAX");
837 cbDomain *=
sizeof(WCHAR);
841 if (cbUserName > UINT16_MAX /
sizeof(WCHAR))
843 WLog_ERR(TAG,
"cbUserName > UINT16_MAX");
846 cbUserName *=
sizeof(WCHAR);
849 const char* pin =
"*";
850 if (!settings->RemoteAssistanceMode)
853 if (((flags & INFO_PASSWORD_IS_SC_PIN) == 0) && settings->RedirectionPassword &&
854 (settings->RedirectionPasswordLength > 0))
862 if (settings->RedirectionPasswordLength > UINT16_MAX)
864 WLog_ERR(TAG,
"RedirectionPasswordLength > UINT16_MAX");
867 usedPasswordCookie = TRUE;
869 ptrconv.bp = settings->RedirectionPassword;
870 passwordW = ptrconv.wp;
871 cbPassword = (UINT16)settings->RedirectionPasswordLength;
877 if (!usedPasswordCookie && pin)
879 passwordW = ConvertUtf8ToWCharAlloc(pin, &cbPassword);
880 if (cbPassword > UINT16_MAX /
sizeof(WCHAR))
882 WLog_ERR(TAG,
"cbPassword > UINT16_MAX");
885 cbPassword = (UINT16)cbPassword *
sizeof(WCHAR);
890 const char* altShell =
nullptr;
891 if (!settings->RemoteAssistanceMode)
893 else if (settings->RemoteAssistancePassStub)
898 if (altShell && strlen(altShell) > 0)
900 alternateShellW = ConvertUtf8ToWCharAlloc(altShell, &cbAlternateShell);
901 if (!alternateShellW)
903 WLog_ERR(TAG,
"alternateShellW == nullptr");
906 if (cbAlternateShell > (UINT16_MAX /
sizeof(WCHAR)))
908 WLog_ERR(TAG,
"cbAlternateShell > UINT16_MAX");
911 cbAlternateShell = (UINT16)cbAlternateShell *
sizeof(WCHAR);
916 FreeRDP_Settings_Keys_String inputId = FreeRDP_RemoteAssistanceSessionId;
918 inputId = FreeRDP_ShellWorkingDirectory;
922 if (cbWorkingDir > (UINT16_MAX /
sizeof(WCHAR)))
924 WLog_ERR(TAG,
"cbWorkingDir > UINT16_MAX");
927 cbWorkingDir = (UINT16)cbWorkingDir *
sizeof(WCHAR);
929 if (!Stream_EnsureRemainingCapacity(s, 18ull + cbDomain + cbUserName + cbPassword +
930 cbAlternateShell + cbWorkingDir + 5 *
sizeof(WCHAR)))
933 Stream_Write_UINT32(s, settings->KeyboardCodePage);
934 Stream_Write_UINT32(s, flags);
935 Stream_Write_UINT16(s, (UINT16)cbDomain);
936 Stream_Write_UINT16(s, (UINT16)cbUserName);
937 Stream_Write_UINT16(s, (UINT16)cbPassword);
938 Stream_Write_UINT16(s, (UINT16)cbAlternateShell);
939 Stream_Write_UINT16(s, (UINT16)cbWorkingDir);
941 Stream_Write(s, domainW, cbDomain);
944 Stream_Write_UINT16(s, 0);
946 Stream_Write(s, userNameW, cbUserName);
949 Stream_Write_UINT16(s, 0);
951 Stream_Write(s, passwordW, cbPassword);
954 Stream_Write_UINT16(s, 0);
956 Stream_Write(s, alternateShellW, cbAlternateShell);
959 Stream_Write_UINT16(s, 0);
961 Stream_Write(s, workingDirW, cbWorkingDir);
964 Stream_Write_UINT16(s, 0);
969 free(alternateShellW);
972 if (!usedPasswordCookie)
978 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
979 ret = rdp_write_extended_info_packet(rdp, s);
991BOOL rdp_recv_client_info(rdpRdp* rdp,
wStream* s)
994 UINT16 channelId = 0;
995 UINT16 securityFlags = 0;
997 WINPR_ASSERT(rdp_get_state(rdp) == CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE);
999 if (!rdp_read_header(rdp, s, &length, &channelId))
1002 if (!rdp_read_security_header(rdp, s, &securityFlags, &length))
1005 if ((securityFlags & SEC_INFO_PKT) == 0)
1008 if (rdp->settings->UseRdpSecurityLayer)
1010 if (securityFlags & SEC_REDIRECTION_PKT)
1012 WLog_ERR(TAG,
"Error: SEC_REDIRECTION_PKT unsupported");
1016 if (securityFlags & SEC_ENCRYPT)
1018 if (!rdp_decrypt(rdp, s, &length, securityFlags))
1023 return rdp_read_info_packet(rdp, s, length);
1032BOOL rdp_send_client_info(rdpRdp* rdp)
1034 UINT16 sec_flags = SEC_INFO_PKT;
1037 s = rdp_send_stream_init(rdp, &sec_flags);
1041 WLog_ERR(TAG,
"Stream_New failed!");
1045 if (!rdp_write_info_packet(rdp, s))
1050 return rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID, sec_flags);
1053static void rdp_free_logon_info(logon_info* info)
1058 free(info->username);
1060 const logon_info empty = WINPR_C_ARRAY_INIT;
1064static BOOL rdp_info_read_string(
const char* what,
wStream* s,
size_t size,
size_t max,
1065 BOOL skipMax,
char** dst)
1073 return Stream_SafeSeek(s, max);
1077 if (((size %
sizeof(WCHAR)) != 0) || (size > max))
1079 WLog_ERR(TAG,
"protocol error: invalid %s value: %" PRIuz
"", what, size);
1083 const WCHAR* str = Stream_ConstPointer(s);
1084 if (!Stream_SafeSeek(s, skipMax ? max : size))
1087 if (str[size /
sizeof(WCHAR) - 1])
1089 WLog_ERR(TAG,
"protocol error: %s must be null terminated", what);
1094 char* rc = ConvertWCharNToUtf8Alloc(str, size /
sizeof(WCHAR), &len);
1097 WLog_ERR(TAG,
"failed to convert the %s string", what);
1106static BOOL rdp_recv_logon_info_v1(rdpRdp* rdp,
wStream* s, logon_info* info)
1108 UINT32 cbDomain = 0;
1109 UINT32 cbUserName = 0;
1114 if (!Stream_CheckAndLogRequiredLength(TAG, s, 576))
1117 Stream_Read_UINT32(s, cbDomain);
1122 if (!rdp_info_read_string(
"Domain", s, cbDomain, 52, TRUE, &info->domain))
1125 Stream_Read_UINT32(s, cbUserName);
1130 if (!rdp_info_read_string(
"UserName", s, cbUserName, 512, TRUE, &info->username))
1133 Stream_Read_UINT32(s, info->sessionId);
1134 WLog_DBG(TAG,
"LogonInfoV1: SessionId: 0x%08" PRIX32
" UserName: [%s] Domain: [%s]",
1135 info->sessionId, info->username, info->domain);
1141static BOOL rdp_recv_logon_info_v2(rdpRdp* rdp,
wStream* s, logon_info* info)
1145 UINT32 cbDomain = 0;
1146 UINT32 cbUserName = 0;
1154 if (!Stream_CheckAndLogRequiredLength(TAG, s, logonInfoV2TotalSize))
1157 Stream_Read_UINT16(s, Version);
1158 if (Version != SAVE_SESSION_PDU_VERSION_ONE)
1160 WLog_WARN(TAG,
"LogonInfoV2::Version expected %d bytes, got %" PRIu16,
1161 SAVE_SESSION_PDU_VERSION_ONE, Version);
1165 Stream_Read_UINT32(s, Size);
1171 if (Size != logonInfoV2TotalSize)
1173 if (Size != logonInfoV2Size)
1175 WLog_WARN(TAG,
"LogonInfoV2::Size expected %" PRIu32
" bytes, got %" PRIu32,
1176 logonInfoV2TotalSize, Size);
1181 Stream_Read_UINT32(s, info->sessionId);
1182 Stream_Read_UINT32(s, cbDomain);
1183 Stream_Read_UINT32(s, cbUserName);
1184 Stream_Seek(s, logonInfoV2ReservedSize);
1192 if (!rdp_info_read_string(
"Domain", s, cbDomain, 52, FALSE, &info->domain))
1201 if (!rdp_info_read_string(
"UserName", s, cbUserName, 512, FALSE, &info->username))
1209 const size_t rem = Stream_GetRemainingLength(s);
1213 const char* str = Stream_ConstPointer(s);
1214 for (
size_t x = 0; x < rem; x++)
1221 WLog_WARN(TAG,
"unexpected padding of %" PRIuz
" bytes, data not '\\0'", rem);
1222 winpr_HexDump(TAG, WLOG_TRACE, str, rem);
1225 if (!Stream_SafeSeek(s, rem))
1230 WLog_DBG(TAG,
"LogonInfoV2: SessionId: 0x%08" PRIX32
" UserName: [%s] Domain: [%s]",
1231 info->sessionId, info->username, info->domain);
1237static BOOL rdp_recv_logon_plain_notify(rdpRdp* rdp,
wStream* s)
1240 if (!Stream_CheckAndLogRequiredLength(TAG, s, 576))
1243 Stream_Seek(s, 576);
1244 WLog_DBG(TAG,
"LogonPlainNotify");
1248static BOOL rdp_recv_logon_error_info(rdpRdp* rdp,
wStream* s, logon_info_ex* info)
1250 freerdp* instance =
nullptr;
1251 UINT32 errorNotificationType = 0;
1252 UINT32 errorNotificationData = 0;
1255 WINPR_ASSERT(rdp->context);
1259 instance = rdp->context->instance;
1260 WINPR_ASSERT(instance);
1262 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1265 Stream_Read_UINT32(s, errorNotificationType);
1266 Stream_Read_UINT32(s, errorNotificationData);
1267 WLog_DBG(TAG,
"LogonErrorInfo: Data: 0x%08" PRIX32
" Type: 0x%08" PRIX32
"",
1268 errorNotificationData, errorNotificationType);
1269 if (instance->LogonErrorInfo)
1272 instance->LogonErrorInfo(instance, errorNotificationData, errorNotificationType);
1276 info->ErrorNotificationType = errorNotificationType;
1277 info->ErrorNotificationData = errorNotificationData;
1281static BOOL rdp_recv_logon_info_extended(rdpRdp* rdp,
wStream* s, logon_info_ex* info)
1283 UINT32 cbFieldData = 0;
1284 UINT32 fieldsPresent = 0;
1291 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1293 WLog_WARN(TAG,
"received short logon info extended, need 6 bytes, got %" PRIuz,
1294 Stream_GetRemainingLength(s));
1298 Stream_Read_UINT16(s, Length);
1299 Stream_Read_UINT32(s, fieldsPresent);
1301 if ((Length < 6) || (!Stream_CheckAndLogRequiredLength(TAG, s, (Length - 6U))))
1304 "received short logon info extended, need %" PRIu16
" - 6 bytes, got %" PRIuz,
1305 Length, Stream_GetRemainingLength(s));
1309 WLog_DBG(TAG,
"LogonInfoExtended: fieldsPresent: 0x%08" PRIX32
"", fieldsPresent);
1313 if (fieldsPresent & LOGON_EX_AUTORECONNECTCOOKIE)
1315 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1318 info->haveCookie = TRUE;
1319 Stream_Read_UINT32(s, cbFieldData);
1321 if (!Stream_CheckAndLogRequiredLength(TAG, s, cbFieldData))
1324 if (!rdp_read_server_auto_reconnect_cookie(rdp, s, info))
1328 if (fieldsPresent & LOGON_EX_LOGONERRORS)
1330 info->haveErrorInfo = TRUE;
1332 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1335 Stream_Read_UINT32(s, cbFieldData);
1337 if (!Stream_CheckAndLogRequiredLength(TAG, s, cbFieldData))
1340 if (!rdp_recv_logon_error_info(rdp, s, info))
1344 if (!Stream_CheckAndLogRequiredLength(TAG, s, 570))
1347 Stream_Seek(s, 570);
1351BOOL rdp_recv_save_session_info(rdpRdp* rdp,
wStream* s)
1353 UINT32 infoType = 0;
1355 logon_info logonInfo = WINPR_C_ARRAY_INIT;
1356 logon_info_ex logonInfoEx = WINPR_C_ARRAY_INIT;
1357 rdpContext* context = rdp->context;
1358 rdpUpdate* update = rdp->context->update;
1360 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1363 Stream_Read_UINT32(s, infoType);
1367 case INFO_TYPE_LOGON:
1368 status = rdp_recv_logon_info_v1(rdp, s, &logonInfo);
1370 if (status && update->SaveSessionInfo)
1371 status = update->SaveSessionInfo(context, infoType, &logonInfo);
1373 rdp_free_logon_info(&logonInfo);
1376 case INFO_TYPE_LOGON_LONG:
1377 status = rdp_recv_logon_info_v2(rdp, s, &logonInfo);
1379 if (status && update->SaveSessionInfo)
1380 status = update->SaveSessionInfo(context, infoType, &logonInfo);
1382 rdp_free_logon_info(&logonInfo);
1385 case INFO_TYPE_LOGON_PLAIN_NOTIFY:
1386 status = rdp_recv_logon_plain_notify(rdp, s);
1388 if (status && update->SaveSessionInfo)
1389 status = update->SaveSessionInfo(context, infoType,
nullptr);
1393 case INFO_TYPE_LOGON_EXTENDED_INF:
1394 status = rdp_recv_logon_info_extended(rdp, s, &logonInfoEx);
1396 if (status && update->SaveSessionInfo)
1397 status = update->SaveSessionInfo(context, infoType, &logonInfoEx);
1402 WLog_ERR(TAG,
"Unhandled saveSessionInfo type 0x%" PRIx32
"", infoType);
1409 WLog_DBG(TAG,
"SaveSessionInfo error: infoType: %s (%" PRIu32
")",
1410 infoType < 4 ? INFO_TYPE_LOGON_STRINGS[infoType % 4] :
"Unknown", infoType);
1416static BOOL rdp_write_logon_info_v1(
wStream* s, logon_info* info)
1418 const size_t charLen = 52 /
sizeof(WCHAR);
1419 const size_t userCharLen = 512 /
sizeof(WCHAR);
1421 size_t sz = 4 + 52 + 4 + 512 + 4;
1423 if (!Stream_EnsureRemainingCapacity(s, sz))
1429 if (!info->domain || !info->username)
1431 const size_t len = strnlen(info->domain, charLen + 1);
1435 const size_t wlen = len *
sizeof(WCHAR);
1436 if (wlen > UINT32_MAX)
1439 Stream_Write_UINT32(s, (UINT32)wlen);
1440 if (Stream_Write_UTF16_String_From_UTF8(s, charLen, info->domain, len, TRUE) < 0)
1446 const size_t len = strnlen(info->username, userCharLen + 1);
1447 if (len > userCharLen)
1450 const size_t wlen = len *
sizeof(WCHAR);
1451 if (wlen > UINT32_MAX)
1454 Stream_Write_UINT32(s, (UINT32)wlen);
1456 if (Stream_Write_UTF16_String_From_UTF8(s, userCharLen, info->username, len, TRUE) < 0)
1461 Stream_Write_UINT32(s, info->sessionId);
1465static BOOL rdp_write_logon_info_v2(
wStream* s,
const logon_info* info)
1467 size_t domainLen = 0;
1468 size_t usernameLen = 0;
1469 size_t domainStrLen = 0;
1470 size_t usernameStrLen = 0;
1472 if (!Stream_EnsureRemainingCapacity(s, logonInfoV2TotalSize))
1475 Stream_Write_UINT16(s, SAVE_SESSION_PDU_VERSION_ONE);
1480 Stream_Write_UINT32(s, logonInfoV2Size);
1481 Stream_Write_UINT32(s, info->sessionId);
1484 domainStrLen = strnlen(info->domain, 256);
1485 const SSIZE_T wlen = ConvertUtf8NToWChar(info->domain, domainStrLen,
nullptr, 0);
1488 domainLen = WINPR_ASSERTING_INT_CAST(
size_t, wlen);
1490 if (domainLen >= UINT32_MAX /
sizeof(WCHAR))
1492 Stream_Write_UINT32(s, (UINT32)(domainLen + 1) *
sizeof(WCHAR));
1496 usernameStrLen = strnlen(info->username, 256);
1497 const SSIZE_T wlen = ConvertUtf8NToWChar(info->username, usernameStrLen,
nullptr, 0);
1500 usernameLen = WINPR_ASSERTING_INT_CAST(
size_t, wlen);
1502 if (usernameLen >= UINT32_MAX /
sizeof(WCHAR))
1504 Stream_Write_UINT32(s, (UINT32)(usernameLen + 1) *
sizeof(WCHAR));
1505 Stream_Seek(s, logonInfoV2ReservedSize);
1506 if (Stream_Write_UTF16_String_From_UTF8(s, domainLen + 1, info->domain, domainStrLen, TRUE) < 0)
1508 if (Stream_Write_UTF16_String_From_UTF8(s, usernameLen + 1, info->username, usernameStrLen,
1514static BOOL rdp_write_logon_info_plain(
wStream* s)
1516 if (!Stream_EnsureRemainingCapacity(s, 576))
1519 Stream_Seek(s, 576);
1523static BOOL rdp_write_logon_info_ex(
wStream* s, logon_info_ex* info)
1525 UINT32 FieldsPresent = 0;
1526 UINT16 Size = 2 + 4 + 570;
1528 if (info->haveCookie)
1530 FieldsPresent |= LOGON_EX_AUTORECONNECTCOOKIE;
1534 if (info->haveErrorInfo)
1536 FieldsPresent |= LOGON_EX_LOGONERRORS;
1540 if (!Stream_EnsureRemainingCapacity(s, Size))
1543 Stream_Write_UINT16(s, Size);
1544 Stream_Write_UINT32(s, FieldsPresent);
1546 if (info->haveCookie)
1548 Stream_Write_UINT32(s, 28);
1549 Stream_Write_UINT32(s, 28);
1550 Stream_Write_UINT32(s, AUTO_RECONNECT_VERSION_1);
1551 Stream_Write_UINT32(s, info->LogonId);
1552 Stream_Write(s, info->ArcRandomBits, 16);
1555 if (info->haveErrorInfo)
1557 Stream_Write_UINT32(s, 8);
1558 Stream_Write_UINT32(s, info->ErrorNotificationType);
1559 Stream_Write_UINT32(s, info->ErrorNotificationData);
1562 Stream_Seek(s, 570);
1566BOOL rdp_send_save_session_info(rdpContext* context, UINT32 type,
void* data)
1568 UINT16 sec_flags = 0;
1571 WINPR_ASSERT(context);
1572 rdpRdp* rdp = context->rdp;
1573 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
1578 Stream_Write_UINT32(s, type);
1582 case INFO_TYPE_LOGON:
1583 status = rdp_write_logon_info_v1(s, (logon_info*)data);
1586 case INFO_TYPE_LOGON_LONG:
1587 status = rdp_write_logon_info_v2(s, (logon_info*)data);
1590 case INFO_TYPE_LOGON_PLAIN_NOTIFY:
1591 status = rdp_write_logon_info_plain(s);
1594 case INFO_TYPE_LOGON_EXTENDED_INF:
1595 status = rdp_write_logon_info_ex(s, (logon_info_ex*)data);
1599 WLog_ERR(TAG,
"saveSessionInfo type 0x%" PRIx32
" not handled", type);
1606 rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SAVE_SESSION_INFO, rdp->mcs->userId, sec_flags);
1613BOOL rdp_send_server_status_info(rdpContext* context, UINT32 status)
1615 UINT16 sec_flags = 0;
1617 rdpRdp* rdp = context->rdp;
1618 s = rdp_data_pdu_init(rdp, &sec_flags);
1623 Stream_Write_UINT32(s, status);
1624 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_STATUS_INFO, rdp->mcs->userId, sec_flags);
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string_from_utf16N(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const WCHAR *param, size_t length)
Sets a string settings value. The param is converted to UTF-8 and the copy stored.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string 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_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 UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API WCHAR * freerdp_settings_get_string_as_utf16(const rdpSettings *settings, FreeRDP_Settings_Keys_String id, size_t *pCharLen)
Return an allocated UTF16 string.
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.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.