|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* FreeRDP: A Remote Desktop Protocol Implementation
|
|
Packit |
1fb8d4 |
* RDP Server Redirection
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
Packit |
1fb8d4 |
* you may not use this file except in compliance with the License.
|
|
Packit |
1fb8d4 |
* You may obtain a copy of the License at
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
1fb8d4 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
1fb8d4 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
1fb8d4 |
* See the License for the specific language governing permissions and
|
|
Packit |
1fb8d4 |
* limitations under the License.
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
1fb8d4 |
#include "config.h"
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <winpr/crt.h>
|
|
Packit |
1fb8d4 |
#include <freerdp/log.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include "connection.h"
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include "redirection.h"
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#define TAG FREERDP_TAG("core.redirection")
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
struct rdp_redirection
|
|
Packit Service |
5a9772 |
{
|
|
Packit Service |
5a9772 |
UINT32 flags;
|
|
Packit Service |
5a9772 |
UINT32 sessionID;
|
|
Packit Service |
5a9772 |
BYTE* TsvUrl;
|
|
Packit Service |
5a9772 |
DWORD TsvUrlLength;
|
|
Packit Service |
5a9772 |
char* Username;
|
|
Packit Service |
5a9772 |
char* Domain;
|
|
Packit Service |
5a9772 |
BYTE* Password;
|
|
Packit Service |
5a9772 |
DWORD PasswordLength;
|
|
Packit Service |
5a9772 |
char* TargetFQDN;
|
|
Packit Service |
5a9772 |
BYTE* LoadBalanceInfo;
|
|
Packit Service |
5a9772 |
DWORD LoadBalanceInfoLength;
|
|
Packit Service |
5a9772 |
char* TargetNetBiosName;
|
|
Packit Service |
5a9772 |
char* TargetNetAddress;
|
|
Packit Service |
5a9772 |
UINT32 TargetNetAddressesCount;
|
|
Packit Service |
5a9772 |
char** TargetNetAddresses;
|
|
Packit Service |
5a9772 |
};
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
static void rdp_print_redirection_flags(UINT32 flags)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "redirectionFlags = {");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_TARGET_NET_ADDRESS)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_TARGET_NET_ADDRESS");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_LOAD_BALANCE_INFO)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_LOAD_BALANCE_INFO");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_USERNAME)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_USERNAME");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_DOMAIN)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_DOMAIN");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_PASSWORD)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_PASSWORD");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_DONTSTOREUSERNAME)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_DONTSTOREUSERNAME");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_SMARTCARD_LOGON)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_SMARTCARD_LOGON");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_NOREDIRECT)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_NOREDIRECT");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_TARGET_FQDN)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_TARGET_FQDN");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_TARGET_NETBIOS_NAME)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_TARGET_NETBIOS_NAME");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_TARGET_NET_ADDRESSES)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_TARGET_NET_ADDRESSES");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_CLIENT_TSV_URL)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_CLIENT_TSV_URL");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (flags & LB_SERVER_TSV_CAPABLE)
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "\tLB_SERVER_TSV_CAPABLE");
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "}");
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t maxLength)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT32 length;
|
|
Packit |
1fb8d4 |
WCHAR* wstr = NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < 4)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
WLog_ERR(TAG, "rdp_redirection_read_string failure: cannot read length");
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
Stream_Read_UINT32(s, length);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if ((length % 2) || length < 2 || length > maxLength)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
WLog_ERR(TAG,
|
|
Packit Service |
5a9772 |
"rdp_redirection_read_string failure: invalid unicode string length: %" PRIu32 "",
|
|
Packit Service |
5a9772 |
length);
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < length)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
WLog_ERR(TAG,
|
|
Packit Service |
5a9772 |
"rdp_redirection_read_string failure: insufficient stream length (%" PRIu32
|
|
Packit Service |
5a9772 |
" bytes required)",
|
|
Packit Service |
5a9772 |
length);
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
wstr = (WCHAR*)Stream_Pointer(s);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (wstr[length / 2 - 1])
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
WLog_ERR(TAG, "rdp_redirection_read_string failure: unterminated unicode string");
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, str, 0, NULL, NULL) < 1)
|
|
Packit |
1fb8d4 |
{
|
|
Packit Service |
5a9772 |
WLog_ERR(TAG, "rdp_redirection_read_string failure: string conversion failed");
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
Stream_Seek(s, length);
|
|
Packit |
1fb8d4 |
return TRUE;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
int rdp_redirection_apply_settings(rdpRdp* rdp)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
rdpSettings* settings = rdp->settings;
|
|
Packit |
1fb8d4 |
rdpRedirection* redirection = rdp->redirection;
|
|
Packit |
1fb8d4 |
settings->RedirectionFlags = redirection->flags;
|
|
Packit |
1fb8d4 |
settings->RedirectedSessionId = redirection->sessionID;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_LOAD_BALANCE_INFO)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* LoadBalanceInfo may not contain a null terminator */
|
|
Packit |
1fb8d4 |
free(settings->LoadBalanceInfo);
|
|
Packit |
1fb8d4 |
settings->LoadBalanceInfoLength = redirection->LoadBalanceInfoLength;
|
|
Packit Service |
5a9772 |
settings->LoadBalanceInfo = (BYTE*)malloc(settings->LoadBalanceInfoLength);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!settings->LoadBalanceInfo)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
CopyMemory(settings->LoadBalanceInfo, redirection->LoadBalanceInfo,
|
|
Packit Service |
5a9772 |
settings->LoadBalanceInfoLength);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* Free previous LoadBalanceInfo, if any, otherwise it may end up
|
|
Packit |
1fb8d4 |
* being reused for the redirected session, which is not what we want.
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
free(settings->LoadBalanceInfo);
|
|
Packit |
1fb8d4 |
settings->LoadBalanceInfo = NULL;
|
|
Packit |
1fb8d4 |
settings->LoadBalanceInfoLength = 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_TARGET_FQDN)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(settings->RedirectionTargetFQDN);
|
|
Packit |
1fb8d4 |
settings->RedirectionTargetFQDN = _strdup(redirection->TargetFQDN);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->RedirectionTargetFQDN)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESS)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(settings->TargetNetAddress);
|
|
Packit |
1fb8d4 |
settings->TargetNetAddress = _strdup(redirection->TargetNetAddress);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->TargetNetAddress)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_TARGET_NETBIOS_NAME)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(settings->RedirectionTargetNetBiosName);
|
|
Packit |
1fb8d4 |
settings->RedirectionTargetNetBiosName = _strdup(redirection->TargetNetBiosName);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->RedirectionTargetNetBiosName)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_USERNAME)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(settings->RedirectionUsername);
|
|
Packit |
1fb8d4 |
settings->RedirectionUsername = _strdup(redirection->Username);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->RedirectionUsername)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_DOMAIN)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(settings->RedirectionDomain);
|
|
Packit |
1fb8d4 |
settings->RedirectionDomain = _strdup(redirection->Domain);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->RedirectionDomain)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_PASSWORD)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* Password may be a cookie without a null terminator */
|
|
Packit |
1fb8d4 |
free(settings->RedirectionPassword);
|
|
Packit |
1fb8d4 |
settings->RedirectionPasswordLength = redirection->PasswordLength;
|
|
Packit |
1fb8d4 |
/* For security reasons we'll allocate an additional zero WCHAR at the
|
|
Packit |
1fb8d4 |
* end of the buffer that is not included in RedirectionPasswordLength
|
|
Packit |
1fb8d4 |
*/
|
|
Packit Service |
5a9772 |
settings->RedirectionPassword =
|
|
Packit Service |
5a9772 |
(BYTE*)calloc(1, settings->RedirectionPasswordLength + sizeof(WCHAR));
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->RedirectionPassword)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
CopyMemory(settings->RedirectionPassword, redirection->Password,
|
|
Packit Service |
5a9772 |
settings->RedirectionPasswordLength);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_CLIENT_TSV_URL)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* TsvUrl may not contain a null terminator */
|
|
Packit |
1fb8d4 |
free(settings->RedirectionTsvUrl);
|
|
Packit |
1fb8d4 |
settings->RedirectionTsvUrlLength = redirection->TsvUrlLength;
|
|
Packit Service |
5a9772 |
settings->RedirectionTsvUrl = (BYTE*)malloc(settings->RedirectionTsvUrlLength);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->RedirectionTsvUrl)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit Service |
5a9772 |
|
|
Packit Service |
5a9772 |
CopyMemory(settings->RedirectionTsvUrl, redirection->TsvUrl,
|
|
Packit Service |
5a9772 |
settings->RedirectionTsvUrlLength);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESSES)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT32 i;
|
|
Packit |
1fb8d4 |
freerdp_target_net_addresses_free(settings);
|
|
Packit |
1fb8d4 |
settings->TargetNetAddressCount = redirection->TargetNetAddressesCount;
|
|
Packit Service |
5a9772 |
settings->TargetNetAddresses =
|
|
Packit Service |
5a9772 |
(char**)calloc(settings->TargetNetAddressCount, sizeof(char*));
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->TargetNetAddresses)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
settings->TargetNetAddressCount = 0;
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
for (i = 0; i < settings->TargetNetAddressCount; i++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
settings->TargetNetAddresses[i] = _strdup(redirection->TargetNetAddresses[i]);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!settings->TargetNetAddresses[i])
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT32 j;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
for (j = 0; j < i; j++)
|
|
Packit |
1fb8d4 |
free(settings->TargetNetAddresses[j]);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT16 flags;
|
|
Packit |
1fb8d4 |
UINT16 length;
|
|
Packit |
1fb8d4 |
rdpRedirection* redirection = rdp->redirection;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < 12)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
Stream_Read_UINT16(s, flags); /* flags (2 bytes) */
|
|
Packit Service |
5a9772 |
Stream_Read_UINT16(s, length); /* length (2 bytes) */
|
|
Packit |
1fb8d4 |
Stream_Read_UINT32(s, redirection->sessionID); /* sessionID (4 bytes) */
|
|
Packit Service |
5a9772 |
Stream_Read_UINT32(s, redirection->flags); /* redirFlags (4 bytes) */
|
|
Packit Service |
5a9772 |
WLog_DBG(TAG,
|
|
Packit Service |
5a9772 |
"flags: 0x%04" PRIX16 ", redirFlags: 0x%08" PRIX32 " length: %" PRIu16
|
|
Packit Service |
5a9772 |
", sessionID: 0x%08" PRIX32 "",
|
|
Packit Service |
5a9772 |
flags, redirection->flags, length, redirection->sessionID);
|
|
Packit |
1fb8d4 |
rdp_print_redirection_flags(redirection->flags);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Although MS-RDPBCGR does not mention any length constraints limits for the
|
|
Packit |
1fb8d4 |
* variable length null-terminated unicode strings in the RDP_SERVER_REDIRECTION_PACKET
|
|
Packit |
1fb8d4 |
* structure we will use the following limits in bytes including the null terminator:
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* TargetNetAddress: 80 bytes
|
|
Packit |
1fb8d4 |
* UserName: 512 bytes
|
|
Packit |
1fb8d4 |
* Domain: 52 bytes
|
|
Packit |
1fb8d4 |
* Password(Cookie): 512 bytes
|
|
Packit |
1fb8d4 |
* TargetFQDN: 512 bytes
|
|
Packit |
1fb8d4 |
* TargetNetBiosName: 32 bytes
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_TARGET_NET_ADDRESS)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddress), 80))
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_LOAD_BALANCE_INFO)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* See [MSFT-SDLBTS] (a.k.a. TS_Session_Directory.doc)
|
|
Packit |
1fb8d4 |
* load balance info example data:
|
|
Packit |
1fb8d4 |
* 0000 43 6f 6f 6b 69 65 3a 20 6d 73 74 73 3d 32 31 33 Cookie: msts=213
|
|
Packit |
1fb8d4 |
* 0010 34 30 32 36 34 33 32 2e 31 35 36 32 39 2e 30 30 4026432.15629.00
|
|
Packit Service |
5a9772 |
* 0020 30 30 0d 0a 00..
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < 4)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
Stream_Read_UINT32(s, redirection->LoadBalanceInfoLength);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < redirection->LoadBalanceInfoLength)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
redirection->LoadBalanceInfo = (BYTE*)malloc(redirection->LoadBalanceInfoLength);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!redirection->LoadBalanceInfo)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
Stream_Read(s, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength);
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "loadBalanceInfo:");
|
|
Packit Service |
5a9772 |
winpr_HexDump(TAG, WLOG_DEBUG, redirection->LoadBalanceInfo,
|
|
Packit Service |
5a9772 |
redirection->LoadBalanceInfoLength);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_USERNAME)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!rdp_redirection_read_unicode_string(s, &(redirection->Username), 512))
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "Username: %s", redirection->Username);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_DOMAIN)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!rdp_redirection_read_unicode_string(s, &(redirection->Domain), 52))
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "Domain: %s", redirection->Domain);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_PASSWORD)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* Note: Password is a variable-length array of bytes containing the
|
|
Packit |
1fb8d4 |
* password used by the user in Unicode format, including a null-terminator
|
|
Packit |
1fb8d4 |
* or (!) or a cookie value that MUST be passed to the target server on
|
|
Packit |
1fb8d4 |
* successful connection.
|
|
Packit |
1fb8d4 |
* Since the format of the password cookie (probably some salted hash) is
|
|
Packit |
1fb8d4 |
* currently unknown we'll treat it as opaque data. All cookies seen so far
|
|
Packit |
1fb8d4 |
* are 120 bytes including \0\0 termination.
|
|
Packit |
1fb8d4 |
* Here is an observed example of a redirection password cookie:
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* 0000 02 00 00 80 44 53 48 4c 60 ab 69 2f 07 d6 9e 2d ....DSHL`.i/...-
|
|
Packit |
1fb8d4 |
* 0010 f0 3a 97 3b a9 c5 ec 7e 66 bd b3 84 6c b1 ef b9 .:.;...~f...l...
|
|
Packit |
1fb8d4 |
* 0020 b6 82 4e cc 3a df 64 b7 7b 25 04 54 c2 58 98 f8 ..N.:.d.{%.T.X..
|
|
Packit |
1fb8d4 |
* 0030 97 87 d4 93 c7 c1 e1 5b c2 85 f8 22 49 1f 81 88 .......[..."I...
|
|
Packit |
1fb8d4 |
* 0040 43 44 83 f6 9a 72 40 24 dc 4d 43 cb d9 92 3c 8f CD...r@$.MC...<.
|
|
Packit |
1fb8d4 |
* 0050 3a 37 5c 77 13 a0 72 3c 72 08 64 2a 29 fb dc eb :7\w..r
|
|
Packit |
1fb8d4 |
* 0060 0d 2b 06 b4 c6 08 b4 73 34 16 93 62 6d 24 e9 93 .+.....s4..bm$..
|
|
Packit |
1fb8d4 |
* 0070 97 27 7b dd 9a 72 00 00 .'{..r..
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Notwithstanding the above, we'll allocated an additional zero WCHAR at the
|
|
Packit |
1fb8d4 |
* end of the buffer which won't get counted in PasswordLength.
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < 4)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
Stream_Read_UINT32(s, redirection->PasswordLength);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* [MS-RDPBCGR] specifies 512 bytes as the upper limit for the password length
|
|
Packit |
1fb8d4 |
* including the null terminatior(s). This should also be enough for the unknown
|
|
Packit |
1fb8d4 |
* password cookie format (see previous comment).
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < redirection->PasswordLength)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->PasswordLength > LB_PASSWORD_MAX_LENGTH)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
redirection->Password = (BYTE*)calloc(1, redirection->PasswordLength + sizeof(WCHAR));
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!redirection->Password)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
Stream_Read(s, redirection->Password, redirection->PasswordLength);
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "PasswordCookie:");
|
|
Packit Service |
5a9772 |
#if defined(WITH_DEBUG_REDIR)
|
|
Packit |
1fb8d4 |
winpr_HexDump(TAG, WLOG_DEBUG, redirection->Password, redirection->PasswordLength);
|
|
Packit Service |
5a9772 |
#endif
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_TARGET_FQDN)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetFQDN), 512))
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "TargetFQDN: %s", redirection->TargetFQDN);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_TARGET_NETBIOS_NAME)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetBiosName), 32))
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "TargetNetBiosName: %s", redirection->TargetNetBiosName);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_CLIENT_TSV_URL)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < 4)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
Stream_Read_UINT32(s, redirection->TsvUrlLength);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < redirection->TsvUrlLength)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
redirection->TsvUrl = (BYTE*)malloc(redirection->TsvUrlLength);
|
|
Packit Service |
5a9772 |
|
|
Packit |
1fb8d4 |
if (!redirection->TsvUrl)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
Stream_Read(s, redirection->TsvUrl, redirection->TsvUrlLength);
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "TsvUrl:");
|
|
Packit |
1fb8d4 |
winpr_HexDump(TAG, WLOG_DEBUG, redirection->TsvUrl, redirection->TsvUrlLength);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_TARGET_NET_ADDRESSES)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int i;
|
|
Packit |
1fb8d4 |
UINT32 count;
|
|
Packit |
1fb8d4 |
UINT32 targetNetAddressesLength;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) < 8)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
Stream_Read_UINT32(s, targetNetAddressesLength);
|
|
Packit |
1fb8d4 |
Stream_Read_UINT32(s, redirection->TargetNetAddressesCount);
|
|
Packit |
1fb8d4 |
count = redirection->TargetNetAddressesCount;
|
|
Packit Service |
5a9772 |
redirection->TargetNetAddresses = (char**)calloc(count, sizeof(char*));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!redirection->TargetNetAddresses)
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
WLog_DBG(TAG, "TargetNetAddressesCount: %" PRIu32 "", redirection->TargetNetAddressesCount);
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
for (i = 0; i < (int)count; i++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddresses[i]), 80))
|
|
Packit |
1fb8d4 |
return FALSE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "TargetNetAddresses[%d]: %s", i, redirection->TargetNetAddresses[i]);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) >= 8)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* some versions of windows don't included this padding before closing the connection */
|
|
Packit |
1fb8d4 |
Stream_Seek(s, 8); /* pad (8 bytes) */
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->flags & LB_NOREDIRECT)
|
|
Packit |
1fb8d4 |
return 0;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return 1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
int rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int status = 0;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!Stream_SafeSeek(s, 2)) /* pad2Octets (2 bytes) */
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
status = rdp_recv_server_redirection_pdu(rdp, s);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (status < 0)
|
|
Packit |
1fb8d4 |
return status;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (Stream_GetRemainingLength(s) >= 1)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* this field is optional, and its absence is not an error */
|
|
Packit |
1fb8d4 |
Stream_Seek(s, 1); /* pad2Octets (1 byte) */
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return status;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
rdpRedirection* redirection_new()
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
rdpRedirection* redirection;
|
|
Packit Service |
5a9772 |
redirection = (rdpRedirection*)calloc(1, sizeof(rdpRedirection));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return redirection;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
void redirection_free(rdpRedirection* redirection)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (redirection)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(redirection->TsvUrl);
|
|
Packit |
1fb8d4 |
free(redirection->Username);
|
|
Packit |
1fb8d4 |
free(redirection->Domain);
|
|
Packit |
1fb8d4 |
free(redirection->TargetFQDN);
|
|
Packit |
1fb8d4 |
free(redirection->TargetNetBiosName);
|
|
Packit |
1fb8d4 |
free(redirection->TargetNetAddress);
|
|
Packit |
1fb8d4 |
free(redirection->LoadBalanceInfo);
|
|
Packit |
1fb8d4 |
free(redirection->Password);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (redirection->TargetNetAddresses)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int i;
|
|
Packit |
1fb8d4 |
|
|
Packit Service |
5a9772 |
for (i = 0; i < (int)redirection->TargetNetAddressesCount; i++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
free(redirection->TargetNetAddresses[i]);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
free(redirection->TargetNetAddresses);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
free(redirection);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|