diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index f6e5c61e2..a80dd0300 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -361,6 +361,9 @@ FREERDP_API const char* freerdp_get_last_error_name(UINT32 error); FREERDP_API const char* freerdp_get_last_error_string(UINT32 error); FREERDP_API void freerdp_set_last_error(rdpContext* context, UINT32 lastError); +FREERDP_API const char* freerdp_get_logon_error_info_type(UINT32 type); +FREERDP_API const char* freerdp_get_logon_error_info_data(UINT32 data); + FREERDP_API ULONG freerdp_get_transport_sent(rdpContext* context, BOOL resetCount); diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 509d4d659..a3766eec3 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -238,10 +238,10 @@ struct _TARGET_NET_ADDRESS typedef struct _TARGET_NET_ADDRESS TARGET_NET_ADDRESS; /* Logon Error Info */ - +#define LOGON_MSG_DISCONNECT_REFUSED 0xFFFFFFF9 #define LOGON_MSG_NO_PERMISSION 0xFFFFFFFA #define LOGON_MSG_BUMP_OPTIONS 0xFFFFFFFB -#define LOGON_MSG_SESSION_RECONNECT 0xFFFFFFFC +#define LOGON_MSG_RECONNECT_OPTIONS 0xFFFFFFFC #define LOGON_MSG_SESSION_TERMINATE 0xFFFFFFFD #define LOGON_MSG_SESSION_CONTINUE 0xFFFFFFFE diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 996b5fd45..b57499e8f 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -867,6 +867,54 @@ void freerdp_set_last_error(rdpContext* context, UINT32 lastError) } } +const char* freerdp_get_logon_error_info_type(UINT32 type) +{ + switch (type) + { + case LOGON_MSG_DISCONNECT_REFUSED: + return "LOGON_MSG_DISCONNECT_REFUSED"; + + case LOGON_MSG_NO_PERMISSION: + return "LOGON_MSG_NO_PERMISSION"; + + case LOGON_MSG_BUMP_OPTIONS: + return "LOGON_MSG_BUMP_OPTIONS"; + + case LOGON_MSG_RECONNECT_OPTIONS: + return "LOGON_MSG_RECONNECT_OPTIONS"; + + case LOGON_MSG_SESSION_TERMINATE: + return "LOGON_MSG_SESSION_TERMINATE"; + + case LOGON_MSG_SESSION_CONTINUE: + return "LOGON_MSG_SESSION_CONTINUE"; + + default: + return "UNKNOWN"; + } +} + +const char* freerdp_get_logon_error_info_data(UINT32 data) +{ + switch (data) + { + case LOGON_FAILED_BAD_PASSWORD: + return "LOGON_FAILED_BAD_PASSWORD"; + + case LOGON_FAILED_UPDATE_PASSWORD: + return "LOGON_FAILED_UPDATE_PASSWORD"; + + case LOGON_FAILED_OTHER: + return "LOGON_FAILED_OTHER"; + + case LOGON_WARNING: + return "LOGON_WARNING"; + + default: + return "SESSION_ID"; + } +} + /** Allocator function for the rdp_freerdp structure. * @return an allocated structure filled with 0s. Need to be deallocated using freerdp_free() */ diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 4ae5dcde0..697f247c9 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -43,25 +43,21 @@ static const char* const INFO_TYPE_LOGON_STRINGS[4] = "Logon Extended Info" }; -BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp) +static BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp) { BYTE ClientRandom[32]; BYTE AutoReconnectRandom[32]; ARC_SC_PRIVATE_PACKET* serverCookie; ARC_CS_PRIVATE_PACKET* clientCookie; rdpSettings* settings = rdp->settings; - serverCookie = settings->ServerAutoReconnectCookie; clientCookie = settings->ClientAutoReconnectCookie; - clientCookie->cbLen = 28; clientCookie->version = serverCookie->version; clientCookie->logonId = serverCookie->logonId; ZeroMemory(clientCookie->securityVerifier, 16); - ZeroMemory(AutoReconnectRandom, sizeof(AutoReconnectRandom)); CopyMemory(AutoReconnectRandom, serverCookie->arcRandomBits, 16); - ZeroMemory(ClientRandom, sizeof(ClientRandom)); if (settings->SelectedProtocol == PROTOCOL_RDP) @@ -69,7 +65,8 @@ BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp) /* SecurityVerifier = HMAC_MD5(AutoReconnectRandom, ClientRandom) */ - if (!winpr_HMAC(WINPR_MD_MD5, AutoReconnectRandom, 16, ClientRandom, 32, clientCookie->securityVerifier, 16)) + if (!winpr_HMAC(WINPR_MD_MD5, AutoReconnectRandom, 16, ClientRandom, 32, + clientCookie->securityVerifier, 16)) return FALSE; return TRUE; @@ -82,18 +79,18 @@ BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp) * @param settings settings */ -BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s, logon_info_ex *info) +static BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s, logon_info_ex* info) { BYTE* p; ARC_SC_PRIVATE_PACKET* autoReconnectCookie; rdpSettings* settings = rdp->settings; - autoReconnectCookie = settings->ServerAutoReconnectCookie; if (Stream_GetRemainingLength(s) < 28) return FALSE; Stream_Read_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ + if (autoReconnectCookie->cbLen != 28) { WLog_ERR(TAG, "ServerAutoReconnectCookie.cbLen != 28"); @@ -103,16 +100,13 @@ BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s, logon_info_e Stream_Read_UINT32(s, autoReconnectCookie->version); /* Version (4 bytes) */ Stream_Read_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ Stream_Read(s, autoReconnectCookie->arcRandomBits, 16); /* ArcRandomBits (16 bytes) */ - p = autoReconnectCookie->arcRandomBits; - WLog_DBG(TAG, "ServerAutoReconnectCookie: Version: %"PRIu32" LogonId: %"PRIu32" SecurityVerifier: " - "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"" - "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"", - autoReconnectCookie->version, autoReconnectCookie->logonId, - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], - p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); - + "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"" + "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"", + autoReconnectCookie->version, autoReconnectCookie->logonId, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); info->LogonId = autoReconnectCookie->logonId; CopyMemory(info->ArcRandomBits, p, 16); @@ -134,11 +128,10 @@ BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s, logon_info_e * @param settings settings */ -BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) +static BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) { ARC_CS_PRIVATE_PACKET* autoReconnectCookie; rdpSettings* settings = rdp->settings; - autoReconnectCookie = settings->ClientAutoReconnectCookie; if (Stream_GetRemainingLength(s) < 28) @@ -148,7 +141,6 @@ BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) Stream_Read_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */ Stream_Read_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ Stream_Read(s, autoReconnectCookie->securityVerifier, 16); /* SecurityVerifier */ - return TRUE; } @@ -159,23 +151,19 @@ BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) * @param settings settings */ -void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) +static void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) { BYTE* p; ARC_CS_PRIVATE_PACKET* autoReconnectCookie; rdpSettings* settings = rdp->settings; - autoReconnectCookie = settings->ClientAutoReconnectCookie; - p = autoReconnectCookie->securityVerifier; - WLog_DBG(TAG, "ClientAutoReconnectCookie: Version: %"PRIu32" LogonId: %"PRIu32" ArcRandomBits: " - "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"" - "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"", - autoReconnectCookie->version, autoReconnectCookie->logonId, - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], - p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); - + "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"" + "%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"%02"PRIX8"", + autoReconnectCookie->version, autoReconnectCookie->logonId, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); Stream_Write_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ @@ -189,7 +177,7 @@ void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) * @param settings settings */ -BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) +static BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) { UINT16 clientAddressFamily; UINT16 cbClientAddress; @@ -231,16 +219,19 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) if (cbClientAddress) { wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbClientAddress / 2 - 1]) { WLog_ERR(TAG, "protocol error: clientAddress must be null terminated"); return FALSE; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->ClientAddress, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert client address"); return FALSE; } + Stream_Seek(s, cbClientAddress); WLog_DBG(TAG, "rdp client address: [%s]", settings->ClientAddress); } @@ -276,16 +267,20 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) if (cbClientDir) { wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbClientDir / 2 - 1]) { WLog_ERR(TAG, "protocol error: clientDir must be null terminated"); return FALSE; } - if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, &settings->ClientDir, 0, NULL, NULL) < 1) + + if (ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(s), -1, &settings->ClientDir, 0, NULL, + NULL) < 1) { WLog_ERR(TAG, "failed to convert client directory"); return FALSE; } + Stream_Seek(s, cbClientDir); WLog_DBG(TAG, "rdp client dir: [%s]", settings->ClientDir); } @@ -298,29 +293,36 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) /* optional: clientTimeZone (172 bytes) */ if (Stream_GetRemainingLength(s) == 0) return TRUE; + if (!rdp_read_client_time_zone(s, settings)) return FALSE; /* optional: clientSessionId (4 bytes), should be set to 0 */ if (Stream_GetRemainingLength(s) == 0) return TRUE; + if (Stream_GetRemainingLength(s) < 4) return FALSE; + Stream_Seek_UINT32(s); /* optional: performanceFlags (4 bytes) */ if (Stream_GetRemainingLength(s) == 0) return TRUE; + if (Stream_GetRemainingLength(s) < 4) return FALSE; + Stream_Read_UINT32(s, settings->PerformanceFlags); freerdp_performance_flags_split(settings); /* optional: cbAutoReconnectLen (2 bytes) */ if (Stream_GetRemainingLength(s) == 0) return TRUE; + if (Stream_GetRemainingLength(s) < 2) return FALSE; + Stream_Read_UINT16(s, cbAutoReconnectLen); /* optional: autoReconnectCookie (28 bytes) */ @@ -329,13 +331,11 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) return rdp_read_client_auto_reconnect_cookie(rdp, s); /* TODO */ - /* reserved1 (2 bytes) */ /* reserved2 (2 bytes) */ /* cbDynamicDSTTimeZoneKeyName (2 bytes) */ /* dynamicDSTTimeZoneKeyName (variable) */ /* dynamicDaylightTimeDisabled (2 bytes) */ - return TRUE; } @@ -346,7 +346,7 @@ BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) * @param settings settings */ -void rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) +static void rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) { int clientAddressFamily; WCHAR* clientAddress = NULL; @@ -355,44 +355,33 @@ void rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) int cbClientDir; int cbAutoReconnectCookie; rdpSettings* settings = rdp->settings; - clientAddressFamily = settings->IPv6Enabled ? ADDRESS_FAMILY_INET6 : ADDRESS_FAMILY_INET; - cbClientAddress = ConvertToUnicode(CP_UTF8, 0, settings->ClientAddress, -1, &clientAddress, 0) * 2; - cbClientDir = ConvertToUnicode(CP_UTF8, 0, settings->ClientDir, -1, &clientDir, 0) * 2; - cbAutoReconnectCookie = (int) settings->ServerAutoReconnectCookie->cbLen; - Stream_Write_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ - Stream_Write_UINT16(s, cbClientAddress + 2); /* cbClientAddress (2 bytes) */ if (cbClientAddress > 0) Stream_Write(s, clientAddress, cbClientAddress); /* clientAddress */ - Stream_Write_UINT16(s, 0); + Stream_Write_UINT16(s, 0); Stream_Write_UINT16(s, cbClientDir + 2); /* cbClientDir (2 bytes) */ if (cbClientDir > 0) Stream_Write(s, clientDir, cbClientDir); /* clientDir */ + Stream_Write_UINT16(s, 0); - rdp_write_client_time_zone(s, settings); /* clientTimeZone (172 bytes) */ - Stream_Write_UINT32(s, 0); /* clientSessionId (4 bytes), should be set to 0 */ - freerdp_performance_flags_make(settings); Stream_Write_UINT32(s, settings->PerformanceFlags); /* performanceFlags (4 bytes) */ - Stream_Write_UINT16(s, cbAutoReconnectCookie); /* cbAutoReconnectCookie (2 bytes) */ if (cbAutoReconnectCookie > 0) { rdp_compute_client_auto_reconnect_cookie(rdp); - rdp_write_client_auto_reconnect_cookie(rdp, s); /* autoReconnectCookie */ - Stream_Write_UINT16(s, 0); /* reserved1 (2 bytes) */ Stream_Write_UINT16(s, 0); /* reserved2 (2 bytes) */ } @@ -408,7 +397,7 @@ void rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) * @param settings settings */ -BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) +static BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) { UINT32 flags; UINT16 cbDomain; @@ -425,7 +414,6 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) Stream_Seek_UINT32(s); /* CodePage (4 bytes ) */ Stream_Read_UINT32(s, flags); /* flags (4 bytes) */ - settings->AudioCapture = ((flags & INFO_AUDIOCAPTURE) ? TRUE : FALSE); settings->AudioPlayback = ((flags & INFO_NOAUDIOPLAYBACK) ? FALSE : TRUE); settings->AutoLogonEnabled = ((flags & INFO_AUTOLOGON) ? TRUE : FALSE); @@ -452,7 +440,7 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, cbAlternateShell); /* cbAlternateShell (2 bytes) */ Stream_Read_UINT16(s, cbWorkingDir); /* cbWorkingDir (2 bytes) */ - if (Stream_GetRemainingLength(s) < (size_t) (cbDomain + 2)) + if (Stream_GetRemainingLength(s) < (size_t)(cbDomain + 2)) return FALSE; if (cbDomain > 0) @@ -466,22 +454,27 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) WLog_ERR(TAG, "protocol error: invalid cbDomain value: %"PRIu16"", cbDomain); return FALSE; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2]) { WLog_ERR(TAG, "protocol error: Domain must be null terminated"); return FALSE; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Domain, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert Domain string"); return FALSE; } + Stream_Seek(s, cbDomain); } + Stream_Seek(s, 2); - if (Stream_GetRemainingLength(s) < (size_t) (cbUserName + 2)) + if (Stream_GetRemainingLength(s) < (size_t)(cbUserName + 2)) return FALSE; if (cbUserName > 0) @@ -495,22 +488,27 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) WLog_ERR(TAG, "protocol error: invalid cbUserName value: %"PRIu16"", cbUserName); return FALSE; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2]) { WLog_ERR(TAG, "protocol error: UserName must be null terminated"); return FALSE; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Username, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert UserName string"); return FALSE; } + Stream_Seek(s, cbUserName); } + Stream_Seek(s, 2); - if (Stream_GetRemainingLength(s) < (size_t) (cbPassword + 2)) + if (Stream_GetRemainingLength(s) < (size_t)(cbPassword + 2)) return FALSE; if (cbPassword > 0) @@ -524,22 +522,27 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) WLog_ERR(TAG, "protocol error: invalid cbPassword value: %"PRIu16"", cbPassword); return FALSE; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbPassword / 2]) { WLog_ERR(TAG, "protocol error: Password must be null terminated"); return FALSE; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->Password, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert Password string"); return FALSE; } + Stream_Seek(s, cbPassword); } + Stream_Seek(s, 2); - if (Stream_GetRemainingLength(s) < (size_t) (cbAlternateShell + 2)) + if (Stream_GetRemainingLength(s) < (size_t)(cbAlternateShell + 2)) return FALSE; if (cbAlternateShell > 0) @@ -553,22 +556,27 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) WLog_ERR(TAG, "protocol error: invalid cbAlternateShell value: %"PRIu16"", cbAlternateShell); return FALSE; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbAlternateShell / 2]) { WLog_ERR(TAG, "protocol error: AlternateShell must be null terminated"); return FALSE; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->AlternateShell, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert AlternateShell string"); return FALSE; } + Stream_Seek(s, cbAlternateShell); } + Stream_Seek(s, 2); - if (Stream_GetRemainingLength(s) < (size_t) (cbWorkingDir + 2)) + if (Stream_GetRemainingLength(s) < (size_t)(cbWorkingDir + 2)) return FALSE; if (cbWorkingDir > 0) @@ -582,19 +590,24 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) WLog_ERR(TAG, "protocol error: invalid cbWorkingDir value: %"PRIu16"", cbWorkingDir); return FALSE; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbWorkingDir / 2]) { WLog_ERR(TAG, "protocol error: WorkingDir must be null terminated"); return FALSE; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &settings->ShellWorkingDirectory, 0, NULL, NULL) < 1) { WLog_ERR(TAG, "failed to convert AlternateShell string"); return FALSE; } + Stream_Seek(s, cbWorkingDir); } + Stream_Seek(s, 2); if (settings->RdpVersion >= 5) @@ -610,7 +623,7 @@ BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) * @param settings settings */ -void rdp_write_info_packet(rdpRdp* rdp, wStream* s) +static void rdp_write_info_packet(rdpRdp* rdp, wStream* s) { UINT32 flags; WCHAR* domainW = NULL; @@ -625,7 +638,6 @@ void rdp_write_info_packet(rdpRdp* rdp, wStream* s) int cbWorkingDir = 0; BOOL usedPasswordCookie = FALSE; rdpSettings* settings = rdp->settings; - flags = INFO_MOUSE | INFO_UNICODE | INFO_LOGONERRORS | @@ -704,7 +716,8 @@ void rdp_write_info_packet(rdpRdp* rdp, wStream* s) if (!settings->RemoteAssistanceMode) { - cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->AlternateShell, -1, &alternateShellW, 0) * 2; + cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->AlternateShell, -1, &alternateShellW, + 0) * 2; } else { @@ -716,23 +729,25 @@ void rdp_write_info_packet(rdpRdp* rdp, wStream* s) else { /* This field must contain the remote assistance password */ - cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->RemoteAssistancePassword, -1, &alternateShellW, 0) * 2; + cbAlternateShell = ConvertToUnicode(CP_UTF8, 0, settings->RemoteAssistancePassword, -1, + &alternateShellW, 0) * 2; } } if (!settings->RemoteAssistanceMode) { - cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->ShellWorkingDirectory, -1, &workingDirW, 0) * 2; + cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->ShellWorkingDirectory, -1, &workingDirW, + 0) * 2; } else { /* Remote Assistance Session Id */ - cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->RemoteAssistanceSessionId, -1, &workingDirW, 0) * 2; + cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->RemoteAssistanceSessionId, -1, &workingDirW, + 0) * 2; } Stream_Write_UINT32(s, 0); /* CodePage (4 bytes) */ Stream_Write_UINT32(s, flags); /* flags (4 bytes) */ - Stream_Write_UINT16(s, cbDomain); /* cbDomain (2 bytes) */ Stream_Write_UINT16(s, cbUserName); /* cbUserName (2 bytes) */ Stream_Write_UINT16(s, cbPassword); /* cbPassword (2 bytes) */ @@ -741,24 +756,28 @@ void rdp_write_info_packet(rdpRdp* rdp, wStream* s) if (cbDomain > 0) Stream_Write(s, domainW, cbDomain); + Stream_Write_UINT16(s, 0); if (cbUserName > 0) Stream_Write(s, userNameW, cbUserName); + Stream_Write_UINT16(s, 0); if (cbPassword > 0) Stream_Write(s, passwordW, cbPassword); + Stream_Write_UINT16(s, 0); if (cbAlternateShell > 0) Stream_Write(s, alternateShellW, cbAlternateShell); + Stream_Write_UINT16(s, 0); if (cbWorkingDir > 0) Stream_Write(s, workingDirW, cbWorkingDir); - Stream_Write_UINT16(s, 0); + Stream_Write_UINT16(s, 0); free(domainW); free(userNameW); free(alternateShellW); @@ -824,9 +843,7 @@ BOOL rdp_send_client_info(rdpRdp* rdp) { wStream* s; BOOL status; - rdp->sec_flags |= SEC_INFO_PKT; - s = Stream_New(NULL, 2048); if (!s) @@ -836,22 +853,17 @@ BOOL rdp_send_client_info(rdpRdp* rdp) } rdp_init_stream(rdp, s); - rdp_write_info_packet(rdp, s); - status = rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID); - Stream_Free(s, TRUE); - return status; } -BOOL rdp_recv_logon_info_v1(rdpRdp* rdp, wStream* s, logon_info *info) +static BOOL rdp_recv_logon_info_v1(rdpRdp* rdp, wStream* s, logon_info* info) { UINT32 cbDomain; UINT32 cbUserName; WCHAR* wstr; - ZeroMemory(info, sizeof(*info)); if (Stream_GetRemainingLength(s) < 576) @@ -869,21 +881,23 @@ BOOL rdp_recv_logon_info_v1(rdpRdp* rdp, wStream* s, logon_info *info) WLog_ERR(TAG, "protocol error: invalid cbDomain value: %"PRIu32"", cbDomain); goto fail; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2 - 1]) { WLog_ERR(TAG, "protocol error: Domain must be null terminated"); goto fail; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->domain, 0, NULL, FALSE) < 1) { WLog_ERR(TAG, "failed to convert the Domain string"); goto fail; } } + Stream_Seek(s, 52); /* domain (52 bytes) */ - - Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ /* cbUserName is the size of the Unicode character data (including the mandatory @@ -896,27 +910,27 @@ BOOL rdp_recv_logon_info_v1(rdpRdp* rdp, wStream* s, logon_info *info) WLog_ERR(TAG, "protocol error: invalid cbUserName value: %"PRIu32"", cbUserName); goto fail; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2 - 1]) { WLog_ERR(TAG, "protocol error: UserName must be null terminated"); goto fail; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->username, 0, NULL, FALSE) < 1) { WLog_ERR(TAG, "failed to convert the UserName string"); goto fail; } } + Stream_Seek(s, 512); /* userName (512 bytes) */ - Stream_Read_UINT32(s, info->sessionId); /* SessionId (4 bytes) */ - WLog_DBG(TAG, "LogonInfoV1: SessionId: 0x%08"PRIX32" UserName: [%s] Domain: [%s]", - info->sessionId, info->username, info->domain); - + info->sessionId, info->username, info->domain); return TRUE; - fail: free(info->username); info->username = NULL; @@ -925,14 +939,13 @@ fail: return FALSE; } -BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s, logon_info *info) +static BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s, logon_info* info) { UINT16 Version; UINT32 Size; UINT32 cbDomain; UINT32 cbUserName; WCHAR* wstr; - ZeroMemory(info, sizeof(*info)); if (Stream_GetRemainingLength(s) < 576) @@ -945,7 +958,6 @@ BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s, logon_info *info) Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ Stream_Seek(s, 558); /* pad (558 bytes) */ - /* cbDomain is the size in bytes of the Unicode character data in the Domain field. * The size of the mandatory null terminator is include in this value. * Note: Since MS-RDPBCGR 2.2.10.1.1.2 does not mention any size limits we assume @@ -959,23 +971,28 @@ BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s, logon_info *info) WLog_ERR(TAG, "protocol error: invalid cbDomain value: %"PRIu32"", cbDomain); goto fail; } + if (Stream_GetRemainingLength(s) < (size_t) cbDomain) { WLog_ERR(TAG, "insufficient remaining stream length"); goto fail; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbDomain / 2 - 1]) { WLog_ERR(TAG, "protocol error: Domain field must be null terminated"); goto fail; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->domain, 0, NULL, FALSE) < 1) { WLog_ERR(TAG, "failed to convert the Domain string"); goto fail; } } + Stream_Seek(s, cbDomain); /* domain */ /* cbUserName is the size in bytes of the Unicode character data in the UserName field. @@ -991,30 +1008,32 @@ BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s, logon_info *info) WLog_ERR(TAG, "protocol error: invalid cbUserName value: %"PRIu32"", cbUserName); goto fail; } + if (Stream_GetRemainingLength(s) < (size_t) cbUserName) { WLog_ERR(TAG, "insufficient remaining stream length"); goto fail; } + wstr = (WCHAR*) Stream_Pointer(s); + if (wstr[cbUserName / 2 - 1]) { WLog_ERR(TAG, "protocol error: UserName field must be null terminated"); goto fail; } + if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, &info->username, 0, NULL, FALSE) < 1) { WLog_ERR(TAG, "failed to convert the Domain string"); goto fail; } } + Stream_Seek(s, cbUserName); /* userName */ - WLog_DBG(TAG, "LogonInfoV2: SessionId: 0x%08"PRIX32" UserName: [%s] Domain: [%s]", - info->sessionId, info->username, info->domain); - + info->sessionId, info->username, info->domain); return TRUE; - fail: free(info->username); info->username = NULL; @@ -1023,19 +1042,17 @@ fail: return FALSE; } -BOOL rdp_recv_logon_plain_notify(rdpRdp* rdp, wStream* s) +static BOOL rdp_recv_logon_plain_notify(rdpRdp* rdp, wStream* s) { if (Stream_GetRemainingLength(s) < 576) return FALSE; Stream_Seek(s, 576); /* pad (576 bytes) */ - WLog_DBG(TAG, "LogonPlainNotify"); - return TRUE; } -BOOL rdp_recv_logon_error_info(rdpRdp* rdp, wStream* s, logon_info_ex *info) +static BOOL rdp_recv_logon_error_info(rdpRdp* rdp, wStream* s, logon_info_ex* info) { UINT32 errorNotificationType; UINT32 errorNotificationData; @@ -1045,18 +1062,15 @@ BOOL rdp_recv_logon_error_info(rdpRdp* rdp, wStream* s, logon_info_ex *info) Stream_Read_UINT32(s, errorNotificationType); /* errorNotificationType (4 bytes) */ Stream_Read_UINT32(s, errorNotificationData); /* errorNotificationData (4 bytes) */ - WLog_DBG(TAG, "LogonErrorInfo: Data: 0x%08"PRIX32" Type: 0x%08"PRIX32"", - errorNotificationData, errorNotificationType); - + errorNotificationData, errorNotificationType); IFCALL(rdp->instance->LogonErrorInfo, rdp->instance, errorNotificationData, errorNotificationType); - info->ErrorNotificationType = errorNotificationType; info->ErrorNotificationData = errorNotificationData; return TRUE; } -BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s, logon_info_ex *info) +static BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s, logon_info_ex* info) { UINT32 cbFieldData; UINT32 fieldsPresent; @@ -1093,6 +1107,7 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s, logon_info_ex *info) if (fieldsPresent & LOGON_EX_LOGONERRORS) { info->haveErrorInfo = TRUE; + if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -1109,7 +1124,6 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s, logon_info_ex *info) return FALSE; Stream_Seek(s, 570); /* pad (570 bytes) */ - return TRUE; } @@ -1119,8 +1133,8 @@ BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) BOOL status; logon_info logonInfo; logon_info_ex logonInfoEx; - rdpContext *context = rdp->context; - rdpUpdate *update = rdp->context->update; + rdpContext* context = rdp->context; + rdpUpdate* update = rdp->context->update; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -1132,8 +1146,10 @@ BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) case INFO_TYPE_LOGON: ZeroMemory(&logonInfo, sizeof(logonInfo)); status = rdp_recv_logon_info_v1(rdp, s, &logonInfo); + if (status && update->SaveSessionInfo) status = update->SaveSessionInfo(context, infoType, &logonInfo); + free(logonInfo.domain); free(logonInfo.username); break; @@ -1141,23 +1157,29 @@ BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) case INFO_TYPE_LOGON_LONG: ZeroMemory(&logonInfo, sizeof(logonInfo)); status = rdp_recv_logon_info_v2(rdp, s, &logonInfo); + if (status && update->SaveSessionInfo) status = update->SaveSessionInfo(context, infoType, &logonInfo); + free(logonInfo.domain); free(logonInfo.username); break; case INFO_TYPE_LOGON_PLAIN_NOTIFY: status = rdp_recv_logon_plain_notify(rdp, s); + if (status && update->SaveSessionInfo) status = update->SaveSessionInfo(context, infoType, NULL); + break; case INFO_TYPE_LOGON_EXTENDED_INF: ZeroMemory(&logonInfoEx, sizeof(logonInfoEx)); status = rdp_recv_logon_info_extended(rdp, s, &logonInfoEx); + if (status && update->SaveSessionInfo) status = update->SaveSessionInfo(context, infoType, &logonInfoEx); + break; default: @@ -1169,26 +1191,29 @@ BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) if (!status) { WLog_DBG(TAG, "SaveSessionInfo error: infoType: %s (%"PRIu32")", - infoType < 4 ? INFO_TYPE_LOGON_STRINGS[infoType % 4] : "Unknown", infoType); + infoType < 4 ? INFO_TYPE_LOGON_STRINGS[infoType % 4] : "Unknown", infoType); } return status; } -static BOOL rdp_write_logon_info_v1(wStream *s, logon_info *info) +static BOOL rdp_write_logon_info_v1(wStream* s, logon_info* info) { int sz = 4 + 52 + 4 + 512 + 4; int len; - WCHAR *wString = NULL; + WCHAR* wString = NULL; if (!Stream_EnsureRemainingCapacity(s, sz)) return FALSE; /* domain */ len = ConvertToUnicode(CP_UTF8, 0, info->domain, -1, &wString, 0); + if (len < 0) return FALSE; + len *= 2; + if (len > 52) return FALSE; @@ -1196,13 +1221,14 @@ static BOOL rdp_write_logon_info_v1(wStream *s, logon_info *info) Stream_Write(s, wString, len); Stream_Seek(s, 52 - len); free(wString); - /* username */ len = ConvertToUnicode(CP_UTF8, 0, info->username, -1, &wString, 0); + if (len < 0) return FALSE; len *= 2; + if (len > 512) return FALSE; @@ -1210,18 +1236,16 @@ static BOOL rdp_write_logon_info_v1(wStream *s, logon_info *info) Stream_Write(s, wString, len); Stream_Seek(s, 512 - len); free(wString); - /* sessionId */ Stream_Write_UINT32(s, info->sessionId); - return TRUE; } -static BOOL rdp_write_logon_info_v2(wStream *s, logon_info *info) +static BOOL rdp_write_logon_info_v2(wStream* s, logon_info* info) { int Size = 2 + 4 + 4 + 4 + 4 + 558; int domainLen, usernameLen, len; - WCHAR *wString; + WCHAR* wString; if (!Stream_EnsureRemainingCapacity(s, Size)) return FALSE; @@ -1229,23 +1253,20 @@ static BOOL rdp_write_logon_info_v2(wStream *s, logon_info *info) Stream_Write_UINT16(s, SAVE_SESSION_PDU_VERSION_ONE); Stream_Write_UINT32(s, Size); Stream_Write_UINT32(s, info->sessionId); - domainLen = strlen(info->domain); Stream_Write_UINT32(s, (domainLen + 1) * 2); - usernameLen = strlen(info->username); Stream_Write_UINT32(s, (usernameLen + 1) * 2); - Stream_Seek(s, 558); - len = ConvertToUnicode(CP_UTF8, 0, info->domain, -1, &wString, 0); + if (len < 0) return FALSE; Stream_Write(s, wString, len * 2); free(wString); - len = ConvertToUnicode(CP_UTF8, 0, info->username, -1, &wString, 0); + if (len < 0) return FALSE; @@ -1254,7 +1275,7 @@ static BOOL rdp_write_logon_info_v2(wStream *s, logon_info *info) return TRUE; } -static BOOL rdp_write_logon_info_plain(wStream *s) +static BOOL rdp_write_logon_info_plain(wStream* s) { if (!Stream_EnsureRemainingCapacity(s, 576)) return FALSE; @@ -1263,7 +1284,7 @@ static BOOL rdp_write_logon_info_plain(wStream *s) return TRUE; } -static BOOL rdp_write_logon_info_ex(wStream *s, logon_info_ex *info) +static BOOL rdp_write_logon_info_ex(wStream* s, logon_info_ex* info) { UINT32 FieldsPresent = 0; UINT16 Size = 2 + 4 + 570; @@ -1289,7 +1310,6 @@ static BOOL rdp_write_logon_info_ex(wStream *s, logon_info_ex *info) if (info->haveCookie) { Stream_Write_UINT32(s, 28); /* cbFieldData (4 bytes) */ - Stream_Write_UINT32(s, 28); /* cbLen (4 bytes) */ Stream_Write_UINT32(s, AUTO_RECONNECT_VERSION_1); /* Version (4 bytes) */ Stream_Write_UINT32(s, info->LogonId); /* LogonId (4 bytes) */ @@ -1299,7 +1319,6 @@ static BOOL rdp_write_logon_info_ex(wStream *s, logon_info_ex *info) if (info->haveErrorInfo) { Stream_Write_UINT32(s, 8); /* cbFieldData (4 bytes) */ - Stream_Write_UINT32(s, info->ErrorNotificationType); /* ErrorNotificationType (4 bytes) */ Stream_Write_UINT32(s, info->ErrorNotificationData); /* ErrorNotificationData (4 bytes) */ } @@ -1308,13 +1327,13 @@ static BOOL rdp_write_logon_info_ex(wStream *s, logon_info_ex *info) return TRUE; } -BOOL rdp_send_save_session_info(rdpContext *context, UINT32 type, void *data) +BOOL rdp_send_save_session_info(rdpContext* context, UINT32 type, void* data) { - wStream *s; + wStream* s; BOOL status; - rdpRdp *rdp = context->rdp; - + rdpRdp* rdp = context->rdp; s = rdp_data_pdu_init(rdp); + if (!s) return FALSE; @@ -1322,27 +1341,32 @@ BOOL rdp_send_save_session_info(rdpContext *context, UINT32 type, void *data) switch (type) { - case INFO_TYPE_LOGON: - status = rdp_write_logon_info_v1(s, (logon_info *)data); - break; - case INFO_TYPE_LOGON_LONG: - status = rdp_write_logon_info_v2(s, (logon_info *)data); - break; - case INFO_TYPE_LOGON_PLAIN_NOTIFY: - status = rdp_write_logon_info_plain(s); - break; - case INFO_TYPE_LOGON_EXTENDED_INF: - status = rdp_write_logon_info_ex(s, (logon_info_ex *)data); - break; - default: - WLog_ERR(TAG, "saveSessionInfo type 0x%"PRIx32" not handled", type); - status = FALSE; - break; + case INFO_TYPE_LOGON: + status = rdp_write_logon_info_v1(s, (logon_info*)data); + break; + + case INFO_TYPE_LOGON_LONG: + status = rdp_write_logon_info_v2(s, (logon_info*)data); + break; + + case INFO_TYPE_LOGON_PLAIN_NOTIFY: + status = rdp_write_logon_info_plain(s); + break; + + case INFO_TYPE_LOGON_EXTENDED_INF: + status = rdp_write_logon_info_ex(s, (logon_info_ex*)data); + break; + + default: + WLog_ERR(TAG, "saveSessionInfo type 0x%"PRIx32" not handled", type); + status = FALSE; + break; } if (status) status = rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SAVE_SESSION_INFO, rdp->mcs->userId); else Stream_Free(s, TRUE); + return status; } diff --git a/libfreerdp/core/info.h b/libfreerdp/core/info.h index ab2962e3e..6ed61d112 100644 --- a/libfreerdp/core/info.h +++ b/libfreerdp/core/info.h @@ -58,16 +58,7 @@ #define SAVE_SESSION_PDU_VERSION_ONE 0x0001 - -FREERDP_LOCAL BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, - wStream* s); -FREERDP_LOCAL void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, - wStream* s); FREERDP_LOCAL void rdp_write_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); -FREERDP_LOCAL BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s); -FREERDP_LOCAL void rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s); -FREERDP_LOCAL BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s); -FREERDP_LOCAL void rdp_write_info_packet(rdpRdp* rdp, wStream* s); FREERDP_LOCAL BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s); FREERDP_LOCAL BOOL rdp_send_client_info(rdpRdp* rdp); FREERDP_LOCAL BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s);