Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,170 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# libfreerdp-core cmake build script
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "freerdp-core")
set(MODULE_PREFIX "FREERDP_CORE")
# We use some fields that are only defined in linux 5.11+
check_symbol_exists(VMADDR_FLAG_TO_HOST "ctype.h;sys/socket.h;linux/vm_sockets.h" HAVE_AF_VSOCK_H)
freerdp_definition_add(EXT_PATH="${FREERDP_EXTENSION_PATH}")
freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR})
set(${MODULE_PREFIX}_GATEWAY_DIR "gateway")
set(${MODULE_PREFIX}_GATEWAY_SRCS
${${MODULE_PREFIX}_GATEWAY_DIR}/tsg.c
${${MODULE_PREFIX}_GATEWAY_DIR}/tsg.h
${${MODULE_PREFIX}_GATEWAY_DIR}/rdg.c
${${MODULE_PREFIX}_GATEWAY_DIR}/rdg.h
${${MODULE_PREFIX}_GATEWAY_DIR}/rpc.c
${${MODULE_PREFIX}_GATEWAY_DIR}/rpc.h
${${MODULE_PREFIX}_GATEWAY_DIR}/rpc_bind.c
${${MODULE_PREFIX}_GATEWAY_DIR}/rpc_bind.h
${${MODULE_PREFIX}_GATEWAY_DIR}/rpc_client.c
${${MODULE_PREFIX}_GATEWAY_DIR}/rpc_client.h
${${MODULE_PREFIX}_GATEWAY_DIR}/rpc_fault.c
${${MODULE_PREFIX}_GATEWAY_DIR}/rpc_fault.h
${${MODULE_PREFIX}_GATEWAY_DIR}/rts.c
${${MODULE_PREFIX}_GATEWAY_DIR}/rts.h
${${MODULE_PREFIX}_GATEWAY_DIR}/rts_signature.c
${${MODULE_PREFIX}_GATEWAY_DIR}/rts_signature.h
${${MODULE_PREFIX}_GATEWAY_DIR}/http.c
${${MODULE_PREFIX}_GATEWAY_DIR}/http.h
${${MODULE_PREFIX}_GATEWAY_DIR}/websocket.c
${${MODULE_PREFIX}_GATEWAY_DIR}/websocket.h
${${MODULE_PREFIX}_GATEWAY_DIR}/wst.c
${${MODULE_PREFIX}_GATEWAY_DIR}/wst.h
${${MODULE_PREFIX}_GATEWAY_DIR}/arm.c
${${MODULE_PREFIX}_GATEWAY_DIR}/arm.h
${${MODULE_PREFIX}_GATEWAY_DIR}/ncacn_http.c
${${MODULE_PREFIX}_GATEWAY_DIR}/ncacn_http.h
)
set(${MODULE_PREFIX}_SRCS
simd.h
state.h
state.c
utils.c
utils.h
streamdump.c
activation.c
activation.h
gcc.c
gcc.h
mcs.c
mcs.h
nla.c
nla.h
smartcardlogon.c
nego.c
nego.h
info.c
info.h
input.c
input.h
license.c
license.h
errinfo.c
errbase.c
errconnect.c
errinfo.h
security.c
security.h
settings.c
settings.h
orders.c
orders.h
freerdp.c
graphics.c
client.c
client.h
server.c
server.h
codecs.c
metrics.c
capabilities.c
capabilities.h
connection.c
connection.h
redirection.c
redirection.h
autodetect.c
autodetect.h
heartbeat.c
heartbeat.h
multitransport.c
multitransport.h
timezone.c
timezone.h
childsession.c
rdp.c
rdp.h
tcp.c
tcp.h
proxy.c
proxy.h
tpdu.c
tpdu.h
tpkt.c
tpkt.h
fastpath.c
fastpath.h
surface.c
surface.h
transport.c
transport.h
update.c
update.h
message.c
message.h
channels.c
channels.h
window.c
window.h
listener.c
listener.h
peer.c
peer.h
display.c
display.h
credssp_auth.c
credssp_auth.h
rdstls.c
rdstls.h
aad.c
aad.h
timer.c
timer.h
)
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_GATEWAY_SRCS})
freerdp_module_add(${${MODULE_PREFIX}_SRCS})
if(WIN32)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ws2_32)
freerdp_library_add(ws2_32)
endif()
freerdp_library_add(${OPENSSL_LIBRARIES})
freerdp_pc_add_requires_private("libssl")
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()

1051
third_party/FreeRDP/libfreerdp/core/aad.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Network Level Authentication (NLA)
*
* Copyright 2023 Isaac Klein <fifthdegree@protonmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_AAD_H
#define FREERDP_LIB_CORE_AAD_H
typedef struct rdp_aad rdpAad;
typedef enum
{
AAD_STATE_INITIAL,
AAD_STATE_AUTH,
AAD_STATE_FINAL
} AAD_STATE;
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL aad_is_supported(void);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int aad_client_begin(rdpAad* aad);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int aad_recv(rdpAad* aad, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL AAD_STATE aad_get_state(rdpAad* aad);
FREERDP_LOCAL void aad_free(rdpAad* aad);
WINPR_ATTR_MALLOC(aad_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpAad* aad_new(rdpContext* context);
#endif /* FREERDP_LIB_CORE_AAD_H */

View File

@@ -0,0 +1,834 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Activation Sequence
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include "settings.h"
#include <winpr/assert.h>
#include <winpr/cast.h>
#include "activation.h"
#include "display.h"
#define TAG FREERDP_TAG("core.activation")
static BOOL rdp_recv_client_font_list_pdu(wStream* s);
static BOOL rdp_recv_client_persistent_key_list_pdu(wStream* s);
static BOOL rdp_send_server_font_map_pdu(rdpRdp* rdp);
static BOOL rdp_write_synchronize_pdu(wStream* s, const rdpSettings* settings)
{
const UINT32 PduSource = freerdp_settings_get_uint32(settings, FreeRDP_PduSource);
if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 4))
return FALSE;
Stream_Write_UINT16(s, SYNCMSGTYPE_SYNC); /* messageType (2 bytes) */
Stream_Write_UINT16(s,
WINPR_ASSERTING_INT_CAST(uint16_t, PduSource)); /* targetUser (2 bytes) */
return TRUE;
}
static BOOL rdp_recv_sync_pdu(rdpRdp* rdp, wStream* s, const char* what)
{
UINT16 msgType = 0;
UINT16 targetUser = 0;
WINPR_UNUSED(rdp);
if (!Stream_CheckAndLogRequiredLengthEx(TAG, WLOG_WARN, s, 4, 1, "%s(%s:%" PRIuz ") %s",
__func__, __FILE__, (size_t)__LINE__, what))
return FALSE;
Stream_Read_UINT16(s, msgType);
if (msgType != SYNCMSGTYPE_SYNC)
{
WLog_WARN(TAG, "%s: Invalid messageType=0x%04" PRIx16 ", expected 0x%04" PRIx16, what,
msgType, WINPR_CXX_COMPAT_CAST(uint16_t, SYNCMSGTYPE_SYNC));
return FALSE;
}
Stream_Read_UINT16(s, targetUser);
WLog_VRB(TAG, "%s: targetUser=0x%04" PRIx16, what, targetUser);
return TRUE;
}
BOOL rdp_recv_server_synchronize_pdu(rdpRdp* rdp, wStream* s)
{
if (!rdp_recv_sync_pdu(rdp, s, "[MS-RDPBCGR] 2.2.1.19 Server Synchronize PDU"))
return FALSE;
return rdp_finalize_set_flag(rdp, FINALIZE_SC_SYNCHRONIZE_PDU);
}
BOOL rdp_send_server_synchronize_pdu(rdpRdp* rdp)
{
UINT16 sec_flags = 0;
wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
if (!s)
return FALSE;
WINPR_ASSERT(rdp);
if (!rdp_write_synchronize_pdu(s, rdp->settings))
{
Stream_Free(s, TRUE);
return FALSE;
}
WINPR_ASSERT(rdp->mcs);
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SYNCHRONIZE, rdp->mcs->userId, sec_flags);
}
BOOL rdp_recv_client_synchronize_pdu(rdpRdp* rdp, wStream* s)
{
if (!rdp_recv_sync_pdu(rdp, s, "[MS-RDPBCGR] 2.2.1.14 Client Synchronize PDU"))
return FALSE;
return rdp_finalize_set_flag(rdp, FINALIZE_CS_SYNCHRONIZE_PDU);
}
BOOL rdp_send_client_synchronize_pdu(rdpRdp* rdp)
{
UINT16 sec_flags = 0;
wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
if (!s)
return FALSE;
WINPR_ASSERT(rdp);
if (!rdp_write_synchronize_pdu(s, rdp->settings))
{
Stream_Free(s, TRUE);
return FALSE;
}
WINPR_ASSERT(rdp->mcs);
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SYNCHRONIZE, rdp->mcs->userId, sec_flags);
}
static BOOL rdp_recv_control_pdu(wStream* s, UINT16* action, UINT16* grantId, UINT32* controlId)
{
WINPR_ASSERT(s);
WINPR_ASSERT(action);
WINPR_ASSERT(grantId);
WINPR_ASSERT(controlId);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return FALSE;
Stream_Read_UINT16(s, *action); /* action (2 bytes) */
Stream_Read_UINT16(s, *grantId); /* grantId (2 bytes) */
Stream_Read_UINT32(s, *controlId); /* controlId (4 bytes) */
return TRUE;
}
static BOOL rdp_write_client_control_pdu(wStream* s, UINT16 action, UINT16 grantId,
UINT32 controlId)
{
WINPR_ASSERT(s);
if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
return FALSE;
Stream_Write_UINT16(s, action); /* action (2 bytes) */
Stream_Write_UINT16(s, grantId); /* grantId (2 bytes) */
Stream_Write_UINT32(s, controlId); /* controlId (4 bytes) */
return TRUE;
}
BOOL rdp_recv_server_control_pdu(rdpRdp* rdp, wStream* s)
{
UINT16 action = 0;
UINT16 grantId = 0;
UINT32 controlId = 0;
WINPR_ASSERT(rdp);
WINPR_ASSERT(s);
if (!rdp_recv_control_pdu(s, &action, &grantId, &controlId))
return FALSE;
switch (action)
{
case CTRLACTION_COOPERATE:
return rdp_finalize_set_flag(rdp, FINALIZE_SC_CONTROL_COOPERATE_PDU);
case CTRLACTION_GRANTED_CONTROL:
rdp->resendFocus = TRUE;
return rdp_finalize_set_flag(rdp, FINALIZE_SC_CONTROL_GRANTED_PDU);
default:
{
char buffer[128] = WINPR_C_ARRAY_INIT;
WLog_WARN(TAG, "Unexpected control PDU %s",
rdp_ctrlaction_string(action, buffer, sizeof(buffer)));
return FALSE;
}
}
}
BOOL rdp_send_server_control_cooperate_pdu(rdpRdp* rdp)
{
UINT16 sec_flags = 0;
wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
if (!s)
return FALSE;
if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
{
Stream_Free(s, TRUE);
return FALSE;
}
Stream_Write_UINT16(s, CTRLACTION_COOPERATE); /* action (2 bytes) */
Stream_Write_UINT16(s, 0); /* grantId (2 bytes) */
Stream_Write_UINT32(s, 0); /* controlId (4 bytes) */
WINPR_ASSERT(rdp->mcs);
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->userId, sec_flags);
}
BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp)
{
UINT16 sec_flags = 0;
wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
if (!s)
return FALSE;
if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
{
Stream_Free(s, TRUE);
return FALSE;
}
WINPR_ASSERT(rdp->mcs);
Stream_Write_UINT16(s, CTRLACTION_GRANTED_CONTROL); /* action (2 bytes) */
Stream_Write_UINT16(s, rdp->mcs->userId); /* grantId (2 bytes) */
Stream_Write_UINT32(s, 0x03EA); /* controlId (4 bytes) */
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->userId, sec_flags);
}
BOOL rdp_send_client_control_pdu(rdpRdp* rdp, UINT16 action)
{
UINT16 GrantId = 0;
UINT16 ControlId = 0;
switch (action)
{
case CTRLACTION_COOPERATE:
case CTRLACTION_REQUEST_CONTROL:
break;
default:
WLog_WARN(TAG,
"Invalid client control PDU::action 0x%04" PRIx16 ", not allowed by client",
action);
return FALSE;
}
UINT16 sec_flags = 0;
wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
if (!s)
return FALSE;
if (!rdp_write_client_control_pdu(s, action, GrantId, ControlId))
{
Stream_Free(s, TRUE);
return FALSE;
}
WINPR_ASSERT(rdp->mcs);
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->userId, sec_flags);
}
static BOOL rdp_write_client_persistent_key_list_pdu(wStream* s,
const RDP_BITMAP_PERSISTENT_INFO* info)
{
WINPR_ASSERT(s);
WINPR_ASSERT(info);
if (!Stream_EnsureRemainingCapacity(s, 24))
return FALSE;
Stream_Write_UINT16(s, info->numEntriesCache0); /* numEntriesCache0 (2 bytes) */
Stream_Write_UINT16(s, info->numEntriesCache1); /* numEntriesCache1 (2 bytes) */
Stream_Write_UINT16(s, info->numEntriesCache2); /* numEntriesCache2 (2 bytes) */
Stream_Write_UINT16(s, info->numEntriesCache3); /* numEntriesCache3 (2 bytes) */
Stream_Write_UINT16(s, info->numEntriesCache4); /* numEntriesCache4 (2 bytes) */
Stream_Write_UINT16(s, info->totalEntriesCache0); /* totalEntriesCache0 (2 bytes) */
Stream_Write_UINT16(s, info->totalEntriesCache1); /* totalEntriesCache1 (2 bytes) */
Stream_Write_UINT16(s, info->totalEntriesCache2); /* totalEntriesCache2 (2 bytes) */
Stream_Write_UINT16(s, info->totalEntriesCache3); /* totalEntriesCache3 (2 bytes) */
Stream_Write_UINT16(s, info->totalEntriesCache4); /* totalEntriesCache4 (2 bytes) */
Stream_Write_UINT8(s, PERSIST_FIRST_PDU | PERSIST_LAST_PDU); /* bBitMask (1 byte) */
Stream_Write_UINT8(s, 0); /* pad1 (1 byte) */
Stream_Write_UINT16(s, 0); /* pad3 (2 bytes) */
/* entries */
if (!Stream_EnsureRemainingCapacity(s, info->keyCount * 8ull))
return FALSE;
for (UINT32 index = 0; index < info->keyCount; index++)
{
const UINT64 val = info->keyList[index];
Stream_Write_UINT64(s, val);
}
return TRUE;
}
static UINT16 rdp_load_persistent_key_list(rdpRdp* rdp, UINT64** pKeyList)
{
UINT16 keyCount = 0;
UINT64* keyList = nullptr;
rdpPersistentCache* persistent = nullptr;
rdpSettings* settings = rdp->settings;
*pKeyList = nullptr;
if (!freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
return 0;
if (!settings->BitmapCachePersistFile)
return 0;
persistent = persistent_cache_new();
if (!persistent)
return 0;
const int status =
persistent_cache_open(persistent, settings->BitmapCachePersistFile, FALSE, 0);
if (status < 1)
goto error;
{
const int count = persistent_cache_get_count(persistent);
if ((count < 0) || (count > UINT16_MAX))
goto error;
keyCount = (UINT16)count;
keyList = (UINT64*)calloc(keyCount, sizeof(UINT64));
if (!keyList)
goto error;
for (int index = 0; index < count; index++)
{
PERSISTENT_CACHE_ENTRY cacheEntry = WINPR_C_ARRAY_INIT;
if (persistent_cache_read_entry(persistent, &cacheEntry) < 1)
continue;
keyList[index] = cacheEntry.key64;
}
}
*pKeyList = keyList;
persistent_cache_free(persistent);
return keyCount;
error:
persistent_cache_free(persistent);
free(keyList);
return 0;
}
BOOL rdp_send_client_persistent_key_list_pdu(rdpRdp* rdp)
{
UINT16 keyMaxFrag = 2042;
UINT64* keyList = nullptr;
RDP_BITMAP_PERSISTENT_INFO info = WINPR_C_ARRAY_INIT;
WINPR_ASSERT(rdp);
rdpSettings* settings = rdp->settings;
UINT16 keyCount = rdp_load_persistent_key_list(rdp, &keyList);
WLog_DBG(TAG, "Persistent Key List: TotalKeyCount: %" PRIu16 " MaxKeyFrag: %" PRIu16, keyCount,
keyMaxFrag);
// MS-RDPBCGR recommends sending no more than 169 entries at once.
// In practice, sending more than 2042 entries at once triggers an error.
// It should be possible to advertise the entire client bitmap cache
// by sending multiple persistent key list PDUs, but the current code
// only bothers sending a single, smaller list of entries instead.
if (keyCount > keyMaxFrag)
keyCount = keyMaxFrag;
WINPR_ASSERT(settings->BitmapCacheV2CellInfo[0].numEntries <= UINT16_MAX);
info.totalEntriesCache0 = (UINT16)settings->BitmapCacheV2CellInfo[0].numEntries;
WINPR_ASSERT(settings->BitmapCacheV2CellInfo[1].numEntries <= UINT16_MAX);
info.totalEntriesCache1 = (UINT16)settings->BitmapCacheV2CellInfo[1].numEntries;
WINPR_ASSERT(settings->BitmapCacheV2CellInfo[2].numEntries <= UINT16_MAX);
info.totalEntriesCache2 = (UINT16)settings->BitmapCacheV2CellInfo[2].numEntries;
WINPR_ASSERT(settings->BitmapCacheV2CellInfo[3].numEntries <= UINT16_MAX);
info.totalEntriesCache3 = (UINT16)settings->BitmapCacheV2CellInfo[3].numEntries;
WINPR_ASSERT(settings->BitmapCacheV2CellInfo[4].numEntries <= UINT16_MAX);
info.totalEntriesCache4 = (UINT16)settings->BitmapCacheV2CellInfo[4].numEntries;
info.numEntriesCache0 = MIN(keyCount, info.totalEntriesCache0);
keyCount -= info.numEntriesCache0;
info.numEntriesCache1 = MIN(keyCount, info.totalEntriesCache1);
keyCount -= info.numEntriesCache1;
info.numEntriesCache2 = MIN(keyCount, info.totalEntriesCache2);
keyCount -= info.numEntriesCache2;
info.numEntriesCache3 = MIN(keyCount, info.totalEntriesCache3);
keyCount -= info.numEntriesCache3;
info.numEntriesCache4 = MIN(keyCount, info.totalEntriesCache4);
info.totalEntriesCache0 = info.numEntriesCache0;
info.totalEntriesCache1 = info.numEntriesCache1;
info.totalEntriesCache2 = info.numEntriesCache2;
info.totalEntriesCache3 = info.numEntriesCache3;
info.totalEntriesCache4 = info.numEntriesCache4;
keyCount = info.totalEntriesCache0 + info.totalEntriesCache1 + info.totalEntriesCache2 +
info.totalEntriesCache3 + info.totalEntriesCache4;
info.keyCount = keyCount;
info.keyList = keyList;
WLog_DBG(TAG, "persistentKeyList count: %" PRIu32, info.keyCount);
WLog_DBG(TAG,
"numEntriesCache: [0]: %" PRIu16 " [1]: %" PRIu16 " [2]: %" PRIu16 " [3]: %" PRIu16
" [4]: %" PRIu16,
info.numEntriesCache0, info.numEntriesCache1, info.numEntriesCache2,
info.numEntriesCache3, info.numEntriesCache4);
WLog_DBG(TAG,
"totalEntriesCache: [0]: %" PRIu16 " [1]: %" PRIu16 " [2]: %" PRIu16 " [3]: %" PRIu16
" [4]: %" PRIu16,
info.totalEntriesCache0, info.totalEntriesCache1, info.totalEntriesCache2,
info.totalEntriesCache3, info.totalEntriesCache4);
UINT16 sec_flags = 0;
wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
if (!s)
{
free(keyList);
return FALSE;
}
if (!rdp_write_client_persistent_key_list_pdu(s, &info))
{
Stream_Free(s, TRUE);
free(keyList);
return FALSE;
}
WINPR_ASSERT(rdp->mcs);
free(keyList);
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST, rdp->mcs->userId,
sec_flags);
}
BOOL rdp_recv_client_font_list_pdu(wStream* s)
{
WINPR_ASSERT(s);
/* 2.2.1.18 Client Font List PDU */
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return FALSE;
return Stream_SafeSeek(s, 8);
}
BOOL rdp_recv_client_persistent_key_list_pdu(wStream* s)
{
BYTE flags = 0;
size_t count = 0;
size_t total = 0;
UINT16 cache = 0;
WINPR_ASSERT(s);
/* 2.2.1.17.1 Persistent Key List PDU Data (TS_BITMAPCACHE_PERSISTENT_LIST_PDU) */
if (!Stream_CheckAndLogRequiredLength(TAG, s, 21))
{
WLog_ERR(TAG, "short TS_BITMAPCACHE_PERSISTENT_LIST_PDU, need 21 bytes, got %" PRIuz,
Stream_GetRemainingLength(s));
return FALSE;
}
/* Read numEntriesCacheX for variable length data in PDU */
for (size_t x = 0; x < 5; x++)
{
Stream_Read_UINT16(s, cache);
count += cache;
}
/* Skip totalEntriesCacheX */
for (size_t x = 0; x < 5; x++)
{
UINT16 tmp = 0;
Stream_Read_UINT16(s, tmp);
total += tmp;
}
if (total > 262144)
{
WLog_ERR(TAG,
"TS_BITMAPCACHE_PERSISTENT_LIST_PDU::totalEntriesCacheX exceeds 262144 entries");
return FALSE;
}
Stream_Read_UINT8(s, flags);
if ((flags & ~(PERSIST_LAST_PDU | PERSIST_FIRST_PDU)) != 0)
{
WLog_ERR(TAG,
"TS_BITMAPCACHE_PERSISTENT_LIST_PDU::bBitMask has an invalid value of 0x%02" PRIx8,
flags);
return FALSE;
}
/* Skip padding */
if (!Stream_SafeSeek(s, 3))
{
WLog_ERR(TAG, "short TS_BITMAPCACHE_PERSISTENT_LIST_PDU, need 3 bytes, got %" PRIuz,
Stream_GetRemainingLength(s));
return FALSE;
}
/* Skip actual entries sent by client */
if (!Stream_SafeSeek(s, count * sizeof(UINT64)))
{
WLog_ERR(TAG,
"short TS_BITMAPCACHE_PERSISTENT_LIST_PDU, need %" PRIuz " bytes, got %" PRIuz,
count * sizeof(UINT64), Stream_GetRemainingLength(s));
return FALSE;
}
return TRUE;
}
static BOOL rdp_write_client_font_list_pdu(wStream* s, UINT16 flags)
{
WINPR_ASSERT(s);
if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
return FALSE;
Stream_Write_UINT16(s, 0); /* numberFonts (2 bytes) */
Stream_Write_UINT16(s, 0); /* totalNumFonts (2 bytes) */
Stream_Write_UINT16(s, flags); /* listFlags (2 bytes) */
Stream_Write_UINT16(s, 50); /* entrySize (2 bytes) */
return TRUE;
}
BOOL rdp_send_client_font_list_pdu(rdpRdp* rdp, UINT16 flags)
{
UINT16 sec_flags = 0;
wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
if (!s)
return FALSE;
if (!rdp_write_client_font_list_pdu(s, flags))
{
Stream_Free(s, TRUE);
return FALSE;
}
WINPR_ASSERT(rdp->mcs);
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FONT_LIST, rdp->mcs->userId, sec_flags);
}
BOOL rdp_recv_font_map_pdu(rdpRdp* rdp, wStream* s)
{
UINT16 numberEntries = 0;
UINT16 totalNumEntries = 0;
UINT16 mapFlags = 0;
UINT16 entrySize = 0;
WINPR_ASSERT(rdp);
WINPR_ASSERT(rdp->settings);
WINPR_ASSERT(s);
WINPR_ASSERT(!freerdp_settings_get_bool(rdp->settings, FreeRDP_ServerMode));
/* Do not fail here, see https://github.com/FreeRDP/FreeRDP/issues/925 */
if (Stream_CheckAndLogRequiredLength(TAG, s, 8))
{
Stream_Read_UINT16(s, numberEntries); /* numberEntries (2 bytes) */
if (numberEntries != 0)
WLog_WARN(
TAG,
"[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU)::numberEntries != 0 "
"[%" PRIu16 "]",
numberEntries);
Stream_Read_UINT16(s, totalNumEntries); /* totalNumEntries (2 bytes) */
if (totalNumEntries != 0)
WLog_WARN(
TAG,
"[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU)::totalNumEntries != "
"0 [%" PRIu16 "]",
totalNumEntries);
Stream_Read_UINT16(s, mapFlags); /* mapFlags (2 bytes) */
if (mapFlags != (FONTLIST_FIRST | FONTLIST_LAST))
WLog_WARN(
TAG,
"[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU)::mapFlags != 0x0003 "
"(FONTLIST_FIRST | FONTLIST_LAST) "
"[0x%04" PRIx16 "]",
mapFlags);
Stream_Read_UINT16(s, entrySize); /* entrySize (2 bytes) */
if (entrySize != 4)
WLog_WARN(TAG,
"[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU)::entrySize != 4 "
"[%" PRIu16 "]",
entrySize);
}
else
WLog_WARN(TAG,
"[MS-RDPBCGR] 2.2.1.22.1 Font Map PDU Data (TS_FONT_MAP_PDU) paylaod size is "
"0 instead of 8");
return rdp_finalize_set_flag(rdp, FINALIZE_SC_FONT_MAP_PDU);
}
BOOL rdp_send_server_font_map_pdu(rdpRdp* rdp)
{
UINT16 sec_flags = 0;
wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
if (!s)
return FALSE;
if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 8))
{
Stream_Free(s, TRUE);
return FALSE;
}
Stream_Write_UINT16(s, 0); /* numberEntries (2 bytes) */
Stream_Write_UINT16(s, 0); /* totalNumEntries (2 bytes) */
Stream_Write_UINT16(s, FONTLIST_FIRST | FONTLIST_LAST); /* mapFlags (2 bytes) */
Stream_Write_UINT16(s, 4); /* entrySize (2 bytes) */
WINPR_ASSERT(rdp->mcs);
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FONT_MAP, rdp->mcs->userId, sec_flags);
}
BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s)
{
UINT16 lengthSourceDescriptor = 0;
WINPR_ASSERT(rdp);
WINPR_ASSERT(s);
if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE)
{
if (!rdp_finalize_set_flag(rdp, FINALIZE_DEACTIVATE_REACTIVATE))
return FALSE;
rdp->was_deactivated = TRUE;
rdp->deactivated_height = freerdp_settings_get_uint32(rdp->settings, FreeRDP_DesktopHeight);
rdp->deactivated_width = freerdp_settings_get_uint32(rdp->settings, FreeRDP_DesktopWidth);
}
/*
* Windows XP can send short DEACTIVATE_ALL PDU that doesn't contain
* the following fields.
*/
WINPR_ASSERT(rdp->settings);
if (Stream_GetRemainingLength(s) > 0)
{
do
{
UINT32 ShareId = 0;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
break;
Stream_Read_UINT32(s, ShareId); /* shareId (4 bytes) */
if (!freerdp_settings_set_uint32(rdp->settings, FreeRDP_ShareId, ShareId))
return FALSE;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
break;
Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
if (!Stream_CheckAndLogRequiredLength(TAG, s, lengthSourceDescriptor))
break;
Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor (should be 0x00) */
} while (0);
}
return rdp_client_transition_to_state(rdp,
CONNECTION_STATE_CAPABILITIES_EXCHANGE_DEMAND_ACTIVE);
}
BOOL rdp_send_deactivate_all(rdpRdp* rdp)
{
WINPR_ASSERT(rdp);
WINPR_ASSERT(rdp->mcs);
if (rdp->mcs->userId == 0)
{
WLog_Print(rdp->log, WLOG_WARN,
"rdpMcs::userId == 0, skip sending PDU_TYPE_DEACTIVATE_ALL");
return TRUE;
}
UINT16 sec_flags = 0;
wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
BOOL status = FALSE;
if (!s)
return FALSE;
if (!Stream_CheckAndLogRequiredCapacityWLog(rdp->log, (s), 7))
goto fail;
WINPR_ASSERT(rdp->settings);
{
const UINT32 ShareId = freerdp_settings_get_uint32(rdp->settings, FreeRDP_ShareId);
Stream_Write_UINT32(s, ShareId); /* shareId (4 bytes) */
}
Stream_Write_UINT16(s, 1); /* lengthSourceDescriptor (2 bytes) */
Stream_Write_UINT8(s, 0); /* sourceDescriptor (should be 0x00) */
WINPR_ASSERT(rdp->mcs);
status = rdp_send_pdu(rdp, s, PDU_TYPE_DEACTIVATE_ALL, rdp->mcs->userId, sec_flags);
fail:
Stream_Release(s);
return status;
}
BOOL rdp_server_accept_client_control_pdu(rdpRdp* rdp, wStream* s)
{
UINT16 action = 0;
UINT16 GrantId = 0;
UINT32 ControlId = 0;
const CONNECTION_STATE state = rdp_get_state(rdp);
WINPR_ASSERT(rdp);
WINPR_ASSERT(s);
if (!rdp_recv_control_pdu(s, &action, &GrantId, &ControlId))
return FALSE;
switch (action)
{
case CTRLACTION_REQUEST_CONTROL:
if (!rdp_finalize_is_flag_set(rdp, FINALIZE_CS_CONTROL_COOPERATE_PDU))
{
char abuffer[128] = WINPR_C_ARRAY_INIT;
char buffer[1024] = WINPR_C_ARRAY_INIT;
WLog_WARN(TAG,
"Received action=%s with GrantId=0x%04" PRIx16 ", ControlId=0x%08" PRIx32
" in unexpected state %s [missing %s]",
rdp_ctrlaction_string(action, abuffer, sizeof(abuffer)), GrantId,
ControlId, rdp_state_string(state),
rdp_finalize_flags_to_str(FINALIZE_CS_CONTROL_COOPERATE_PDU, buffer,
sizeof(buffer)));
return FALSE;
}
if ((GrantId != 0) || (ControlId != 0))
{
WLog_WARN(TAG,
"Received CTRLACTION_COOPERATE with GrantId=0x%04" PRIx16
" != 0x00, ControlId=0x%08" PRIx32 " != 0x00",
GrantId, ControlId);
return FALSE;
}
return rdp_finalize_set_flag(rdp, FINALIZE_CS_CONTROL_REQUEST_PDU);
case CTRLACTION_COOPERATE:
if (!rdp_finalize_is_flag_set(rdp, FINALIZE_CS_SYNCHRONIZE_PDU))
{
char abuffer[128] = WINPR_C_ARRAY_INIT;
char buffer[1024] = WINPR_C_ARRAY_INIT;
WLog_WARN(
TAG,
"Received action=%s with GrantId=0x%04" PRIx16 ", ControlId=0x%08" PRIx32
" in unexpected state %s [missing %s]",
rdp_ctrlaction_string(action, abuffer, sizeof(abuffer)), GrantId, ControlId,
rdp_state_string(state),
rdp_finalize_flags_to_str(FINALIZE_CS_SYNCHRONIZE_PDU, buffer, sizeof(buffer)));
return FALSE;
}
if ((GrantId != 0) || (ControlId != 0))
{
WLog_WARN(TAG,
"Received CTRLACTION_COOPERATE with GrantId=0x%04" PRIx16
" != 0x00, ControlId=0x%08" PRIx32 " != 0x00",
GrantId, ControlId);
return FALSE;
}
return rdp_finalize_set_flag(rdp, FINALIZE_CS_CONTROL_COOPERATE_PDU);
default:
{
char abuffer[128] = WINPR_C_ARRAY_INIT;
WLog_WARN(TAG,
"Received unexpected action=%s with GrantId=0x%04" PRIx16
", ControlId=0x%08" PRIx32,
rdp_ctrlaction_string(action, abuffer, sizeof(abuffer)), GrantId, ControlId);
return FALSE;
}
}
return TRUE;
}
BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s)
{
WINPR_ASSERT(rdp);
WINPR_ASSERT(s);
if (!rdp_recv_client_font_list_pdu(s))
return FALSE;
rdp_finalize_set_flag(rdp, FINALIZE_CS_FONT_LIST_PDU);
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_FINALIZATION_CLIENT_FONT_MAP))
return FALSE;
if (!rdp_send_server_font_map_pdu(rdp))
return FALSE;
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_ACTIVE))
return FALSE;
return TRUE;
}
BOOL rdp_server_accept_client_persistent_key_list_pdu(rdpRdp* rdp, wStream* s)
{
WINPR_ASSERT(rdp);
WINPR_ASSERT(s);
if (!rdp_recv_client_persistent_key_list_pdu(s))
return FALSE;
rdp_finalize_set_flag(rdp, FINALIZE_CS_PERSISTENT_KEY_LIST_PDU);
// TODO: Actually do something with this
return TRUE;
}
const char* rdp_ctrlaction_string(UINT16 action, char* buffer, size_t size)
{
const char* actstr = nullptr;
switch (action)
{
case CTRLACTION_COOPERATE:
actstr = "CTRLACTION_COOPERATE";
break;
case CTRLACTION_DETACH:
actstr = "CTRLACTION_DETACH";
break;
case CTRLACTION_GRANTED_CONTROL:
actstr = "CTRLACTION_GRANTED_CONTROL";
break;
case CTRLACTION_REQUEST_CONTROL:
actstr = "CTRLACTION_REQUEST_CONTROL";
break;
default:
actstr = "CTRLACTION_UNKNOWN";
break;
}
(void)_snprintf(buffer, size, "%s [0x%04" PRIx16 "]", actstr, action);
return buffer;
}

View File

@@ -0,0 +1,112 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Activation Sequence
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_ACTIVATION_H
#define FREERDP_LIB_CORE_ACTIVATION_H
#include "rdp.h"
#include <freerdp/api.h>
#include <freerdp/settings.h>
#include <freerdp/cache/persistent.h>
#define SYNCMSGTYPE_SYNC 0x0001
typedef enum
{
CTRLACTION_REQUEST_CONTROL = 0x0001,
CTRLACTION_GRANTED_CONTROL = 0x0002,
CTRLACTION_DETACH = 0x0003,
CTRLACTION_COOPERATE = 0x0004
} CTRLACTION;
typedef struct
{
UINT16 numEntriesCache0;
UINT16 numEntriesCache1;
UINT16 numEntriesCache2;
UINT16 numEntriesCache3;
UINT16 numEntriesCache4;
UINT16 totalEntriesCache0;
UINT16 totalEntriesCache1;
UINT16 totalEntriesCache2;
UINT16 totalEntriesCache3;
UINT16 totalEntriesCache4;
UINT32 keyCount;
UINT64* keyList;
} RDP_BITMAP_PERSISTENT_INFO;
#define PERSIST_FIRST_PDU 0x01
#define PERSIST_LAST_PDU 0x02
#define FONTLIST_FIRST 0x0001
#define FONTLIST_LAST 0x0002
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rdp_ctrlaction_string(UINT16 action, char* buffer, size_t size);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_deactivate_all(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_server_synchronize_pdu(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_server_synchronize_pdu(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_client_synchronize_pdu(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_client_synchronize_pdu(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_server_control_pdu(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_server_control_cooperate_pdu(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_client_control_pdu(rdpRdp* rdp, UINT16 action);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_client_persistent_key_list_pdu(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_client_font_list_pdu(rdpRdp* rdp, UINT16 flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_font_map_pdu(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_client_control_pdu(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_client_persistent_key_list_pdu(rdpRdp* rdp, wStream* s);
#endif /* FREERDP_LIB_CORE_ACTIVATION_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Auto-Detect PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_AUTODETECT_H
#define FREERDP_LIB_CORE_AUTODETECT_H
#include "rdp.h"
#include <freerdp/freerdp.h>
#include <freerdp/autodetect.h>
#include <freerdp/log.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
#include <winpr/sysinfo.h>
#include "state.h"
FREERDP_LOCAL void autodetect_free(rdpAutoDetect* autodetect);
WINPR_ATTR_MALLOC(autodetect_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpAutoDetect* autodetect_new(rdpContext* context);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t autodetect_recv_request_packet(rdpAutoDetect* autodetect,
RDP_TRANSPORT_TYPE transport, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t autodetect_recv_response_packet(rdpAutoDetect* autodetect,
RDP_TRANSPORT_TYPE transport, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL FREERDP_AUTODETECT_STATE autodetect_get_state(rdpAutoDetect* autodetect);
FREERDP_LOCAL void autodetect_register_server_callbacks(rdpAutoDetect* autodetect);
FREERDP_LOCAL void autodetect_on_connect_time_auto_detect_begin(rdpAutoDetect* autodetect);
FREERDP_LOCAL void autodetect_on_connect_time_auto_detect_progress(rdpAutoDetect* autodetect);
#define AUTODETECT_TAG FREERDP_TAG("core.autodetect")
#endif /* FREERDP_LIB_CORE_AUTODETECT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Capability Sets
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_CAPABILITIES_H
#define FREERDP_LIB_CORE_CAPABILITIES_H
#include "rdp.h"
#include <freerdp/freerdp.h>
#include <freerdp/constants.h>
#include <freerdp/settings.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
/* Capability Set Types */
#define CAPSET_TYPE_GENERAL 0x0001
#define CAPSET_TYPE_BITMAP 0x0002
#define CAPSET_TYPE_ORDER 0x0003
#define CAPSET_TYPE_BITMAP_CACHE 0x0004
#define CAPSET_TYPE_CONTROL 0x0005
#define CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID 0x0006
#define CAPSET_TYPE_ACTIVATION 0x0007
#define CAPSET_TYPE_POINTER 0x0008
#define CAPSET_TYPE_SHARE 0x0009
#define CAPSET_TYPE_COLOR_CACHE 0x000A
#define CAPSET_TYPE_SOUND 0x000C
#define CAPSET_TYPE_INPUT 0x000D
#define CAPSET_TYPE_FONT 0x000E
#define CAPSET_TYPE_BRUSH 0x000F
#define CAPSET_TYPE_GLYPH_CACHE 0x0010
#define CAPSET_TYPE_OFFSCREEN_CACHE 0x0011
#define CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT 0x0012
#define CAPSET_TYPE_BITMAP_CACHE_V2 0x0013
#define CAPSET_TYPE_VIRTUAL_CHANNEL 0x0014
#define CAPSET_TYPE_DRAW_NINE_GRID_CACHE 0x0015
#define CAPSET_TYPE_DRAW_GDI_PLUS 0x0016
#define CAPSET_TYPE_RAIL 0x0017
#define CAPSET_TYPE_WINDOW 0x0018
#define CAPSET_TYPE_COMP_DESK 0x0019
#define CAPSET_TYPE_MULTI_FRAGMENT_UPDATE 0x001A
#define CAPSET_TYPE_LARGE_POINTER 0x001B
#define CAPSET_TYPE_SURFACE_COMMANDS 0x001C
#define CAPSET_TYPE_BITMAP_CODECS 0x001D
#define CAPSET_TYPE_FRAME_ACKNOWLEDGE 0x001E
#define CAPSET_HEADER_LENGTH 4
#define SOURCE_DESCRIPTOR "FREERDP"
/* Capabilities Protocol Version */
#define CAPS_PROTOCOL_VERSION 0x0200
/* General Capability Flags */
#define FASTPATH_OUTPUT_SUPPORTED 0x0001
#define NO_BITMAP_COMPRESSION_HDR 0x0400
#define LONG_CREDENTIALS_SUPPORTED 0x0004
#define AUTORECONNECT_SUPPORTED 0x0008
#define ENC_SALTED_CHECKSUM 0x0010
/* Drawing Flags */
#define DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY 0x02
#define DRAW_ALLOW_COLOR_SUBSAMPLING 0x04
#define DRAW_ALLOW_SKIP_ALPHA 0x08
/* Order Flags */
#define NEGOTIATE_ORDER_SUPPORT 0x0002
#define ZERO_BOUNDS_DELTA_SUPPORT 0x0008
#define COLOR_INDEX_SUPPORT 0x0020
#define SOLID_PATTERN_BRUSH_ONLY 0x0040
#define ORDER_FLAGS_EXTRA_SUPPORT 0x0080
/* Extended Order Flags */
#define CACHE_BITMAP_V3_SUPPORT 0x0002
#define ALTSEC_FRAME_MARKER_SUPPORT 0x0004
/* Sound Flags */
#define SOUND_BEEPS_FLAG 0x0001
/* Input Flags */
#define INPUT_FLAG_SCANCODES 0x0001
#define INPUT_FLAG_MOUSEX 0x0004
#define INPUT_FLAG_FASTPATH_INPUT 0x0008
#define INPUT_FLAG_UNICODE 0x0010
#define INPUT_FLAG_FASTPATH_INPUT2 0x0020
#define INPUT_FLAG_UNUSED1 0x0040
#define INPUT_FLAG_MOUSE_RELATIVE 0x0080
#define TS_INPUT_FLAG_MOUSE_HWHEEL 0x0100
#define TS_INPUT_FLAG_QOE_TIMESTAMPS 0x0200
/* Font Support Flags */
#define FONTSUPPORT_FONTLIST 0x0001
/* Brush Support Level */
#define BRUSH_DEFAULT 0x00000000
#define BRUSH_COLOR_8x8 0x00000001
#define BRUSH_COLOR_FULL 0x00000002
/* Bitmap Cache Version */
#define BITMAP_CACHE_V2 0x01
/* Bitmap Cache V2 Flags */
#define PERSISTENT_KEYS_EXPECTED_FLAG 0x0001
#define ALLOW_CACHE_WAITING_LIST_FLAG 0x0002
/* Draw Nine Grid Support Level */
#define DRAW_NINEGRID_NO_SUPPORT 0x00000000
#define DRAW_NINEGRID_SUPPORTED 0x00000001
#define DRAW_NINEGRID_SUPPORTED_V2 0x00000002
/* Draw GDI+ Support Level */
#define DRAW_GDIPLUS_DEFAULT 0x00000000
#define DRAW_GDIPLUS_SUPPORTED 0x00000001
/* Draw GDI+ Cache Level */
#define DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT 0x00000000
#define DRAW_GDIPLUS_CACHE_LEVEL_ONE 0x00000001
/* Window Support Level */
#define WINDOW_LEVEL_NOT_SUPPORTED 0x00000000
#define WINDOW_LEVEL_SUPPORTED 0x00000001
#define WINDOW_LEVEL_SUPPORTED_EX 0x00000002
/* Desktop Composition Support Level */
#define COMPDESK_NOT_SUPPORTED 0x0000
#define COMPDESK_SUPPORTED 0x0001
/* Bitmap Codec Constants */
#define CARDP_CAPS_CAPTURE_NON_CAC 0x00000001
#define CBY_CAPS 0xCBC0
#define CBY_CAPSET 0xCBC1
#define CLY_CAPSET 0xCFC0
#define CLW_VERSION_1_0 0x0100
#define CT_TILE_64x64 0x0040
#define CLW_COL_CONV_ICT 0x1
#define CLW_XFORM_DWT_53_A 0x1
#define CLW_ENTROPY_RLGR1 0x01
#define CLW_ENTROPY_RLGR3 0x04
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId,
UINT16* length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_demand_active(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_confirm_active(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type,
rdpSettings* settings, BOOL isServer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len);
#endif /* FREERDP_LIB_CORE_CAPABILITIES_H */

View File

@@ -0,0 +1,321 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Virtual Channels
*
* Copyright 2011 Vic Lee
* Copyright 2015 Copyright 2015 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include "settings.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/stream.h>
#include <winpr/wtsapi.h>
#include <freerdp/freerdp.h>
#include <freerdp/constants.h>
#include <freerdp/log.h>
#include <freerdp/svc.h>
#include <freerdp/peer.h>
#include <freerdp/addin.h>
#include <freerdp/client/channels.h>
#include <freerdp/client/drdynvc.h>
#include <freerdp/channels/channels.h>
#include "rdp.h"
#include "client.h"
#include "server.h"
#include "channels.h"
#define TAG FREERDP_TAG("core.channels")
BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data, size_t size)
{
size_t left = 0;
UINT32 flags = 0;
size_t chunkSize = 0;
rdpMcs* mcs = nullptr;
const rdpMcsChannel* channel = nullptr;
WINPR_ASSERT(rdp);
WINPR_ASSERT(data || (size == 0));
mcs = rdp->mcs;
WINPR_ASSERT(mcs);
for (UINT32 i = 0; i < mcs->channelCount; i++)
{
const rdpMcsChannel* cur = &mcs->channels[i];
if (cur->ChannelId == channelId)
{
channel = cur;
break;
}
}
if (!channel)
{
WLog_ERR(TAG, "freerdp_channel_send: unknown channelId %" PRIu16 "", channelId);
return FALSE;
}
flags = CHANNEL_FLAG_FIRST;
left = size;
while (left > 0)
{
if (left > rdp->settings->VCChunkSize)
{
chunkSize = rdp->settings->VCChunkSize;
}
else
{
chunkSize = left;
flags |= CHANNEL_FLAG_LAST;
}
if (!rdp->settings->ServerMode && (channel->options & CHANNEL_OPTION_SHOW_PROTOCOL))
{
flags |= CHANNEL_FLAG_SHOW_PROTOCOL;
}
if (!freerdp_channel_send_packet(rdp, channelId, size, flags, data, chunkSize))
return FALSE;
data += chunkSize;
left -= chunkSize;
flags = 0;
}
return TRUE;
}
BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId, size_t packetLength)
{
BOOL rc = FALSE;
UINT32 length = 0;
UINT32 flags = 0;
size_t chunkLength = 0;
WINPR_ASSERT(instance);
if (packetLength < 8)
{
WLog_ERR(TAG, "Header length %" PRIuz " bytes promised, none available", packetLength);
return FALSE;
}
packetLength -= 8;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return FALSE;
/* [MS-RDPBCGR] 3.1.5.2.2 Processing of Virtual Channel PDU
* chunked data. Length is the total size of the combined data,
* chunkLength is the actual data received.
* check chunkLength against packetLength, which is the TPKT header size.
*/
Stream_Read_UINT32(s, length);
Stream_Read_UINT32(s, flags);
chunkLength = Stream_GetRemainingLength(s);
if (packetLength != chunkLength)
{
WLog_ERR(TAG, "Header length %" PRIuz " != actual length %" PRIuz, packetLength,
chunkLength);
return FALSE;
}
IFCALLRET(instance->ReceiveChannelData, rc, instance, channelId, Stream_Pointer(s), chunkLength,
flags, length);
if (!rc)
{
WLog_WARN(TAG, "ReceiveChannelData returned %d", rc);
return FALSE;
}
return Stream_SafeSeek(s, chunkLength);
}
BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 channelId)
{
UINT32 length = 0;
UINT32 flags = 0;
WINPR_ASSERT(client);
WINPR_ASSERT(s);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return FALSE;
Stream_Read_UINT32(s, length);
Stream_Read_UINT32(s, flags);
const size_t chunkLength = Stream_GetRemainingLength(s);
if (chunkLength > UINT32_MAX)
return FALSE;
if (client->VirtualChannelRead)
{
int rc = 0;
BOOL found = FALSE;
HANDLE hChannel = nullptr;
rdpContext* context = client->context;
rdpMcs* mcs = context->rdp->mcs;
for (UINT32 index = 0; index < mcs->channelCount; index++)
{
const rdpMcsChannel* mcsChannel = &(mcs->channels[index]);
if (mcsChannel->ChannelId == channelId)
{
hChannel = (HANDLE)mcsChannel->handle;
found = TRUE;
break;
}
}
if (!found)
return FALSE;
rc = client->VirtualChannelRead(client, hChannel, Stream_Pointer(s), (UINT32)chunkLength);
if (rc < 0)
return FALSE;
}
else if (client->ReceiveChannelData)
{
BOOL rc = client->ReceiveChannelData(client, channelId, Stream_Pointer(s),
(UINT32)chunkLength, flags, length);
if (!rc)
return FALSE;
}
if (!Stream_SafeSeek(s, chunkLength))
{
WLog_WARN(TAG, "Short PDU, need %" PRIuz " bytes, got %" PRIuz, chunkLength,
Stream_GetRemainingLength(s));
return FALSE;
}
return TRUE;
}
static const WtsApiFunctionTable FreeRDP_WtsApiFunctionTable = {
0, /* dwVersion */
0, /* dwFlags */
FreeRDP_WTSStopRemoteControlSession, /* StopRemoteControlSession */
FreeRDP_WTSStartRemoteControlSessionW, /* StartRemoteControlSessionW */
FreeRDP_WTSStartRemoteControlSessionA, /* StartRemoteControlSessionA */
FreeRDP_WTSConnectSessionW, /* ConnectSessionW */
FreeRDP_WTSConnectSessionA, /* ConnectSessionA */
FreeRDP_WTSEnumerateServersW, /* EnumerateServersW */
FreeRDP_WTSEnumerateServersA, /* EnumerateServersA */
FreeRDP_WTSOpenServerW, /* OpenServerW */
FreeRDP_WTSOpenServerA, /* OpenServerA */
FreeRDP_WTSOpenServerExW, /* OpenServerExW */
FreeRDP_WTSOpenServerExA, /* OpenServerExA */
FreeRDP_WTSCloseServer, /* CloseServer */
FreeRDP_WTSEnumerateSessionsW, /* EnumerateSessionsW */
FreeRDP_WTSEnumerateSessionsA, /* EnumerateSessionsA */
FreeRDP_WTSEnumerateSessionsExW, /* EnumerateSessionsExW */
FreeRDP_WTSEnumerateSessionsExA, /* EnumerateSessionsExA */
FreeRDP_WTSEnumerateProcessesW, /* EnumerateProcessesW */
FreeRDP_WTSEnumerateProcessesA, /* EnumerateProcessesA */
FreeRDP_WTSTerminateProcess, /* TerminateProcess */
FreeRDP_WTSQuerySessionInformationW, /* QuerySessionInformationW */
FreeRDP_WTSQuerySessionInformationA, /* QuerySessionInformationA */
FreeRDP_WTSQueryUserConfigW, /* QueryUserConfigW */
FreeRDP_WTSQueryUserConfigA, /* QueryUserConfigA */
FreeRDP_WTSSetUserConfigW, /* SetUserConfigW */
FreeRDP_WTSSetUserConfigA, /* SetUserConfigA */
FreeRDP_WTSSendMessageW, /* SendMessageW */
FreeRDP_WTSSendMessageA, /* SendMessageA */
FreeRDP_WTSDisconnectSession, /* DisconnectSession */
FreeRDP_WTSLogoffSession, /* LogoffSession */
FreeRDP_WTSShutdownSystem, /* ShutdownSystem */
FreeRDP_WTSWaitSystemEvent, /* WaitSystemEvent */
FreeRDP_WTSVirtualChannelOpen, /* VirtualChannelOpen */
FreeRDP_WTSVirtualChannelOpenEx, /* VirtualChannelOpenEx */
FreeRDP_WTSVirtualChannelClose, /* VirtualChannelClose */
FreeRDP_WTSVirtualChannelRead, /* VirtualChannelRead */
FreeRDP_WTSVirtualChannelWrite, /* VirtualChannelWrite */
FreeRDP_WTSVirtualChannelPurgeInput, /* VirtualChannelPurgeInput */
FreeRDP_WTSVirtualChannelPurgeOutput, /* VirtualChannelPurgeOutput */
FreeRDP_WTSVirtualChannelQuery, /* VirtualChannelQuery */
FreeRDP_WTSFreeMemory, /* FreeMemory */
FreeRDP_WTSRegisterSessionNotification, /* RegisterSessionNotification */
FreeRDP_WTSUnRegisterSessionNotification, /* UnRegisterSessionNotification */
FreeRDP_WTSRegisterSessionNotificationEx, /* RegisterSessionNotificationEx */
FreeRDP_WTSUnRegisterSessionNotificationEx, /* UnRegisterSessionNotificationEx */
FreeRDP_WTSQueryUserToken, /* QueryUserToken */
FreeRDP_WTSFreeMemoryExW, /* FreeMemoryExW */
FreeRDP_WTSFreeMemoryExA, /* FreeMemoryExA */
FreeRDP_WTSEnumerateProcessesExW, /* EnumerateProcessesExW */
FreeRDP_WTSEnumerateProcessesExA, /* EnumerateProcessesExA */
FreeRDP_WTSEnumerateListenersW, /* EnumerateListenersW */
FreeRDP_WTSEnumerateListenersA, /* EnumerateListenersA */
FreeRDP_WTSQueryListenerConfigW, /* QueryListenerConfigW */
FreeRDP_WTSQueryListenerConfigA, /* QueryListenerConfigA */
FreeRDP_WTSCreateListenerW, /* CreateListenerW */
FreeRDP_WTSCreateListenerA, /* CreateListenerA */
FreeRDP_WTSSetListenerSecurityW, /* SetListenerSecurityW */
FreeRDP_WTSSetListenerSecurityA, /* SetListenerSecurityA */
FreeRDP_WTSGetListenerSecurityW, /* GetListenerSecurityW */
FreeRDP_WTSGetListenerSecurityA, /* GetListenerSecurityA */
FreeRDP_WTSEnableChildSessions, /* EnableChildSessions */
FreeRDP_WTSIsChildSessionsEnabled, /* IsChildSessionsEnabled */
FreeRDP_WTSGetChildSessionId, /* GetChildSessionId */
FreeRDP_WTSGetActiveConsoleSessionId, /* GetActiveConsoleSessionId */
FreeRDP_WTSLogonUser,
FreeRDP_WTSLogoffUser,
FreeRDP_WTSStartRemoteControlSessionExW,
FreeRDP_WTSStartRemoteControlSessionExA
};
const WtsApiFunctionTable* FreeRDP_InitWtsApi(void)
{
return &FreeRDP_WtsApiFunctionTable;
}
BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize, UINT32 flags,
const BYTE* data, size_t chunkSize)
{
if (totalSize > UINT32_MAX)
return FALSE;
UINT16 sec_flags = 0;
wStream* s = rdp_send_stream_init(rdp, &sec_flags);
if (!s)
return FALSE;
if (!Stream_EnsureRemainingCapacity(s, chunkSize + 8))
{
Stream_Release(s);
return FALSE;
}
Stream_Write_UINT32(s, (UINT32)totalSize);
Stream_Write_UINT32(s, flags);
Stream_Write(s, data, chunkSize);
/* WLog_DBG(TAG, "sending data (flags=0x%x size=%d)", flags, size); */
return rdp_send(rdp, s, channelId, sec_flags);
}

View File

@@ -0,0 +1,41 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Virtual Channels
*
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_CHANNELS_H
#define FREERDP_LIB_CORE_CHANNELS_H
#include <freerdp/api.h>
#include "client.h"
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_channel_send(rdpRdp* rdp, UINT16 channelId, const BYTE* data,
size_t size);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize,
UINT32 flags, const BYTE* data, size_t chunkSize);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_channel_process(freerdp* instance, wStream* s, UINT16 channelId,
size_t packetLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_channel_peer_process(freerdp_peer* client, wStream* s, UINT16 channelId);
#endif /* FREERDP_LIB_CORE_CHANNELS_H */

View File

@@ -0,0 +1,572 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Named pipe transport
*
* Copyright 2023-2024 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "tcp.h"
#include <winpr/library.h>
#include <winpr/assert.h>
#include <winpr/print.h>
#include <winpr/sysinfo.h>
#include <freerdp/utils/ringbuffer.h>
#include "childsession.h"
#define TAG FREERDP_TAG("childsession")
typedef struct
{
OVERLAPPED readOverlapped;
HANDLE hFile;
BOOL opInProgress;
BOOL lastOpClosed;
RingBuffer readBuffer;
BOOL blocking;
BYTE tmpReadBuffer[4096];
HANDLE readEvent;
} WINPR_BIO_NAMED;
static int transport_bio_named_uninit(BIO* bio);
static int transport_bio_named_write(BIO* bio, const char* buf, int size)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(buf);
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
if (!buf)
return 0;
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
DWORD written = 0;
const UINT64 start = GetTickCount64();
BOOL ret =
WriteFile(ptr->hFile, buf, WINPR_ASSERTING_INT_CAST(uint32_t, size), &written, nullptr);
// winpr_HexDump(TAG, WLOG_DEBUG, buf, size);
if (!ret)
{
WLog_VRB(TAG, "error or deferred");
return 0;
}
WLog_VRB(TAG, "(%d)=%d written=%" PRIu32 " duration=%" PRIu64, size, ret, written,
GetTickCount64() - start);
if (written == 0)
{
WLog_VRB(TAG, "closed on write");
return 0;
}
WINPR_ASSERT(written <= INT32_MAX);
return (int)written;
}
static BOOL treatReadResult(WINPR_BIO_NAMED* ptr, DWORD readBytes)
{
WLog_VRB(TAG, "treatReadResult(readBytes=%" PRIu32 ")", readBytes);
ptr->opInProgress = FALSE;
if (readBytes == 0)
{
WLog_VRB(TAG, "readBytes == 0");
return TRUE;
}
if (!ringbuffer_write(&ptr->readBuffer, ptr->tmpReadBuffer, readBytes))
{
WLog_VRB(TAG, "ringbuffer_write()");
return FALSE;
}
return SetEvent(ptr->readEvent);
}
static BOOL doReadOp(WINPR_BIO_NAMED* ptr)
{
DWORD readBytes = 0;
if (!ResetEvent(ptr->readEvent))
return FALSE;
ptr->opInProgress = TRUE;
if (!ReadFile(ptr->hFile, ptr->tmpReadBuffer, sizeof(ptr->tmpReadBuffer), &readBytes,
&ptr->readOverlapped))
{
DWORD error = GetLastError();
switch (error)
{
case ERROR_NO_DATA:
WLog_VRB(TAG, "No Data, unexpected");
return TRUE;
case ERROR_IO_PENDING:
WLog_VRB(TAG, "ERROR_IO_PENDING");
return TRUE;
case ERROR_BROKEN_PIPE:
WLog_VRB(TAG, "broken pipe");
ptr->lastOpClosed = TRUE;
return TRUE;
default:
return FALSE;
}
}
return treatReadResult(ptr, readBytes);
}
static int transport_bio_named_read(BIO* bio, char* buf, int size)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(buf);
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
if (!buf)
return 0;
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ);
if (ptr->blocking)
{
while (!ringbuffer_used(&ptr->readBuffer))
{
if (ptr->lastOpClosed)
return 0;
if (ptr->opInProgress)
{
DWORD status = WaitForSingleObjectEx(ptr->readEvent, 500, TRUE);
switch (status)
{
case WAIT_TIMEOUT:
case WAIT_IO_COMPLETION:
continue;
case WAIT_OBJECT_0:
break;
default:
return -1;
}
DWORD readBytes = 0;
if (!GetOverlappedResult(ptr->hFile, &ptr->readOverlapped, &readBytes, FALSE))
{
WLog_ERR(TAG, "GetOverlappedResult blocking(lastError=%" PRIu32 ")",
GetLastError());
return -1;
}
if (!treatReadResult(ptr, readBytes))
{
WLog_ERR(TAG, "treatReadResult blocking");
return -1;
}
}
}
}
else
{
if (ptr->opInProgress)
{
DWORD status = WaitForSingleObject(ptr->readEvent, 0);
switch (status)
{
case WAIT_OBJECT_0:
break;
case WAIT_TIMEOUT:
BIO_set_flags(bio, (BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ));
return -1;
default:
WLog_ERR(TAG, "error WaitForSingleObject(readEvent)=0x%" PRIx32 "", status);
return -1;
}
DWORD readBytes = 0;
if (!GetOverlappedResult(ptr->hFile, &ptr->readOverlapped, &readBytes, FALSE))
{
WLog_ERR(TAG, "GetOverlappedResult non blocking(lastError=%" PRIu32 ")",
GetLastError());
return -1;
}
if (!treatReadResult(ptr, readBytes))
{
WLog_ERR(TAG, "error treatReadResult non blocking");
return -1;
}
}
}
SSIZE_T ret = -1;
if (size >= 0)
{
size_t rsize = ringbuffer_used(&ptr->readBuffer);
if (rsize <= SSIZE_MAX)
ret = MIN(size, (SSIZE_T)rsize);
}
if ((size >= 0) && ret)
{
DataChunk chunks[2] = WINPR_C_ARRAY_INIT;
const int nchunks =
ringbuffer_peek(&ptr->readBuffer, chunks, WINPR_ASSERTING_INT_CAST(size_t, ret));
for (int i = 0; i < nchunks; i++)
{
memcpy(buf, chunks[i].data, chunks[i].size);
buf += chunks[i].size;
}
ringbuffer_commit_read_bytes(&ptr->readBuffer, WINPR_ASSERTING_INT_CAST(size_t, ret));
WLog_VRB(TAG, "(%d)=%" PRIdz " nchunks=%d", size, ret, nchunks);
}
if (!ringbuffer_used(&ptr->readBuffer))
{
if (!ptr->opInProgress && !doReadOp(ptr))
{
WLog_ERR(TAG, "error rearming read");
return -1;
}
}
if (ret <= 0)
BIO_set_flags(bio, (BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ));
WINPR_ASSERT(ret <= INT32_MAX);
return (int)ret;
}
static int transport_bio_named_puts(BIO* bio, const char* str)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(str);
const size_t max = (INT_MAX > SIZE_MAX) ? SIZE_MAX : INT_MAX;
const size_t len = strnlen(str, max);
if (len >= max)
return -1;
return transport_bio_named_write(bio, str, WINPR_ASSERTING_INT_CAST(int, len));
}
static int transport_bio_named_gets(BIO* bio, char* str, int size)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(str);
return transport_bio_named_read(bio, str, size);
}
static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
WINPR_ASSERT(bio);
int status = -1;
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
switch (cmd)
{
case BIO_C_SET_SOCKET:
case BIO_C_GET_SOCKET:
return -1;
case BIO_C_GET_EVENT:
if (!BIO_get_init(bio) || !arg2)
return 0;
*((HANDLE*)arg2) = ptr->readEvent;
return 1;
case BIO_C_SET_HANDLE:
BIO_set_init(bio, 1);
if (!BIO_get_init(bio) || !arg2)
return 0;
ptr->hFile = (HANDLE)arg2;
ptr->blocking = TRUE;
if (!doReadOp(ptr))
return -1;
return 1;
case BIO_C_SET_NONBLOCK:
{
WLog_DBG(TAG, "BIO_C_SET_NONBLOCK");
ptr->blocking = FALSE;
return 1;
}
case BIO_C_WAIT_READ:
{
WLog_DBG(TAG, "BIO_C_WAIT_READ");
return 1;
}
case BIO_C_WAIT_WRITE:
{
WLog_DBG(TAG, "BIO_C_WAIT_WRITE");
return 1;
}
default:
break;
}
switch (cmd)
{
case BIO_CTRL_GET_CLOSE:
status = BIO_get_shutdown(bio);
break;
case BIO_CTRL_SET_CLOSE:
BIO_set_shutdown(bio, (int)arg1);
status = 1;
break;
case BIO_CTRL_DUP:
status = 1;
break;
case BIO_CTRL_FLUSH:
status = 1;
break;
default:
status = 0;
break;
}
return status;
}
static void BIO_NAMED_free(WINPR_BIO_NAMED* ptr)
{
if (!ptr)
return;
if (ptr->hFile)
{
(void)CloseHandle(ptr->hFile);
ptr->hFile = nullptr;
}
if (ptr->readEvent)
{
(void)CloseHandle(ptr->readEvent);
ptr->readEvent = nullptr;
}
ringbuffer_destroy(&ptr->readBuffer);
free(ptr);
}
static int transport_bio_named_uninit(BIO* bio)
{
WINPR_ASSERT(bio);
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
BIO_NAMED_free(ptr);
BIO_set_init(bio, 0);
BIO_set_flags(bio, 0);
return 1;
}
static int transport_bio_named_new(BIO* bio)
{
WINPR_ASSERT(bio);
WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)calloc(1, sizeof(WINPR_BIO_NAMED));
if (!ptr)
return 0;
if (!ringbuffer_init(&ptr->readBuffer, 0xfffff))
goto error;
ptr->readEvent = CreateEventA(nullptr, TRUE, FALSE, nullptr);
if (!ptr->readEvent || ptr->readEvent == INVALID_HANDLE_VALUE)
goto error;
ptr->readOverlapped.hEvent = ptr->readEvent;
BIO_set_data(bio, ptr);
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
return 1;
error:
BIO_NAMED_free(ptr);
return 0;
}
static int transport_bio_named_free(BIO* bio)
{
WINPR_BIO_NAMED* ptr = nullptr;
if (!bio)
return 0;
transport_bio_named_uninit(bio);
ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
if (ptr)
BIO_set_data(bio, nullptr);
return 1;
}
static BIO_METHOD* BIO_s_namedpipe(void)
{
static BIO_METHOD* bio_methods = nullptr;
if (bio_methods == nullptr)
{
if (!(bio_methods = BIO_meth_new(BIO_TYPE_NAMEDPIPE, "NamedPipe")))
return nullptr;
BIO_meth_set_write(bio_methods, transport_bio_named_write);
BIO_meth_set_read(bio_methods, transport_bio_named_read);
BIO_meth_set_puts(bio_methods, transport_bio_named_puts);
BIO_meth_set_gets(bio_methods, transport_bio_named_gets);
BIO_meth_set_ctrl(bio_methods, transport_bio_named_ctrl);
BIO_meth_set_create(bio_methods, transport_bio_named_new);
BIO_meth_set_destroy(bio_methods, transport_bio_named_free);
}
return bio_methods;
}
typedef NTSTATUS (*WinStationCreateChildSessionTransportFn)(WCHAR* path, DWORD len);
static BOOL createChildSessionTransport(HANDLE* pFile)
{
WINPR_ASSERT(pFile);
HANDLE hModule = nullptr;
BOOL ret = FALSE;
*pFile = INVALID_HANDLE_VALUE;
BOOL childEnabled = 0;
if (!WTSIsChildSessionsEnabled(&childEnabled))
{
WLog_ERR(TAG, "error when calling WTSIsChildSessionsEnabled");
goto out;
}
if (!childEnabled)
{
WLog_INFO(TAG, "child sessions aren't enabled");
if (!WTSEnableChildSessions(TRUE))
{
WLog_ERR(TAG, "error when calling WTSEnableChildSessions");
goto out;
}
WLog_INFO(TAG, "successfully enabled child sessions");
}
hModule = LoadLibraryA("winsta.dll");
if (!hModule)
return FALSE;
{
WCHAR pipePath[0x80] = WINPR_C_ARRAY_INIT;
char pipePathA[0x80] = WINPR_C_ARRAY_INIT;
{
WinStationCreateChildSessionTransportFn createChildSessionFn =
GetProcAddressAs(hModule, "WinStationCreateChildSessionTransport",
WinStationCreateChildSessionTransportFn);
if (!createChildSessionFn)
{
WLog_ERR(TAG, "unable to retrieve WinStationCreateChildSessionTransport function");
goto out;
}
{
HRESULT hStatus = createChildSessionFn(pipePath, 0x80);
if (!SUCCEEDED(hStatus))
{
WLog_ERR(TAG, "error 0x%08x when creating childSessionTransport",
WINPR_CXX_COMPAT_CAST(unsigned, hStatus));
goto out;
}
}
}
{
const BYTE startOfPath[] = { '\\', 0, '\\', 0, '.', 0, '\\', 0 };
if (_wcsncmp(pipePath, (const WCHAR*)startOfPath, 4))
{
/* when compiled under 32 bits, the path may miss "\\.\" at the beginning of the
* string so add it if it's not there
*/
size_t len = _wcslen(pipePath);
if (len > 0x80 - (4 + 1))
{
WLog_ERR(TAG, "pipePath is too long to be adjusted");
goto out;
}
memmove(pipePath + 4, pipePath, (len + 1) * sizeof(WCHAR));
memcpy(pipePath, startOfPath, 8);
}
}
(void)ConvertWCharNToUtf8(pipePath, 0x80, pipePathA, sizeof(pipePathA));
WLog_DBG(TAG, "child session is at '%s'", pipePathA);
{
HANDLE f = CreateFileW(pipePath, GENERIC_READ | GENERIC_WRITE, 0, nullptr,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
if (f == INVALID_HANDLE_VALUE)
{
WLog_ERR(TAG, "error when connecting to local named pipe");
goto out;
}
*pFile = f;
}
}
ret = TRUE;
out:
FreeLibrary(hModule);
return ret;
}
BIO* createChildSessionBio(void)
{
HANDLE f = INVALID_HANDLE_VALUE;
if (!createChildSessionTransport(&f))
return nullptr;
BIO* lowLevelBio = BIO_new(BIO_s_namedpipe());
if (!lowLevelBio)
{
(void)CloseHandle(f);
return nullptr;
}
BIO_set_handle(lowLevelBio, f);
BIO* bufferedBio = BIO_new(BIO_s_buffered_socket());
if (!bufferedBio)
{
BIO_free_all(lowLevelBio);
return nullptr;
}
bufferedBio = BIO_push(bufferedBio, lowLevelBio);
return bufferedBio;
}

View File

@@ -0,0 +1,31 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Connecting to windows child session
*
* Copyright 2023 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_CHILDSESSION_H
#define FREERDP_LIB_CORE_CHILDSESSION_H
#include <winpr/wtypes.h>
#include <freerdp/api.h>
#include <openssl/bio.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BIO* createChildSessionBio(void);
#endif /* FREERDP_LIB_CORE_CHILDSESSION_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,138 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Client Channels
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_CLIENT_H
#define FREERDP_LIB_CORE_CLIENT_H
#include <winpr/crt.h>
#include <winpr/stream.h>
#include <winpr/wtsapi.h>
#include <freerdp/freerdp.h>
#include <freerdp/constants.h>
#include <freerdp/svc.h>
#include <freerdp/peer.h>
#include <freerdp/addin.h>
#include <freerdp/api.h>
#include <freerdp/client/channels.h>
#include <freerdp/client/drdynvc.h>
#include <freerdp/channels/channels.h>
#ifndef CHANNEL_MAX_COUNT
#define CHANNEL_MAX_COUNT 30
#endif
typedef struct
{
WINPR_ATTR_NODISCARD PVIRTUALCHANNELENTRY entry;
WINPR_ATTR_NODISCARD PVIRTUALCHANNELENTRYEX entryEx;
PCHANNEL_INIT_EVENT_FN pChannelInitEventProc;
PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx;
void* pInitHandle;
void* lpUserParam;
} CHANNEL_CLIENT_DATA;
typedef struct
{
char name[CHANNEL_NAME_LEN + 1];
uint32_t OpenHandle;
ULONG options;
int flags;
void* pInterface;
rdpChannels* channels;
void* lpUserParam;
PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc;
PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx;
} CHANNEL_OPEN_DATA;
typedef struct
{
void* Data;
UINT32 DataLength;
void* UserData;
CHANNEL_OPEN_DATA* pChannelOpenData;
} CHANNEL_OPEN_EVENT;
/**
* pInitHandle: handle that identifies the client connection
* Obtained by the client with VirtualChannelInit
* Used by the client with VirtualChannelOpen
*/
typedef struct
{
rdpChannels* channels;
void* pInterface;
} CHANNEL_INIT_DATA;
struct rdp_channels
{
int clientDataCount;
CHANNEL_CLIENT_DATA clientDataList[CHANNEL_MAX_COUNT];
int openDataCount;
CHANNEL_OPEN_DATA openDataList[CHANNEL_MAX_COUNT];
int initDataCount;
CHANNEL_INIT_DATA initDataList[CHANNEL_MAX_COUNT];
/* control for entry into MyVirtualChannelInit */
int can_call_init;
/* true once freerdp_channels_post_connect is called */
BOOL connected;
/* used for locating the channels for a given instance */
freerdp* instance;
wMessageQueue* queue;
DrdynvcClientContext* drdynvc;
CRITICAL_SECTION channelsLock;
wHashTable* channelEvents;
};
FREERDP_LOCAL void freerdp_channels_free(rdpChannels* channels);
WINPR_ATTR_MALLOC(freerdp_channels_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpChannels* freerdp_channels_new(freerdp* instance);
FREERDP_LOCAL UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance);
FREERDP_LOCAL void freerdp_channels_close(rdpChannels* channels, freerdp* instance);
FREERDP_LOCAL void freerdp_channels_register_instance(rdpChannels* channels, freerdp* instance);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL UINT freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL UINT freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance);
/** @since version 3.9.0 */
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SSIZE_T freerdp_client_channel_get_registered_event_handles(rdpChannels* channels,
HANDLE* events,
DWORD count);
#endif /* FREERDP_LIB_CORE_CLIENT_H */

View File

@@ -0,0 +1,296 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Codecs
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <winpr/assert.h>
#include "rdp.h"
#include <freerdp/codecs.h>
#define TAG FREERDP_TAG("core.codecs")
static void codecs_free_int(rdpCodecs* codecs, UINT32 flags)
{
WINPR_ASSERT(codecs);
if (flags & FREERDP_CODEC_REMOTEFX)
{
if (codecs->rfx)
{
rfx_context_free(codecs->rfx);
codecs->rfx = nullptr;
}
}
if (flags & FREERDP_CODEC_NSCODEC)
{
if (codecs->nsc)
{
nsc_context_free(codecs->nsc);
codecs->nsc = nullptr;
}
}
#ifdef WITH_GFX_H264
if (flags & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444))
{
if (codecs->h264)
{
h264_context_free(codecs->h264);
codecs->h264 = nullptr;
}
}
#endif
if (flags & FREERDP_CODEC_CLEARCODEC)
{
if (codecs->clear)
{
clear_context_free(codecs->clear);
codecs->clear = nullptr;
}
}
if (flags & FREERDP_CODEC_PROGRESSIVE)
{
if (codecs->progressive)
{
progressive_context_free(codecs->progressive);
codecs->progressive = nullptr;
}
}
if (flags & FREERDP_CODEC_PLANAR)
{
if (codecs->planar)
{
freerdp_bitmap_planar_context_free(codecs->planar);
codecs->planar = nullptr;
}
}
if (flags & FREERDP_CODEC_INTERLEAVED)
{
if (codecs->interleaved)
{
bitmap_interleaved_context_free(codecs->interleaved);
codecs->interleaved = nullptr;
}
}
}
BOOL freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags, UINT32 width, UINT32 height)
{
codecs_free_int(codecs, flags);
if ((flags & FREERDP_CODEC_INTERLEAVED))
{
if (!(codecs->interleaved = bitmap_interleaved_context_new(FALSE)))
{
WLog_ERR(TAG, "Failed to create interleaved codec context");
return FALSE;
}
}
if ((flags & FREERDP_CODEC_PLANAR))
{
if (!(codecs->planar = freerdp_bitmap_planar_context_new(0, 64, 64)))
{
WLog_ERR(TAG, "Failed to create planar bitmap codec context");
return FALSE;
}
}
if ((flags & FREERDP_CODEC_NSCODEC))
{
if (!(codecs->nsc = nsc_context_new()))
{
WLog_ERR(TAG, "Failed to create nsc codec context");
return FALSE;
}
}
if ((flags & FREERDP_CODEC_REMOTEFX))
{
if (!(codecs->rfx = rfx_context_new_ex(FALSE, codecs->ThreadingFlags)))
{
WLog_ERR(TAG, "Failed to create rfx codec context");
return FALSE;
}
}
if ((flags & FREERDP_CODEC_CLEARCODEC))
{
if (!(codecs->clear = clear_context_new(FALSE)))
{
WLog_ERR(TAG, "Failed to create clear codec context");
return FALSE;
}
}
if (flags & FREERDP_CODEC_ALPHACODEC)
{
}
if ((flags & FREERDP_CODEC_PROGRESSIVE))
{
if (!(codecs->progressive = progressive_context_new_ex(FALSE, codecs->ThreadingFlags)))
{
WLog_ERR(TAG, "Failed to create progressive codec context");
return FALSE;
}
}
#ifdef WITH_GFX_H264
if ((flags & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
{
if (!(codecs->h264 = h264_context_new(FALSE)))
{
WLog_WARN(TAG, "Failed to create h264 codec context");
}
}
#endif
return freerdp_client_codecs_reset(codecs, flags, width, height);
}
BOOL freerdp_client_codecs_reset(rdpCodecs* codecs, UINT32 flags, UINT32 width, UINT32 height)
{
BOOL rc = TRUE;
if (flags & FREERDP_CODEC_INTERLEAVED)
{
if (codecs->interleaved)
{
rc &= bitmap_interleaved_context_reset(codecs->interleaved);
}
}
if (flags & FREERDP_CODEC_PLANAR)
{
if (codecs->planar)
{
rc &= freerdp_bitmap_planar_context_reset(codecs->planar, width, height);
}
}
if (flags & FREERDP_CODEC_NSCODEC)
{
if (codecs->nsc)
{
rc &= nsc_context_reset(codecs->nsc, width, height);
}
}
if (flags & FREERDP_CODEC_REMOTEFX)
{
if (codecs->rfx)
{
rc &= rfx_context_reset(codecs->rfx, width, height);
}
}
if (flags & FREERDP_CODEC_CLEARCODEC)
{
if (codecs->clear)
{
rc &= clear_context_reset(codecs->clear);
}
}
if (flags & FREERDP_CODEC_ALPHACODEC)
{
}
if (flags & FREERDP_CODEC_PROGRESSIVE)
{
if (codecs->progressive)
{
rc &= progressive_context_reset(codecs->progressive);
}
}
#ifdef WITH_GFX_H264
if (flags & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444))
{
if (codecs->h264)
{
rc &= h264_context_reset(codecs->h264, width, height);
}
}
#endif
return rc;
}
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
rdpCodecs* codecs_new(rdpContext* context)
{
if (!context || !context->settings)
return nullptr;
const UINT32 flags = freerdp_settings_get_uint32(context->settings, FreeRDP_ThreadingFlags);
return freerdp_client_codecs_new(flags);
}
void codecs_free(rdpCodecs* codecs)
{
freerdp_client_codecs_free(codecs);
}
#endif
rdpCodecs* freerdp_client_codecs_new(UINT32 ThreadingFlags)
{
rdpCodecs* codecs = (rdpCodecs*)calloc(1, sizeof(rdpCodecs));
if (!codecs)
return nullptr;
codecs->ThreadingFlags = ThreadingFlags;
return codecs;
}
void freerdp_client_codecs_free(rdpCodecs* codecs)
{
if (!codecs)
return;
codecs_free_int(codecs, FREERDP_CODEC_ALL);
free(codecs);
}
const char* freerdp_codec_id_to_str(UINT32 id)
{
#define ENTRY(x) \
case x: \
return #x
switch (id)
{
ENTRY(RDP_CODEC_ID_NONE);
ENTRY(RDP_CODEC_ID_NSCODEC);
ENTRY(RDP_CODEC_ID_JPEG);
ENTRY(RDP_CODEC_ID_REMOTEFX);
ENTRY(RDP_CODEC_ID_IMAGE_REMOTEFX);
default:
return "RDP_CODEC_ID_UNKNOWN";
}
#undef ENTRY
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Connection Sequence
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_CONNECTION_H
#define FREERDP_LIB_CORE_CONNECTION_H
#include "rdp.h"
#include "tpkt.h"
#include "tpdu.h"
#include "nego.h"
#include "mcs.h"
#include "activation.h"
#include "state.h"
#include <freerdp/settings.h>
#include <freerdp/api.h>
enum CLIENT_CONNECTION_STATE
{
CLIENT_STATE_INITIAL,
CLIENT_STATE_PRECONNECT_PASSED,
CLIENT_STATE_POSTCONNECT_PASSED
};
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_connect(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_disconnect(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_disconnect_and_clear(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_reconnect(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_redirect(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_skip_mcs_channel_join(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s, DWORD logLevel);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_client_connect_license(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_client_connect_confirm_active(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_client_connect_finalize(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_client_transition_to_state(rdpRdp* rdp, CONNECTION_STATE state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL CONNECTION_STATE rdp_get_state(const rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rdp_state_string(CONNECTION_STATE state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_is_active_state(const rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_mcs_erect_domain_request(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_mcs_attach_user_request(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_mcs_channel_join_request(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_reactivate(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_server_transition_to_state(rdpRdp* rdp, CONNECTION_STATE state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rdp_get_state_string(const rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rdp_client_connection_state_string(UINT state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_channels_from_mcs(rdpSettings* settings, const rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_handle_message_channel(rdpRdp* rdp, wStream* s, UINT16 channelId,
UINT16 length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_handle_optional_rdp_decryption(rdpRdp* rdp, wStream* s, UINT16* length,
UINT16* pSecurityFlags);
#endif /* FREERDP_LIB_CORE_CONNECTION_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,102 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
*
* Copyright 2022 Isaac Klein <fifthdegree@protonmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_CREDSSP_AUTH_H
#define FREERDP_LIB_CORE_CREDSSP_AUTH_H
#define CREDSSP_AUTH_PKG_SPNEGO "Negotiate"
#define CREDSSP_AUTH_PKG_NTLM "NTLM"
#define CREDSSP_AUTH_PKG_KERBEROS "Kerberos"
#define CREDSSP_AUTH_PKG_SCHANNEL "Schannel"
typedef struct rdp_credssp_auth rdpCredsspAuth;
#include <freerdp/freerdp.h>
#include <winpr/tchar.h>
#include <winpr/sspi.h>
#include <winpr/secapi.h>
FREERDP_LOCAL void credssp_auth_free(rdpCredsspAuth* auth);
WINPR_ATTR_MALLOC(credssp_auth_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpCredsspAuth* credssp_auth_new(const rdpContext* context);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_init(rdpCredsspAuth* auth, TCHAR* pkg_name,
SecPkgContext_Bindings* bindings);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_setup_client(rdpCredsspAuth* auth, const char* target_service,
const char* target_hostname,
const SEC_WINNT_AUTH_IDENTITY* identity,
const char* pkinit);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_setup_server(rdpCredsspAuth* auth);
FREERDP_LOCAL void credssp_auth_set_flags(rdpCredsspAuth* auth, ULONG flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int credssp_auth_authenticate(rdpCredsspAuth* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_encrypt(rdpCredsspAuth* auth, const SecBuffer* plaintext,
SecBuffer* ciphertext, size_t* signature_length,
ULONG sequence);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_decrypt(rdpCredsspAuth* auth, const SecBuffer* ciphertext,
SecBuffer* plaintext, ULONG sequence);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_impersonate(rdpCredsspAuth* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_revert_to_self(rdpCredsspAuth* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_set_spn(rdpCredsspAuth* auth, const char* service,
const char* hostname);
FREERDP_LOCAL void credssp_auth_take_input_buffer(rdpCredsspAuth* auth, SecBuffer* buffer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const SecBuffer* credssp_auth_get_output_buffer(const rdpCredsspAuth* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_have_output_token(rdpCredsspAuth* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL credssp_auth_is_complete(const rdpCredsspAuth* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* credssp_auth_pkg_name(const rdpCredsspAuth* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t credssp_auth_trailer_size(const rdpCredsspAuth* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL INT32 credssp_auth_sspi_error(const rdpCredsspAuth* auth);
FREERDP_LOCAL void credssp_auth_tableAndContext(rdpCredsspAuth* auth,
SecurityFunctionTable** ptable,
CtxtHandle* pcontext);
#endif /* FREERDP_LIB_CORE_CREDSSP_AUTH_H */

View File

@@ -0,0 +1,91 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Display update notifications
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "display.h"
static BOOL display_write_monitor_layout_pdu(wStream* s, UINT32 monitorCount,
const MONITOR_DEF* monitorDefArray)
{
if (!Stream_EnsureRemainingCapacity(s, 4 + (monitorCount * 20)))
return FALSE;
Stream_Write_UINT32(s, monitorCount); /* monitorCount (4 bytes) */
for (UINT32 index = 0; index < monitorCount; index++)
{
const MONITOR_DEF* monitor = &monitorDefArray[index];
Stream_Write_INT32(s, monitor->left); /* left (4 bytes) */
Stream_Write_INT32(s, monitor->top); /* top (4 bytes) */
Stream_Write_INT32(s, monitor->right); /* right (4 bytes) */
Stream_Write_INT32(s, monitor->bottom); /* bottom (4 bytes) */
Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */
}
return TRUE;
}
BOOL display_convert_rdp_monitor_to_monitor_def(UINT32 monitorCount,
const rdpMonitor* monitorDefArray,
MONITOR_DEF** result)
{
MONITOR_DEF* mdef = nullptr;
if (!monitorDefArray || !result || (*result))
return FALSE;
mdef = (MONITOR_DEF*)calloc(monitorCount, sizeof(MONITOR_DEF));
if (!mdef)
return FALSE;
for (UINT32 index = 0; index < monitorCount; index++)
{
const rdpMonitor* monitor = &monitorDefArray[index];
MONITOR_DEF* current = &mdef[index];
current->left = monitor->x; /* left (4 bytes) */
current->top = monitor->y; /* top (4 bytes) */
current->right = monitor->x + monitor->width - 1; /* right (4 bytes) */
current->bottom = monitor->y + monitor->height - 1; /* bottom (4 bytes) */
current->flags = monitor->is_primary ? MONITOR_PRIMARY : 0x0; /* flags (4 bytes) */
}
*result = mdef;
return TRUE;
}
BOOL freerdp_display_send_monitor_layout(rdpContext* context, UINT32 monitorCount,
const MONITOR_DEF* monitorDefArray)
{
rdpRdp* rdp = context->rdp;
UINT16 sec_flags = 0;
wStream* st = rdp_data_pdu_init(rdp, &sec_flags);
if (!st)
return FALSE;
if (!display_write_monitor_layout_pdu(st, monitorCount, monitorDefArray))
{
Stream_Release(st);
return FALSE;
}
return rdp_send_data_pdu(rdp, st, DATA_PDU_TYPE_MONITOR_LAYOUT, 0, sec_flags);
}

View File

@@ -0,0 +1,31 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Display update notifications
*
* Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_DISPLAY_H
#define FREERDP_LIB_CORE_DISPLAY_H
#include <freerdp/display.h>
#include "rdp.h"
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL display_convert_rdp_monitor_to_monitor_def(UINT32 monitorCount,
const rdpMonitor* monitorDefArray,
MONITOR_DEF** result);
#endif /* FREERDP_LIB_CORE_DISPLAY_H */

View File

@@ -0,0 +1,85 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Error Base
*
* Copyright 2015 Armin Novak <armin.novak@thincast.com>
* Copyright 2015 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <stdio.h>
#include <freerdp/log.h>
#include "errinfo.h"
#define ERRBASE_DEFINE(_code) \
{ \
ERRBASE_##_code, "ERRBASE_" #_code, ERRBASE_##_code##_STRING, "" \
}
/* Protocol-independent codes */
/* Special codes */
#define ERRBASE_SUCCESS_STRING "Success."
#define ERRBASE_NONE_STRING ""
static const ERRINFO ERRBASE_CODES[] = { ERRBASE_DEFINE(SUCCESS),
ERRBASE_DEFINE(NONE) };
const char* freerdp_get_error_base_string(UINT32 code)
{
for (size_t x = 0; x < ARRAYSIZE(ERRBASE_CODES); x++)
{
const ERRINFO* errInfo = &ERRBASE_CODES[x];
if (code == errInfo->code)
{
return errInfo->info;
}
}
return "ERRBASE_UNKNOWN";
}
const char* freerdp_get_error_base_category(UINT32 code)
{
for (size_t x = 0; x < ARRAYSIZE(ERRBASE_CODES); x++)
{
const ERRINFO* errInfo = &ERRBASE_CODES[x];
if (code == errInfo->code)
{
return errInfo->category;
}
}
return "ERRBASE_UNKNOWN";
}
const char* freerdp_get_error_base_name(UINT32 code)
{
for (size_t x = 0; x < ARRAYSIZE(ERRBASE_CODES); x++)
{
const ERRINFO* errInfo = &ERRBASE_CODES[x];
if (code == errInfo->code)
{
return errInfo->name;
}
}
return "ERRBASE_UNKNOWN";
}

View File

@@ -0,0 +1,191 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Error Connect
*
* Copyright 2015 Armin Novak <armin.novak@thincast.com>
* Copyright 2015 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <stdio.h>
#include <freerdp/log.h>
#include "errinfo.h"
#define ERRCONNECT_DEFINE(_code, category) \
{ \
ERRCONNECT_##_code, "ERRCONNECT_" #_code, ERRCONNECT_##_code##_STRING, category \
}
/* Protocol-independent codes */
#define ERRCONNECT_PRE_CONNECT_FAILED_STRING \
"A configuration error prevented a connection to be established."
#define ERRCONNECT_CONNECT_UNDEFINED_STRING "A undefined connection error occurred."
#define ERRCONNECT_POST_CONNECT_FAILED_STRING \
"The connection attempt was aborted due to post connect configuration errors."
#define ERRCONNECT_DNS_ERROR_STRING "The DNS entry could not be resolved."
#define ERRCONNECT_DNS_NAME_NOT_FOUND_STRING "The DNS host name was not found."
#define ERRCONNECT_CONNECT_FAILED_STRING "The connection failed."
#define ERRCONNECT_MCS_CONNECT_INITIAL_ERROR_STRING "The connection failed at initial MCS connect"
#define ERRCONNECT_TLS_CONNECT_FAILED_STRING "The connection failed at TLS connect."
#define ERRCONNECT_AUTHENTICATION_FAILED_STRING "An authentication failure aborted the connection."
#define ERRCONNECT_INSUFFICIENT_PRIVILEGES_STRING \
"Insufficient privileges to establish a connection."
#define ERRCONNECT_CONNECT_CANCELLED_STRING "The connection was cancelled."
#define ERRCONNECT_SECURITY_NEGO_CONNECT_FAILED_STRING \
"The connection failed at negotiating security settings."
#define ERRCONNECT_CONNECT_TRANSPORT_FAILED_STRING "The connection transport layer failed."
#define ERRCONNECT_PASSWORD_EXPIRED_STRING "The password has expired and must be changed."
#define ERRCONNECT_PASSWORD_CERTAINLY_EXPIRED_STRING \
"The password has certainly expired and must be changed."
#define ERRCONNECT_CLIENT_REVOKED_STRING "The client has been revoked."
#define ERRCONNECT_KDC_UNREACHABLE_STRING "The KDC is unreachable."
#define ERRCONNECT_ACCOUNT_DISABLED_STRING "The account is disabled."
#define ERRCONNECT_PASSWORD_MUST_CHANGE_STRING "The password must be changed."
#define ERRCONNECT_LOGON_FAILURE_STRING "Logon failed."
#define ERRCONNECT_WRONG_PASSWORD_STRING "Wrong password supplied."
#define ERRCONNECT_ACCESS_DENIED_STRING "Access denied."
#define ERRCONNECT_ACCOUNT_RESTRICTION_STRING "Account restriction."
#define ERRCONNECT_ACCOUNT_LOCKED_OUT_STRING "Account locked out."
#define ERRCONNECT_ACCOUNT_EXPIRED_STRING "Account expired."
#define ERRCONNECT_LOGON_TYPE_NOT_GRANTED_STRING "Logon type not granted."
#define ERRCONNECT_NO_OR_MISSING_CREDENTIALS_STRING "Credentials invalid or missing."
#define ERRCONNECT_ACTIVATION_TIMEOUT_STRING "Timeout waiting for activation."
#define ERRCONNECT_TARGET_BOOTING_STRING "Starting your VM. It may take up to 5 minutes."
/* Special codes */
#define ERRCONNECT_SUCCESS_STRING "Success."
#define ERRCONNECT_NONE_STRING ""
static const ERRINFO ERRCONNECT_CODES[] = {
ERRCONNECT_DEFINE(SUCCESS, CAT_NONE),
ERRCONNECT_DEFINE(PRE_CONNECT_FAILED, CAT_CONFIG),
ERRCONNECT_DEFINE(CONNECT_UNDEFINED, CAT_USE),
ERRCONNECT_DEFINE(POST_CONNECT_FAILED, CAT_CONFIG),
ERRCONNECT_DEFINE(DNS_ERROR, CAT_USE),
ERRCONNECT_DEFINE(DNS_NAME_NOT_FOUND, CAT_CONFIG),
ERRCONNECT_DEFINE(CONNECT_FAILED, CAT_USE),
ERRCONNECT_DEFINE(MCS_CONNECT_INITIAL_ERROR, CAT_PROTOCOL),
ERRCONNECT_DEFINE(TLS_CONNECT_FAILED, CAT_USE),
ERRCONNECT_DEFINE(AUTHENTICATION_FAILED, CAT_USE),
ERRCONNECT_DEFINE(INSUFFICIENT_PRIVILEGES, CAT_ADMIN),
ERRCONNECT_DEFINE(CONNECT_CANCELLED, CAT_USE),
ERRCONNECT_DEFINE(SECURITY_NEGO_CONNECT_FAILED, CAT_USE),
ERRCONNECT_DEFINE(CONNECT_TRANSPORT_FAILED, CAT_USE),
ERRCONNECT_DEFINE(PASSWORD_EXPIRED, CAT_ADMIN),
ERRCONNECT_DEFINE(PASSWORD_CERTAINLY_EXPIRED, CAT_ADMIN),
ERRCONNECT_DEFINE(CLIENT_REVOKED, CAT_ADMIN),
ERRCONNECT_DEFINE(KDC_UNREACHABLE, CAT_ADMIN),
ERRCONNECT_DEFINE(ACCOUNT_DISABLED, CAT_ADMIN),
ERRCONNECT_DEFINE(PASSWORD_MUST_CHANGE, CAT_ADMIN),
ERRCONNECT_DEFINE(LOGON_FAILURE, CAT_USE),
ERRCONNECT_DEFINE(WRONG_PASSWORD, CAT_USE),
ERRCONNECT_DEFINE(ACCESS_DENIED, CAT_ADMIN),
ERRCONNECT_DEFINE(ACCOUNT_RESTRICTION, CAT_ADMIN),
ERRCONNECT_DEFINE(ACCOUNT_LOCKED_OUT, CAT_ADMIN),
ERRCONNECT_DEFINE(ACCOUNT_EXPIRED, CAT_ADMIN),
ERRCONNECT_DEFINE(LOGON_TYPE_NOT_GRANTED, CAT_ADMIN),
ERRCONNECT_DEFINE(NO_OR_MISSING_CREDENTIALS, CAT_USE),
ERRCONNECT_DEFINE(ACTIVATION_TIMEOUT, CAT_PROTOCOL),
ERRCONNECT_DEFINE(TARGET_BOOTING, CAT_ADMIN),
ERRCONNECT_DEFINE(NONE, CAT_NONE)
};
const char* freerdp_get_error_connect_string(UINT32 code)
{
const ERRINFO* errInfo = nullptr;
errInfo = &ERRCONNECT_CODES[0];
while (errInfo->code != ERRCONNECT_NONE)
{
if (code == errInfo->code)
{
return errInfo->info;
}
errInfo++;
}
return "ERRCONNECT_UNKNOWN";
}
const char* freerdp_get_error_connect_category(UINT32 code)
{
const ERRINFO* errInfo = nullptr;
errInfo = &ERRCONNECT_CODES[0];
while (errInfo->code != ERRCONNECT_NONE)
{
if (code == errInfo->code)
{
return errInfo->category;
}
errInfo++;
}
return "ERRCONNECT_UNKNOWN";
}
const char* freerdp_get_error_connect_name(UINT32 code)
{
const ERRINFO* errInfo = nullptr;
errInfo = &ERRCONNECT_CODES[0];
while (errInfo->code != ERRCONNECT_NONE)
{
if (code == errInfo->code)
{
return errInfo->name;
}
errInfo++;
}
return "ERRCONNECT_UNKNOWN";
}

View File

@@ -0,0 +1,698 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Error Info
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <stdio.h>
#include <freerdp/log.h>
#include "errinfo.h"
#define TAG FREERDP_TAG("core")
#define ERRINFO_DEFINE(_code, category) \
{ \
ERRINFO_##_code, "ERRINFO_" #_code, ERRINFO_##_code##_STRING, category \
}
/* Protocol-independent codes */
#define ERRINFO_RPC_INITIATED_DISCONNECT_STRING \
"The disconnection was initiated by an administrative tool on the server in another session."
#define ERRINFO_RPC_INITIATED_LOGOFF_STRING \
"The disconnection was due to a forced logoff initiated by an administrative tool on the " \
"server in another session."
#define ERRINFO_IDLE_TIMEOUT_STRING "The idle session limit timer on the server has elapsed."
#define ERRINFO_LOGON_TIMEOUT_STRING "The active session limit timer on the server has elapsed."
#define ERRINFO_DISCONNECTED_BY_OTHER_CONNECTION_STRING \
"Another user connected to the server, forcing the disconnection of the current connection."
#define ERRINFO_OUT_OF_MEMORY_STRING "The server ran out of available memory resources."
#define ERRINFO_SERVER_DENIED_CONNECTION_STRING "The server denied the connection."
#define ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES_STRING \
"The user cannot connect to the server due to insufficient access privileges."
#define ERRINFO_SERVER_FRESH_CREDENTIALS_REQUIRED_STRING \
"The server does not accept saved user credentials and requires that the user enter their " \
"credentials for each connection."
#define ERRINFO_RPC_INITIATED_DISCONNECT_BY_USER_STRING \
"The disconnection was initiated by an administrative tool on the server running in the " \
"user's session."
#define ERRINFO_LOGOFF_BY_USER_STRING \
"The disconnection was initiated by the user logging off their session on the server."
#define ERRINFO_CLOSE_STACK_ON_DRIVER_NOT_READY_STRING \
"The display driver in the remote session did not report any status within the time allotted " \
"for startup."
#define ERRINFO_SERVER_DWM_CRASH_STRING \
"The DWM process running in the remote session terminated unexpectedly."
#define ERRINFO_CLOSE_STACK_ON_DRIVER_FAILURE_STRING \
"The display driver in the remote session was unable to complete all the tasks required for " \
"startup."
#define ERRINFO_CLOSE_STACK_ON_DRIVER_IFACE_FAILURE_STRING \
"The display driver in the remote session started up successfully, but due to internal " \
"failures was not usable by the remoting stack."
#define ERRINFO_SERVER_WINLOGON_CRASH_STRING \
"The Winlogon process running in the remote session terminated unexpectedly."
#define ERRINFO_SERVER_CSRSS_CRASH_STRING \
"The CSRSS process running in the remote session terminated unexpectedly."
/* Protocol-independent codes generated by the Connection Broker */
#define ERRINFO_CB_DESTINATION_NOT_FOUND_STRING "The target endpoint could not be found."
#define ERRINFO_CB_LOADING_DESTINATION_STRING \
"The target endpoint to which the client is being redirected is disconnecting from the " \
"Connection Broker."
#define ERRINFO_CB_REDIRECTING_TO_DESTINATION_STRING \
"An error occurred while the connection was being redirected to the target endpoint."
#define ERRINFO_CB_SESSION_ONLINE_VM_WAKE_STRING \
"An error occurred while the target endpoint (a virtual machine) was being awakened."
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT_STRING \
"An error occurred while the target endpoint (a virtual machine) was being started."
#define ERRINFO_CB_SESSION_ONLINE_VM_NO_DNS_STRING \
"The IP address of the target endpoint (a virtual machine) cannot be determined."
#define ERRINFO_CB_DESTINATION_POOL_NOT_FREE_STRING \
"There are no available endpoints in the pool managed by the Connection Broker."
#define ERRINFO_CB_CONNECTION_CANCELLED_STRING "Processing of the connection has been cancelled."
#define ERRINFO_CB_CONNECTION_ERROR_INVALID_SETTINGS_STRING \
"The settings contained in the routingToken field of the X.224 Connection Request PDU " \
"(section 2.2.1.1) cannot be validated."
#define ERRINFO_CB_SESSION_ONLINE_VM_BOOT_TIMEOUT_STRING \
"A time-out occurred while the target endpoint (a virtual machine) was being started."
#define ERRINFO_CB_SESSION_ONLINE_VM_SESSMON_FAILED_STRING \
"A session monitoring error occurred while the target endpoint (a virtual machine) was being " \
"started."
/* Protocol-independent licensing codes */
#define ERRINFO_LICENSE_INTERNAL_STRING \
"An internal error has occurred in the Terminal Services licensing component."
#define ERRINFO_LICENSE_NO_LICENSE_SERVER_STRING \
"A Remote Desktop License Server ([MS-RDPELE] section 1.1) could not be found to provide a " \
"license."
#define ERRINFO_LICENSE_NO_LICENSE_STRING \
"There are no Client Access Licenses ([MS-RDPELE] section 1.1) available for the target " \
"remote computer."
#define ERRINFO_LICENSE_BAD_CLIENT_MSG_STRING \
"The remote computer received an invalid licensing message from the client."
#define ERRINFO_LICENSE_HWID_DOESNT_MATCH_LICENSE_STRING \
"The Client Access License ([MS-RDPELE] section 1.1) stored by the client has been modified."
#define ERRINFO_LICENSE_BAD_CLIENT_LICENSE_STRING \
"The Client Access License ([MS-RDPELE] section 1.1) stored by the client is in an invalid " \
"format."
#define ERRINFO_LICENSE_CANT_FINISH_PROTOCOL_STRING \
"Network problems have caused the licensing protocol ([MS-RDPELE] section 1.3.3) to be " \
"terminated."
#define ERRINFO_LICENSE_CLIENT_ENDED_PROTOCOL_STRING \
"The client prematurely ended the licensing protocol ([MS-RDPELE] section 1.3.3)."
#define ERRINFO_LICENSE_BAD_CLIENT_ENCRYPTION_STRING \
"A licensing message ([MS-RDPELE] sections 2.2 and 5.1) was incorrectly encrypted."
#define ERRINFO_LICENSE_CANT_UPGRADE_LICENSE_STRING \
"The Client Access License ([MS-RDPELE] section 1.1) stored by the client could not be " \
"upgraded or renewed."
#define ERRINFO_LICENSE_NO_REMOTE_CONNECTIONS_STRING \
"The remote computer is not licensed to accept remote connections."
/* RDP specific codes */
#define ERRINFO_UNKNOWN_DATA_PDU_TYPE_STRING \
"Unknown pduType2 field in a received Share Data Header (section 2.2.8.1.1.1.2)."
#define ERRINFO_UNKNOWN_PDU_TYPE_STRING \
"Unknown pduType field in a received Share Control Header (section 2.2.8.1.1.1.1)."
#define ERRINFO_DATA_PDU_SEQUENCE_STRING \
"An out-of-sequence Slow-Path Data PDU (section 2.2.8.1.1.1.1) has been received."
#define ERRINFO_CONTROL_PDU_SEQUENCE_STRING \
"An out-of-sequence Slow-Path Non-Data PDU (section 2.2.8.1.1.1.1) has been received."
#define ERRINFO_INVALID_CONTROL_PDU_ACTION_STRING \
"A Control PDU (sections 2.2.1.15 and 2.2.1.16) has been received with an invalid action " \
"field."
#define ERRINFO_INVALID_INPUT_PDU_TYPE_STRING \
"(a) A Slow-Path Input Event (section 2.2.8.1.1.3.1.1) has been received with an invalid " \
"messageType field.\n" \
"(b) A Fast-Path Input Event (section 2.2.8.1.2.2) has been received with an invalid " \
"eventCode field."
#define ERRINFO_INVALID_INPUT_PDU_MOUSE_STRING \
"(a) A Slow-Path Mouse Event (section 2.2.8.1.1.3.1.1.3) or Extended Mouse Event " \
"(section 2.2.8.1.1.3.1.1.4) has been received with an invalid pointerFlags field.\n" \
"(b) A Fast-Path Mouse Event (section 2.2.8.1.2.2.3) or Fast-Path Extended Mouse Event " \
"(section 2.2.8.1.2.2.4) has been received with an invalid pointerFlags field."
#define ERRINFO_INVALID_REFRESH_RECT_PDU_STRING \
"An invalid Refresh Rect PDU (section 2.2.11.2) has been received."
#define ERRINFO_CREATE_USER_DATA_FAILED_STRING \
"The server failed to construct the GCC Conference Create Response user data (section " \
"2.2.1.4)."
#define ERRINFO_CONNECT_FAILED_STRING \
"Processing during the Channel Connection phase of the RDP Connection Sequence " \
"(see section 1.3.1.1 for an overview of the RDP Connection Sequence phases) has failed."
#define ERRINFO_CONFIRM_ACTIVE_HAS_WRONG_SHAREID_STRING \
"A Confirm Active PDU (section 2.2.1.13.2) was received from the client with an invalid " \
"shareId field."
#define ERRINFO_CONFIRM_ACTIVE_HAS_WRONG_ORIGINATOR_STRING \
"A Confirm Active PDU (section 2.2.1.13.2) was received from the client with an invalid " \
"originatorId field."
#define ERRINFO_PERSISTENT_KEY_PDU_BAD_LENGTH_STRING \
"There is not enough data to process a Persistent Key List PDU (section 2.2.1.17)."
#define ERRINFO_PERSISTENT_KEY_PDU_ILLEGAL_FIRST_STRING \
"A Persistent Key List PDU (section 2.2.1.17) marked as PERSIST_PDU_FIRST (0x01) was " \
"received after the reception " \
"of a prior Persistent Key List PDU also marked as PERSIST_PDU_FIRST."
#define ERRINFO_PERSISTENT_KEY_PDU_TOO_MANY_TOTAL_KEYS_STRING \
"A Persistent Key List PDU (section 2.2.1.17) was received which specified a total number of " \
"bitmap cache entries larger than 262144."
#define ERRINFO_PERSISTENT_KEY_PDU_TOO_MANY_CACHE_KEYS_STRING \
"A Persistent Key List PDU (section 2.2.1.17) was received which specified an invalid total " \
"number of keys for a bitmap cache " \
"(the number of entries that can be stored within each bitmap cache is specified in the " \
"Revision 1 or 2 Bitmap Cache Capability Set " \
"(section 2.2.7.1.4) that is sent from client to server)."
#define ERRINFO_INPUT_PDU_BAD_LENGTH_STRING \
"There is not enough data to process Input Event PDU Data (section 2.2.8.1.1.3.1) or a " \
"Fast-Path Input Event PDU (section 2.2.8.1.2)."
#define ERRINFO_BITMAP_CACHE_ERROR_PDU_BAD_LENGTH_STRING \
"There is not enough data to process the shareDataHeader, NumInfoBlocks, " \
"Pad1, and Pad2 fields of the Bitmap Cache Error PDU Data ([MS-RDPEGDI] section 2.2.2.3.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT_STRING \
"(a) The dataSignature field of the Fast-Path Input Event PDU (section 2.2.8.1.2) does not " \
"contain enough data.\n" \
"(b) The fipsInformation and dataSignature fields of the Fast-Path Input Event PDU (section " \
"2.2.8.1.2) do not contain enough data."
#define ERRINFO_VCHANNEL_DATA_TOO_SHORT_STRING \
"(a) There is not enough data in the Client Network Data (section 2.2.1.3.4) to read the " \
"virtual channel configuration data.\n" \
"(b) There is not enough data to read a complete Channel PDU Header (section 2.2.6.1.1)."
#define ERRINFO_SHARE_DATA_TOO_SHORT_STRING \
"(a) There is not enough data to process Control PDU Data (section 2.2.1.15.1).\n" \
"(b) There is not enough data to read a complete Share Control Header (section " \
"2.2.8.1.1.1.1).\n" \
"(c) There is not enough data to read a complete Share Data Header (section 2.2.8.1.1.1.2) " \
"of a Slow-Path Data PDU (section 2.2.8.1.1.1.1).\n" \
"(d) There is not enough data to process Font List PDU Data (section 2.2.1.18.1)."
#define ERRINFO_BAD_SUPPRESS_OUTPUT_PDU_STRING \
"(a) There is not enough data to process Suppress Output PDU Data (section 2.2.11.3.1).\n" \
"(b) The allowDisplayUpdates field of the Suppress Output PDU Data (section 2.2.11.3.1) is " \
"invalid."
#define ERRINFO_CONFIRM_ACTIVE_PDU_TOO_SHORT_STRING \
"(a) There is not enough data to read the shareControlHeader, shareId, originatorId, " \
"lengthSourceDescriptor, " \
"and lengthCombinedCapabilities fields of the Confirm Active PDU Data (section " \
"2.2.1.13.2.1).\n" \
"(b) There is not enough data to read the sourceDescriptor, numberCapabilities, pad2Octets, " \
"and capabilitySets " \
"fields of the Confirm Active PDU Data (section 2.2.1.13.2.1)."
#define ERRINFO_CAPABILITY_SET_TOO_SMALL_STRING \
"There is not enough data to read the capabilitySetType and the lengthCapability fields in a " \
"received Capability Set (section 2.2.1.13.1.1.1)."
#define ERRINFO_CAPABILITY_SET_TOO_LARGE_STRING \
"A Capability Set (section 2.2.1.13.1.1.1) has been received with a lengthCapability " \
"field that contains a value greater than the total length of the data received."
#define ERRINFO_NO_CURSOR_CACHE_STRING \
"(a) Both the colorPointerCacheSize and pointerCacheSize fields in the Pointer Capability " \
"Set (section 2.2.7.1.5) are set to zero.\n" \
"(b) The pointerCacheSize field in the Pointer Capability Set (section 2.2.7.1.5) is not " \
"present, and the colorPointerCacheSize field is set to zero."
#define ERRINFO_BAD_CAPABILITIES_STRING \
"The capabilities received from the client in the Confirm Active PDU (section 2.2.1.13.2) " \
"were not accepted by the server."
#define ERRINFO_VIRTUAL_CHANNEL_DECOMPRESSION_STRING \
"An error occurred while using the bulk compressor (section 3.1.8 and [MS-RDPEGDI] section " \
"3.1.8) to decompress a Virtual Channel PDU (section 2.2.6.1)"
#define ERRINFO_INVALID_VC_COMPRESSION_TYPE_STRING \
"An invalid bulk compression package was specified in the flags field of the Channel PDU " \
"Header (section 2.2.6.1.1)."
#define ERRINFO_INVALID_CHANNEL_ID_STRING \
"An invalid MCS channel ID was specified in the mcsPdu field of the Virtual Channel PDU " \
"(section 2.2.6.1)."
#define ERRINFO_VCHANNELS_TOO_MANY_STRING \
"The client requested more than the maximum allowed 31 static virtual channels in the Client " \
"Network Data (section 2.2.1.3.4)."
#define ERRINFO_REMOTEAPP_NOT_ENABLED_STRING \
"The INFO_RAIL flag (0x00008000) MUST be set in the flags field of the Info Packet (section " \
"2.2.1.11.1.1) " \
"as the session on the remote server can only host remote applications."
#define ERRINFO_CACHE_CAP_NOT_SET_STRING \
"The client sent a Persistent Key List PDU (section 2.2.1.17) without including the " \
"prerequisite Revision 2 Bitmap Cache " \
"Capability Set (section 2.2.7.1.4.2) in the Confirm Active PDU (section 2.2.1.13.2)."
#define ERRINFO_BITMAP_CACHE_ERROR_PDU_BAD_LENGTH2_STRING \
"The NumInfoBlocks field in the Bitmap Cache Error PDU Data is inconsistent with the amount " \
"of data in the " \
"Info field ([MS-RDPEGDI] section 2.2.2.3.1.1)."
#define ERRINFO_OFFSCREEN_CACHE_ERROR_PDU_BAD_LENGTH_STRING \
"There is not enough data to process an Offscreen Bitmap Cache Error PDU ([MS-RDPEGDI] " \
"section 2.2.2.3.2)."
#define ERRINFO_DRAWNINEGRID_CACHE_ERROR_PDU_BAD_LENGTH_STRING \
"There is not enough data to process a DrawNineGrid Cache Error PDU ([MS-RDPEGDI] section " \
"2.2.2.3.3)."
#define ERRINFO_GDIPLUS_PDU_BAD_LENGTH_STRING \
"There is not enough data to process a GDI+ Error PDU ([MS-RDPEGDI] section 2.2.2.3.4)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT2_STRING \
"There is not enough data to read a Basic Security Header (section 2.2.8.1.1.2.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT3_STRING \
"There is not enough data to read a Non-FIPS Security Header (section 2.2.8.1.1.2.2) or FIPS " \
"Security Header (section 2.2.8.1.1.2.3)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT4_STRING \
"There is not enough data to read the basicSecurityHeader and length fields of the Security " \
"Exchange PDU Data (section 2.2.1.10.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT5_STRING \
"There is not enough data to read the CodePage, flags, cbDomain, cbUserName, cbPassword, " \
"cbAlternateShell, " \
"cbWorkingDir, Domain, UserName, Password, AlternateShell, and WorkingDir fields in the Info " \
"Packet (section 2.2.1.11.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT6_STRING \
"There is not enough data to read the CodePage, flags, cbDomain, cbUserName, cbPassword, " \
"cbAlternateShell, " \
"and cbWorkingDir fields in the Info Packet (section 2.2.1.11.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT7_STRING \
"There is not enough data to read the clientAddressFamily and cbClientAddress fields in the " \
"Extended Info Packet (section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT8_STRING \
"There is not enough data to read the clientAddress field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT9_STRING \
"There is not enough data to read the cbClientDir field in the Extended Info Packet (section " \
"2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT10_STRING \
"There is not enough data to read the clientDir field in the Extended Info Packet (section " \
"2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT11_STRING \
"There is not enough data to read the clientTimeZone field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT12_STRING \
"There is not enough data to read the clientSessionId field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT13_STRING \
"There is not enough data to read the performanceFlags field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT14_STRING \
"There is not enough data to read the cbAutoReconnectLen field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT15_STRING \
"There is not enough data to read the autoReconnectCookie field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT16_STRING \
"The cbAutoReconnectLen field in the Extended Info Packet (section 2.2.1.11.1.1.1) contains " \
"a value " \
"which is larger than the maximum allowed length of 128 bytes."
#define ERRINFO_SECURITY_DATA_TOO_SHORT17_STRING \
"There is not enough data to read the clientAddressFamily and cbClientAddress fields in the " \
"Extended Info Packet (section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT18_STRING \
"There is not enough data to read the clientAddress field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT19_STRING \
"There is not enough data to read the cbClientDir field in the Extended Info Packet (section " \
"2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT20_STRING \
"There is not enough data to read the clientDir field in the Extended Info Packet (section " \
"2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT21_STRING \
"There is not enough data to read the clientTimeZone field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT22_STRING \
"There is not enough data to read the clientSessionId field in the Extended Info Packet " \
"(section 2.2.1.11.1.1.1)."
#define ERRINFO_SECURITY_DATA_TOO_SHORT23_STRING \
"There is not enough data to read the Client Info PDU Data (section 2.2.1.11.1)."
#define ERRINFO_BAD_MONITOR_DATA_STRING \
"The monitorCount field in the Client Monitor Data (section 2.2.1.3.6) is invalid."
#define ERRINFO_VC_DECOMPRESSED_REASSEMBLE_FAILED_STRING \
"The server-side decompression buffer is invalid, or the size of the decompressed VC data " \
"exceeds " \
"the chunking size specified in the Virtual Channel Capability Set (section 2.2.7.1.10)."
#define ERRINFO_VC_DATA_TOO_LONG_STRING \
"The size of a received Virtual Channel PDU (section 2.2.6.1) exceeds the chunking size " \
"specified " \
"in the Virtual Channel Capability Set (section 2.2.7.1.10)."
#define ERRINFO_BAD_FRAME_ACK_DATA_STRING \
"There is not enough data to read a TS_FRAME_ACKNOWLEDGE_PDU ([MS-RDPRFX] section 2.2.3.1)."
#define ERRINFO_GRAPHICS_MODE_NOT_SUPPORTED_STRING \
"The graphics mode requested by the client is not supported by the server."
#define ERRINFO_GRAPHICS_SUBSYSTEM_RESET_FAILED_STRING \
"The server-side graphics subsystem failed to reset."
#define ERRINFO_GRAPHICS_SUBSYSTEM_FAILED_STRING \
"The server-side graphics subsystem is in an error state and unable to continue graphics " \
"encoding."
#define ERRINFO_TIMEZONE_KEY_NAME_LENGTH_TOO_SHORT_STRING \
"There is not enough data to read the cbDynamicDSTTimeZoneKeyName field in the Extended Info " \
"Packet (section 2.2.1.11.1.1.1)."
#define ERRINFO_TIMEZONE_KEY_NAME_LENGTH_TOO_LONG_STRING \
"The length reported in the cbDynamicDSTTimeZoneKeyName field of the Extended Info Packet " \
"(section 2.2.1.11.1.1.1) is too long."
#define ERRINFO_DYNAMIC_DST_DISABLED_FIELD_MISSING_STRING \
"The dynamicDaylightTimeDisabled field is not present in the Extended Info Packet (section " \
"2.2.1.11.1.1.1)."
#define ERRINFO_VC_DECODING_ERROR_STRING \
"An error occurred when processing dynamic virtual channel data ([MS-RDPEDYC] section 3.3.5)."
#define ERRINFO_VIRTUALDESKTOPTOOLARGE_STRING \
"The width or height of the virtual desktop defined by the monitor layout in the Client " \
"Monitor Data " \
"(section 2.2.1.3.6) is larger than the maximum allowed value of 32,766."
#define ERRINFO_MONITORGEOMETRYVALIDATIONFAILED_STRING \
"The monitor geometry defined by the Client Monitor Data (section 2.2.1.3.6) is invalid."
#define ERRINFO_INVALIDMONITORCOUNT_STRING \
"The monitorCount field in the Client Monitor Data(section 2.2.1.3.6) is too large."
#define ERRINFO_UPDATE_SESSION_KEY_FAILED_STRING \
"An attempt to update the session keys while using Standard RDP Security mechanisms (section " \
"5.3.7) failed."
#define ERRINFO_DECRYPT_FAILED_STRING \
"(a) Decryption using Standard RDP Security mechanisms (section 5.3.6) failed.\n" \
"(b) Session key creation using Standard RDP Security mechanisms (section 5.3.5) failed."
#define ERRINFO_ENCRYPT_FAILED_STRING \
"Encryption using Standard RDP Security mechanisms (section 5.3.6) failed."
#define ERRINFO_ENCRYPTION_PACKAGE_MISMATCH_STRING \
"Failed to find a usable Encryption Method (section 5.3.2) in the encryptionMethods field of " \
"the Client Security Data (section 2.2.1.4.3)."
#define ERRINFO_DECRYPT_FAILED2_STRING \
"Unencrypted data was encountered in a protocol stream which is meant to be encrypted with " \
"Standard RDP Security mechanisms (section 5.3.6)."
#define ERRINFO_PEER_DISCONNECTED_STRING "The peer connection was lost."
/* Special codes */
#define ERRINFO_SUCCESS_STRING "Success."
#define ERRINFO_NONE_STRING ""
static const ERRINFO ERRINFO_CODES[] = {
ERRINFO_DEFINE(SUCCESS, CAT_NONE),
/* Protocol-independent codes */
ERRINFO_DEFINE(RPC_INITIATED_DISCONNECT, CAT_ADMIN),
ERRINFO_DEFINE(RPC_INITIATED_LOGOFF, CAT_ADMIN), ERRINFO_DEFINE(IDLE_TIMEOUT, CAT_ADMIN),
ERRINFO_DEFINE(LOGON_TIMEOUT, CAT_ADMIN),
ERRINFO_DEFINE(DISCONNECTED_BY_OTHER_CONNECTION, CAT_USE),
ERRINFO_DEFINE(OUT_OF_MEMORY, CAT_ADMIN), ERRINFO_DEFINE(SERVER_DENIED_CONNECTION, CAT_ADMIN),
ERRINFO_DEFINE(SERVER_INSUFFICIENT_PRIVILEGES, CAT_ADMIN),
ERRINFO_DEFINE(SERVER_FRESH_CREDENTIALS_REQUIRED, CAT_ADMIN),
ERRINFO_DEFINE(RPC_INITIATED_DISCONNECT_BY_USER, CAT_ADMIN),
ERRINFO_DEFINE(LOGOFF_BY_USER, CAT_USE),
ERRINFO_DEFINE(CLOSE_STACK_ON_DRIVER_NOT_READY, CAT_SERVER),
ERRINFO_DEFINE(SERVER_DWM_CRASH, CAT_SERVER),
ERRINFO_DEFINE(CLOSE_STACK_ON_DRIVER_FAILURE, CAT_SERVER),
ERRINFO_DEFINE(CLOSE_STACK_ON_DRIVER_IFACE_FAILURE, CAT_SERVER),
ERRINFO_DEFINE(SERVER_WINLOGON_CRASH, CAT_SERVER),
ERRINFO_DEFINE(SERVER_CSRSS_CRASH, CAT_SERVER),
/* Protocol-independent licensing codes */
ERRINFO_DEFINE(LICENSE_INTERNAL, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_NO_LICENSE_SERVER, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_NO_LICENSE, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_BAD_CLIENT_MSG, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_HWID_DOESNT_MATCH_LICENSE, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_BAD_CLIENT_LICENSE, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_CANT_FINISH_PROTOCOL, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_CLIENT_ENDED_PROTOCOL, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_BAD_CLIENT_ENCRYPTION, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_CANT_UPGRADE_LICENSE, CAT_LICENSING),
ERRINFO_DEFINE(LICENSE_NO_REMOTE_CONNECTIONS, CAT_LICENSING),
/* Protocol-independent codes generated by the Connection Broker */
ERRINFO_DEFINE(CB_DESTINATION_NOT_FOUND, CAT_BROKER),
ERRINFO_DEFINE(CB_LOADING_DESTINATION, CAT_BROKER),
ERRINFO_DEFINE(CB_REDIRECTING_TO_DESTINATION, CAT_BROKER),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_WAKE, CAT_BROKER),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_BOOT, CAT_BROKER),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_NO_DNS, CAT_BROKER),
ERRINFO_DEFINE(CB_DESTINATION_POOL_NOT_FREE, CAT_BROKER),
ERRINFO_DEFINE(CB_CONNECTION_CANCELLED, CAT_BROKER),
ERRINFO_DEFINE(CB_CONNECTION_ERROR_INVALID_SETTINGS, CAT_BROKER),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_BOOT_TIMEOUT, CAT_BROKER),
ERRINFO_DEFINE(CB_SESSION_ONLINE_VM_SESSMON_FAILED, CAT_BROKER),
/* RDP specific codes */
ERRINFO_DEFINE(UNKNOWN_DATA_PDU_TYPE, CAT_PROTOCOL),
ERRINFO_DEFINE(UNKNOWN_PDU_TYPE, CAT_PROTOCOL), ERRINFO_DEFINE(DATA_PDU_SEQUENCE, CAT_PROTOCOL),
ERRINFO_DEFINE(CONTROL_PDU_SEQUENCE, CAT_PROTOCOL),
ERRINFO_DEFINE(INVALID_CONTROL_PDU_ACTION, CAT_PROTOCOL),
ERRINFO_DEFINE(INVALID_INPUT_PDU_TYPE, CAT_PROTOCOL),
ERRINFO_DEFINE(INVALID_INPUT_PDU_MOUSE, CAT_PROTOCOL),
ERRINFO_DEFINE(INVALID_REFRESH_RECT_PDU, CAT_PROTOCOL),
ERRINFO_DEFINE(CREATE_USER_DATA_FAILED, CAT_PROTOCOL), ERRINFO_DEFINE(CONNECT_FAILED, CAT_USE),
ERRINFO_DEFINE(CONFIRM_ACTIVE_HAS_WRONG_SHAREID, CAT_PROTOCOL),
ERRINFO_DEFINE(CONFIRM_ACTIVE_HAS_WRONG_ORIGINATOR, CAT_PROTOCOL),
ERRINFO_DEFINE(PERSISTENT_KEY_PDU_BAD_LENGTH, CAT_PROTOCOL),
ERRINFO_DEFINE(PERSISTENT_KEY_PDU_ILLEGAL_FIRST, CAT_PROTOCOL),
ERRINFO_DEFINE(PERSISTENT_KEY_PDU_TOO_MANY_TOTAL_KEYS, CAT_PROTOCOL),
ERRINFO_DEFINE(PERSISTENT_KEY_PDU_TOO_MANY_CACHE_KEYS, CAT_PROTOCOL),
ERRINFO_DEFINE(INPUT_PDU_BAD_LENGTH, CAT_PROTOCOL),
ERRINFO_DEFINE(BITMAP_CACHE_ERROR_PDU_BAD_LENGTH, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT, CAT_PROTOCOL),
ERRINFO_DEFINE(VCHANNEL_DATA_TOO_SHORT, CAT_PROTOCOL),
ERRINFO_DEFINE(SHARE_DATA_TOO_SHORT, CAT_PROTOCOL),
ERRINFO_DEFINE(BAD_SUPPRESS_OUTPUT_PDU, CAT_PROTOCOL),
ERRINFO_DEFINE(CONFIRM_ACTIVE_PDU_TOO_SHORT, CAT_PROTOCOL),
ERRINFO_DEFINE(CAPABILITY_SET_TOO_SMALL, CAT_PROTOCOL),
ERRINFO_DEFINE(CAPABILITY_SET_TOO_LARGE, CAT_PROTOCOL),
ERRINFO_DEFINE(NO_CURSOR_CACHE, CAT_PROTOCOL), ERRINFO_DEFINE(BAD_CAPABILITIES, CAT_PROTOCOL),
ERRINFO_DEFINE(VIRTUAL_CHANNEL_DECOMPRESSION, CAT_PROTOCOL),
ERRINFO_DEFINE(INVALID_VC_COMPRESSION_TYPE, CAT_PROTOCOL),
ERRINFO_DEFINE(INVALID_CHANNEL_ID, CAT_PROTOCOL),
ERRINFO_DEFINE(VCHANNELS_TOO_MANY, CAT_PROTOCOL),
ERRINFO_DEFINE(REMOTEAPP_NOT_ENABLED, CAT_ADMIN),
ERRINFO_DEFINE(CACHE_CAP_NOT_SET, CAT_PROTOCOL),
ERRINFO_DEFINE(BITMAP_CACHE_ERROR_PDU_BAD_LENGTH2, CAT_PROTOCOL),
ERRINFO_DEFINE(OFFSCREEN_CACHE_ERROR_PDU_BAD_LENGTH, CAT_PROTOCOL),
ERRINFO_DEFINE(DRAWNINEGRID_CACHE_ERROR_PDU_BAD_LENGTH, CAT_PROTOCOL),
ERRINFO_DEFINE(GDIPLUS_PDU_BAD_LENGTH, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT2, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT3, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT4, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT5, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT6, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT7, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT8, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT9, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT10, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT11, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT12, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT13, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT14, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT15, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT16, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT17, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT18, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT19, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT20, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT21, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT22, CAT_PROTOCOL),
ERRINFO_DEFINE(SECURITY_DATA_TOO_SHORT23, CAT_PROTOCOL),
ERRINFO_DEFINE(BAD_MONITOR_DATA, CAT_PROTOCOL),
ERRINFO_DEFINE(VC_DECOMPRESSED_REASSEMBLE_FAILED, CAT_PROTOCOL),
ERRINFO_DEFINE(VC_DATA_TOO_LONG, CAT_PROTOCOL),
ERRINFO_DEFINE(BAD_FRAME_ACK_DATA, CAT_PROTOCOL),
ERRINFO_DEFINE(GRAPHICS_MODE_NOT_SUPPORTED, CAT_SERVER),
ERRINFO_DEFINE(GRAPHICS_SUBSYSTEM_RESET_FAILED, CAT_SERVER),
ERRINFO_DEFINE(GRAPHICS_SUBSYSTEM_FAILED, CAT_SERVER),
ERRINFO_DEFINE(TIMEZONE_KEY_NAME_LENGTH_TOO_SHORT, CAT_PROTOCOL),
ERRINFO_DEFINE(TIMEZONE_KEY_NAME_LENGTH_TOO_LONG, CAT_PROTOCOL),
ERRINFO_DEFINE(DYNAMIC_DST_DISABLED_FIELD_MISSING, CAT_PROTOCOL),
ERRINFO_DEFINE(VC_DECODING_ERROR, CAT_PROTOCOL),
ERRINFO_DEFINE(VIRTUALDESKTOPTOOLARGE, CAT_SERVER),
ERRINFO_DEFINE(MONITORGEOMETRYVALIDATIONFAILED, CAT_PROTOCOL),
ERRINFO_DEFINE(INVALIDMONITORCOUNT, CAT_PROTOCOL),
ERRINFO_DEFINE(UPDATE_SESSION_KEY_FAILED, CAT_PROTOCOL),
ERRINFO_DEFINE(DECRYPT_FAILED, CAT_PROTOCOL), ERRINFO_DEFINE(ENCRYPT_FAILED, CAT_PROTOCOL),
ERRINFO_DEFINE(ENCRYPTION_PACKAGE_MISMATCH, CAT_PROTOCOL),
ERRINFO_DEFINE(DECRYPT_FAILED2, CAT_PROTOCOL), ERRINFO_DEFINE(PEER_DISCONNECTED, CAT_USE),
ERRINFO_DEFINE(NONE, CAT_NONE)
};
const char* freerdp_get_error_info_string(UINT32 code)
{
const ERRINFO* errInfo = nullptr;
errInfo = &ERRINFO_CODES[0];
while (errInfo->code != ERRINFO_NONE)
{
if (code == errInfo->code)
{
return errInfo->info;
}
errInfo++;
}
return "Unknown error.";
}
const char* freerdp_get_error_info_category(UINT32 code)
{
const ERRINFO* errInfo = nullptr;
errInfo = &ERRINFO_CODES[0];
while (errInfo->code != ERRINFO_NONE)
{
if (code == errInfo->code)
{
return errInfo->category;
}
errInfo++;
}
return "ERRINFO_UNKNOWN";
}
const char* freerdp_get_error_info_name(UINT32 code)
{
const ERRINFO* errInfo = nullptr;
errInfo = &ERRINFO_CODES[0];
while (errInfo->code != ERRINFO_NONE)
{
if (code == errInfo->code)
{
return errInfo->name;
}
errInfo++;
}
return "ERRINFO_UNKNOWN";
}
void rdp_print_errinfo(UINT32 code)
{
const ERRINFO* errInfo = nullptr;
errInfo = &ERRINFO_CODES[0];
while (errInfo->code != ERRINFO_NONE)
{
if (code == errInfo->code)
{
WLog_INFO(TAG, "%s (0x%08" PRIX32 "):%s", errInfo->name, code, errInfo->info);
return;
}
errInfo++;
}
WLog_ERR(TAG, "ERRINFO_UNKNOWN 0x%08" PRIX32 ": Unknown error.", code);
}

View File

@@ -0,0 +1,36 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Error Info
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_ERRINFO_H
#define FREERDP_LIB_CORE_ERRINFO_H
#include <freerdp/freerdp.h>
#include <freerdp/api.h>
typedef struct
{
UINT32 code;
const char* name;
const char* info;
const char* category;
} ERRINFO;
FREERDP_LOCAL void rdp_print_errinfo(UINT32 code);
#endif /* FREERDP_LIB_CORE_ERRINFO_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Fast Path
*
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_FASTPATH_H
#define FREERDP_LIB_CORE_FASTPATH_H
/*
* Fast-Path has 15 bits available for length information which would lead to a
* maximal pdu size of 0x8000. However in practice only 14 bits are used
* this isn't documented anywhere but it looks like most implementations will
* fail if fast-path packages > 0x3FFF arrive.
*/
#define FASTPATH_MAX_PACKET_SIZE 0x3FFF
/*
* The following size guarantees that no fast-path PDU fragmentation occurs.
* It was calculated by subtracting 128 from FASTPATH_MAX_PACKET_SIZE.
* 128 was chosen because it includes all required and optional headers as well as
* possible paddings and some extra bytes for safety.
*/
#define FASTPATH_FRAGMENT_SAFE_SIZE 0x3F80
typedef struct rdp_fastpath rdpFastPath;
#include "rdp.h"
#include <winpr/stream.h>
#include <freerdp/api.h>
enum FASTPATH_INPUT_ACTION_TYPE
{
FASTPATH_INPUT_ACTION_FASTPATH = 0x0,
FASTPATH_INPUT_ACTION_X224 = 0x3
};
enum FASTPATH_OUTPUT_ACTION_TYPE
{
FASTPATH_OUTPUT_ACTION_FASTPATH = 0x0,
FASTPATH_OUTPUT_ACTION_X224 = 0x3
};
enum FASTPATH_UPDATETYPE
{
FASTPATH_UPDATETYPE_ORDERS = 0x0,
FASTPATH_UPDATETYPE_BITMAP = 0x1,
FASTPATH_UPDATETYPE_PALETTE = 0x2,
FASTPATH_UPDATETYPE_SYNCHRONIZE = 0x3,
FASTPATH_UPDATETYPE_SURFCMDS = 0x4,
FASTPATH_UPDATETYPE_PTR_NULL = 0x5,
FASTPATH_UPDATETYPE_PTR_DEFAULT = 0x6,
FASTPATH_UPDATETYPE_PTR_POSITION = 0x8,
FASTPATH_UPDATETYPE_COLOR = 0x9,
FASTPATH_UPDATETYPE_CACHED = 0xA,
FASTPATH_UPDATETYPE_POINTER = 0xB,
FASTPATH_UPDATETYPE_LARGE_POINTER = 0xC
};
enum FASTPATH_FRAGMENT
{
FASTPATH_FRAGMENT_SINGLE = 0x0,
FASTPATH_FRAGMENT_LAST = 0x1,
FASTPATH_FRAGMENT_FIRST = 0x2,
FASTPATH_FRAGMENT_NEXT = 0x3
};
enum FASTPATH_OUTPUT_COMPRESSION
{
FASTPATH_OUTPUT_COMPRESSION_USED = 0x2
};
/* FastPath Input Events */
enum FASTPATH_INPUT_EVENT_CODE
{
FASTPATH_INPUT_EVENT_SCANCODE = 0x0,
FASTPATH_INPUT_EVENT_MOUSE = 0x1,
FASTPATH_INPUT_EVENT_MOUSEX = 0x2,
FASTPATH_INPUT_EVENT_SYNC = 0x3,
FASTPATH_INPUT_EVENT_UNICODE = 0x4,
TS_FP_RELPOINTER_EVENT = 0x5,
TS_FP_QOETIMESTAMP_EVENT = 0x6
};
/* FastPath Keyboard Event Flags */
enum FASTPATH_INPUT_KBDFLAGS
{
FASTPATH_INPUT_KBDFLAGS_RELEASE = 0x01,
FASTPATH_INPUT_KBDFLAGS_EXTENDED = 0x02,
FASTPATH_INPUT_KBDFLAGS_PREFIX_E1 = 0x04 /* for pause sequence */
};
typedef struct
{
BYTE length1;
BYTE length2;
BYTE fipsInformation[4];
BYTE dataSignature[8];
BYTE action;
BYTE secFlags;
UINT16 length;
} FASTPATH_UPDATE_PDU_HEADER;
typedef struct
{
BYTE compressionFlags;
UINT16 size;
BYTE updateCode;
BYTE fragmentation;
BYTE compression;
} FASTPATH_UPDATE_HEADER;
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL fastpath_read_header_rdp(rdpFastPath* fastpath, wStream* s, UINT16* length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t fastpath_recv_updates(rdpFastPath* fastpath, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t fastpath_recv_inputs(rdpFastPath* fastpath, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL fastpath_decrypt(rdpFastPath* fastpath, wStream* s, UINT16* length);
WINPR_ATTR_MALLOC(Stream_Release, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* fastpath_input_pdu_init_header(rdpFastPath* fastpath, UINT16* sec_flags);
WINPR_ATTR_MALLOC(Stream_Release, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags,
BYTE eventCode, UINT16* sec_flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s,
size_t iNumEvents, UINT16 sec_flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s, UINT16 sec_flags);
WINPR_ATTR_MALLOC(Stream_Release, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* fastpath_update_pdu_init(rdpFastPath* fastpath);
WINPR_ATTR_MALLOC(Stream_Free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* fastpath_update_pdu_init_new(rdpFastPath* fastpath);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s,
BOOL skipCompression);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL fastpath_send_surfcmd_frame_marker(rdpFastPath* fastpath, UINT16 frameAction,
UINT32 frameId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BYTE fastpath_get_encryption_flags(rdpFastPath* fastpath);
FREERDP_LOCAL void fastpath_free(rdpFastPath* fastpath);
WINPR_ATTR_MALLOC(fastpath_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpFastPath* fastpath_new(rdpRdp* rdp);
#endif /* FREERDP_LIB_CORE_FASTPATH_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Azure Virtual Desktop Gateway / Azure Resource Manager
*
* Copyright 2023 Michael Saxl <mike@mwsys.mine.bz>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_ARM_H
#define FREERDP_LIB_CORE_GATEWAY_ARM_H
#include <winpr/wtypes.h>
#include <winpr/wlog.h>
#include <freerdp/api.h>
#include <freerdp/types.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL arm_resolve_endpoint(wLog* log, rdpContext* context, DWORD timeout);
#endif /* FREERDP_LIB_CORE_GATEWAY_ARM_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,225 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Hypertext Transfer Protocol (HTTP)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_HTTP_H
#define FREERDP_LIB_CORE_GATEWAY_HTTP_H
#include <winpr/stream.h>
#include <freerdp/api.h>
#include <freerdp/utils/http.h>
#include "../../crypto/tls.h"
typedef enum
{
TransferEncodingUnknown,
TransferEncodingIdentity,
TransferEncodingChunked
} TRANSFER_ENCODING;
typedef enum
{
ChunkStateLenghHeader,
ChunkStateData,
ChunkStateFooter,
ChunkStateEnd
} CHUNK_STATE;
typedef struct
{
size_t nextOffset;
size_t headerFooterPos;
CHUNK_STATE state;
char lenBuffer[11];
} http_encoding_chunked_context;
/* HTTP context */
typedef struct s_http_context HttpContext;
FREERDP_LOCAL void http_context_free(HttpContext* context);
WINPR_ATTR_MALLOC(http_context_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HttpContext* http_context_new(void);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_method(HttpContext* context, const char* Method);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* http_context_get_uri(HttpContext* context);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_uri(HttpContext* context, const char* URI);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_user_agent(HttpContext* context, const char* UserAgent);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_x_ms_user_agent(HttpContext* context, const char* UserAgent);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_host(HttpContext* context, const char* Host);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_accept(HttpContext* context, const char* Accept);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_cache_control(HttpContext* context, const char* CacheControl);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_connection(HttpContext* context, const char* Connection);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_pragma(HttpContext* context,
WINPR_FORMAT_ARG const char* Pragma, ...);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_append_pragma(HttpContext* context,
WINPR_FORMAT_ARG const char* Pragma, ...);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_cookie(HttpContext* context, const char* CookieName,
const char* CookieValue);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_rdg_connection_id(HttpContext* context,
const GUID* RdgConnectionId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_rdg_correlation_id(HttpContext* context,
const GUID* RdgCorrelationId);
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(3, 4)
FREERDP_LOCAL BOOL http_context_set_header(HttpContext* context, const char* key,
WINPR_FORMAT_ARG const char* value, ...);
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(3, 0)
FREERDP_LOCAL BOOL http_context_set_header_va(HttpContext* context, const char* key,
WINPR_FORMAT_ARG const char* value, va_list ap);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_set_rdg_auth_scheme(HttpContext* context,
const char* RdgAuthScheme);
FREERDP_LOCAL BOOL http_context_enable_websocket_upgrade(HttpContext* context, BOOL enable);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_context_is_websocket_upgrade_enabled(HttpContext* context);
/* HTTP request */
typedef struct s_http_request HttpRequest;
FREERDP_LOCAL void http_request_free(HttpRequest* request);
WINPR_ATTR_MALLOC(http_request_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HttpRequest* http_request_new(void);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_request_set_method(HttpRequest* request, const char* Method);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_request_set_content_type(HttpRequest* request, const char* ContentType);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SSIZE_T http_request_get_content_length(HttpRequest* request);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_request_set_content_length(HttpRequest* request, size_t length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* http_request_get_uri(HttpRequest* request);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_request_set_uri(HttpRequest* request, const char* URI);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_request_set_auth_scheme(HttpRequest* request, const char* AuthScheme);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_request_set_auth_param(HttpRequest* request, const char* AuthParam);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_request_set_transfer_encoding(HttpRequest* request,
TRANSFER_ENCODING TransferEncoding);
WINPR_ATTR_NODISCARD
WINPR_ATTR_FORMAT_ARG(3, 4)
FREERDP_LOCAL BOOL http_request_set_header(HttpRequest* request, const char* key,
WINPR_FORMAT_ARG const char* value, ...);
WINPR_ATTR_MALLOC(Stream_Free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* http_request_write(HttpContext* context, HttpRequest* request);
/* HTTP response */
typedef struct s_http_response HttpResponse;
FREERDP_LOCAL void http_response_free(HttpResponse* response);
WINPR_ATTR_MALLOC(http_response_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HttpResponse* http_response_new(void);
WINPR_ATTR_MALLOC(http_response_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HttpResponse* http_response_recv(rdpTls* tls, BOOL readContentLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL UINT16 http_response_get_status_code(const HttpResponse* response);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t http_response_get_body_length(const HttpResponse* response);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* http_response_get_body(const HttpResponse* response);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* http_response_get_auth_token(const HttpResponse* response,
const char* method);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* http_response_get_setcookie(const HttpResponse* response,
const char* cookie);
FREERDP_LOCAL BOOL http_response_extract_cookies(const HttpResponse* response,
HttpContext* context);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL TRANSFER_ENCODING http_response_get_transfer_encoding(const HttpResponse* response);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL http_response_is_websocket(const HttpContext* http,
const HttpResponse* response);
#define http_response_log_error_status(log, level, response) \
http_response_log_error_status_((log), (level), (response), __FILE__, __LINE__, __func__)
FREERDP_LOCAL void http_response_log_error_status_(wLog* log, DWORD level,
const HttpResponse* response, const char* file,
size_t line, const char* fkt);
/* chunked read helper */
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int http_chuncked_read(BIO* bio, BYTE* pBuffer, size_t size,
http_encoding_chunked_context* encodingContext);
#endif /* FREERDP_LIB_CORE_GATEWAY_HTTP_H */

View File

@@ -0,0 +1,278 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC over HTTP (ncacn_http)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include "../settings.h"
#include "ncacn_http.h"
#include <winpr/crt.h>
#include <winpr/tchar.h>
#include <winpr/stream.h>
#include <winpr/dsparse.h>
#include "../utils.h"
#define TAG FREERDP_TAG("core.gateway.ntlm")
#define AUTH_PKG NTLM_SSP_NAME
static wStream* rpc_auth_http_request(HttpContext* http, const char* method, size_t contentLength,
const SecBuffer* authToken, const char* auth_scheme)
{
wStream* s = nullptr;
HttpRequest* request = nullptr;
char* base64AuthToken = nullptr;
const char* uri = nullptr;
if (!http || !method)
goto fail;
request = http_request_new();
if (!request)
goto fail;
if (authToken)
base64AuthToken = crypto_base64_encode(authToken->pvBuffer, authToken->cbBuffer);
uri = http_context_get_uri(http);
if (!http_request_set_method(request, method) ||
!http_request_set_content_length(request, contentLength) ||
!http_request_set_uri(request, uri))
goto fail;
if (base64AuthToken)
{
if (!http_request_set_auth_scheme(request, auth_scheme) ||
!http_request_set_auth_param(request, base64AuthToken))
goto fail;
}
s = http_request_write(http, request);
fail:
http_request_free(request);
free(base64AuthToken);
return s;
}
BOOL rpc_ncacn_http_send_in_channel_request(RpcChannel* inChannel)
{
wStream* s = nullptr;
SSIZE_T status = 0;
rdpCredsspAuth* auth = nullptr;
HttpContext* http = nullptr;
const SecBuffer* buffer = nullptr;
int rc = 0;
if (!inChannel || !inChannel->auth || !inChannel->http)
return FALSE;
auth = inChannel->auth;
http = inChannel->http;
rc = credssp_auth_authenticate(auth);
if (rc < 0)
return FALSE;
const size_t contentLength = (rc == 0) ? 0 : 0x40000000;
buffer = credssp_auth_have_output_token(auth) ? credssp_auth_get_output_buffer(auth) : nullptr;
s = rpc_auth_http_request(http, "RPC_IN_DATA", contentLength, buffer,
credssp_auth_pkg_name(auth));
if (!s)
return -1;
status = rpc_channel_write(inChannel, Stream_Buffer(s), Stream_Length(s));
Stream_Free(s, TRUE);
return (status > 0) ? 1 : -1;
}
BOOL rpc_ncacn_http_recv_in_channel_response(RpcChannel* inChannel, HttpResponse* response)
{
size_t authTokenLength = 0;
BYTE* authTokenData = nullptr;
if (!inChannel || !response || !inChannel->auth)
return FALSE;
rdpCredsspAuth* auth = inChannel->auth;
const char* token64 = http_response_get_auth_token(response, credssp_auth_pkg_name(auth));
if (token64)
crypto_base64_decode(token64, strlen(token64), &authTokenData, &authTokenLength);
if (authTokenLength > UINT32_MAX)
{
free(authTokenData);
return FALSE;
}
SecBuffer buffer = { .pvBuffer = authTokenData, .cbBuffer = (UINT32)authTokenLength };
if (authTokenData && authTokenLength)
{
credssp_auth_take_input_buffer(auth, &buffer);
return TRUE;
}
sspi_SecBufferFree(&buffer);
return TRUE;
}
BOOL rpc_ncacn_http_auth_init(rdpContext* context, RpcChannel* channel)
{
rdpTls* tls = nullptr;
rdpCredsspAuth* auth = nullptr;
rdpSettings* settings = nullptr;
freerdp* instance = nullptr;
auth_status rc = AUTH_FAILED;
SEC_WINNT_AUTH_IDENTITY identity = WINPR_C_ARRAY_INIT;
if (!context || !channel)
return FALSE;
tls = channel->tls;
auth = channel->auth;
settings = context->settings;
instance = context->instance;
if (!tls || !auth || !instance || !settings)
return FALSE;
rc = utils_authenticate_gateway(instance, GW_AUTH_HTTP);
switch (rc)
{
case AUTH_SUCCESS:
case AUTH_SKIP:
break;
case AUTH_CANCELLED:
freerdp_set_last_error_log(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
return FALSE;
case AUTH_NO_CREDENTIALS:
WLog_INFO(TAG, "No credentials provided - using nullptr identity");
break;
case AUTH_FAILED:
default:
return FALSE;
}
if (!credssp_auth_init(auth, AUTH_PKG, tls->Bindings))
return FALSE;
if (!identity_set_from_settings(&identity, settings, FreeRDP_GatewayUsername,
FreeRDP_GatewayDomain, FreeRDP_GatewayPassword))
return FALSE;
SEC_WINNT_AUTH_IDENTITY* identityArg = (settings->GatewayUsername ? &identity : nullptr);
const BOOL res =
credssp_auth_setup_client(auth, "HTTP", settings->GatewayHostname, identityArg, nullptr);
sspi_FreeAuthIdentity(&identity);
credssp_auth_set_flags(auth, ISC_REQ_CONFIDENTIALITY);
return res;
}
void rpc_ncacn_http_auth_uninit(RpcChannel* channel)
{
if (!channel)
return;
credssp_auth_free(channel->auth);
channel->auth = nullptr;
}
BOOL rpc_ncacn_http_send_out_channel_request(RpcChannel* outChannel, BOOL replacement)
{
BOOL status = TRUE;
wStream* s = nullptr;
size_t contentLength = 0;
rdpCredsspAuth* auth = nullptr;
HttpContext* http = nullptr;
const SecBuffer* buffer = nullptr;
int rc = 0;
if (!outChannel || !outChannel->auth || !outChannel->http)
return FALSE;
auth = outChannel->auth;
http = outChannel->http;
rc = credssp_auth_authenticate(auth);
if (rc < 0)
return FALSE;
if (!replacement)
contentLength = (rc == 0) ? 0 : 76;
else
contentLength = (rc == 0) ? 0 : 120;
buffer = credssp_auth_have_output_token(auth) ? credssp_auth_get_output_buffer(auth) : nullptr;
s = rpc_auth_http_request(http, "RPC_OUT_DATA", contentLength, buffer,
credssp_auth_pkg_name(auth));
if (!s)
return -1;
if (rpc_channel_write(outChannel, Stream_Buffer(s), Stream_Length(s)) < 0)
status = FALSE;
Stream_Free(s, TRUE);
return status;
}
BOOL rpc_ncacn_http_recv_out_channel_response(RpcChannel* outChannel, HttpResponse* response)
{
size_t authTokenLength = 0;
BYTE* authTokenData = nullptr;
if (!outChannel || !response || !outChannel->auth)
return FALSE;
rdpCredsspAuth* auth = outChannel->auth;
const char* token64 = http_response_get_auth_token(response, credssp_auth_pkg_name(auth));
if (token64)
crypto_base64_decode(token64, strlen(token64), &authTokenData, &authTokenLength);
if (authTokenLength > UINT32_MAX)
{
free(authTokenData);
return FALSE;
}
SecBuffer buffer = { .pvBuffer = authTokenData, .cbBuffer = (UINT32)authTokenLength };
if (authTokenData && authTokenLength)
{
credssp_auth_take_input_buffer(auth, &buffer);
return TRUE;
}
sspi_SecBufferFree(&buffer);
return TRUE;
}
BOOL rpc_ncacn_http_is_final_request(RpcChannel* channel)
{
WINPR_ASSERT(channel);
return credssp_auth_is_complete(channel->auth);
}

View File

@@ -0,0 +1,51 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC over HTTP (ncacn_http)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_NCACN_HTTP_H
#define FREERDP_LIB_CORE_GATEWAY_NCACN_HTTP_H
#include <freerdp/api.h>
#include "rpc.h"
#include "http.h"
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_ncacn_http_auth_init(rdpContext* context, RpcChannel* channel);
FREERDP_LOCAL void rpc_ncacn_http_auth_uninit(RpcChannel* channel);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_ncacn_http_send_in_channel_request(RpcChannel* inChannel);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_ncacn_http_recv_in_channel_response(RpcChannel* inChannel,
HttpResponse* response);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_ncacn_http_send_out_channel_request(RpcChannel* outChannel,
BOOL replacement);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_ncacn_http_recv_out_channel_response(RpcChannel* outChannel,
HttpResponse* response);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_ncacn_http_is_final_request(RpcChannel* channel);
#endif /* FREERDP_LIB_CORE_GATEWAY_NCACN_HTTP_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Remote Desktop Gateway (RDG)
*
* Copyright 2015 Denis Vincent <dvincent@devolutions.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_RDG_H
#define FREERDP_LIB_CORE_GATEWAY_RDG_H
#include <winpr/wtypes.h>
#include <winpr/stream.h>
#include <winpr/winpr.h>
#include <freerdp/api.h>
#include <freerdp/types.h>
/* needed for BIO */
#include <openssl/ssl.h>
typedef struct rdp_rdg rdpRdg;
FREERDP_LOCAL void rdg_free(rdpRdg* rdg);
WINPR_ATTR_MALLOC(rdg_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpRdg* rdg_new(rdpContext* context);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BIO* rdg_get_front_bio_and_take_ownership(rdpRdg* rdg);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdg_connect(rdpRdg* rdg, DWORD timeout, BOOL* rpcFallback);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL DWORD rdg_get_event_handles(rdpRdg* rdg, HANDLE* events, DWORD count);
#endif /* FREERDP_LIB_CORE_GATEWAY_RDG_H */

View File

@@ -0,0 +1,983 @@
/*
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC over HTTP
*
* Copyright 2012 Fujitsu Technology Solutions GmbH
* Copyright 2012 Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include "../settings.h"
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/tchar.h>
#include <winpr/synch.h>
#include <winpr/dsparse.h>
#include <winpr/crypto.h>
#include <freerdp/log.h>
#ifdef FREERDP_HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
#include "../proxy.h"
#include "http.h"
#include "../credssp_auth.h"
#include "ncacn_http.h"
#include "rpc_bind.h"
#include "rpc_fault.h"
#include "rpc_client.h"
#include "rpc.h"
#include "rts.h"
#define TAG FREERDP_TAG("core.gateway.rpc")
static const char* PTYPE_STRINGS[] = { "PTYPE_REQUEST", "PTYPE_PING",
"PTYPE_RESPONSE", "PTYPE_FAULT",
"PTYPE_WORKING", "PTYPE_NOCALL",
"PTYPE_REJECT", "PTYPE_ACK",
"PTYPE_CL_CANCEL", "PTYPE_FACK",
"PTYPE_CANCEL_ACK", "PTYPE_BIND",
"PTYPE_BIND_ACK", "PTYPE_BIND_NAK",
"PTYPE_ALTER_CONTEXT", "PTYPE_ALTER_CONTEXT_RESP",
"PTYPE_RPC_AUTH_3", "PTYPE_SHUTDOWN",
"PTYPE_CO_CANCEL", "PTYPE_ORPHANED",
"PTYPE_RTS", "" };
static const char* client_in_state_str(CLIENT_IN_CHANNEL_STATE state)
{
// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
const char* str = "CLIENT_IN_CHANNEL_STATE_UNKNOWN";
switch (state)
{
case CLIENT_IN_CHANNEL_STATE_INITIAL:
str = "CLIENT_IN_CHANNEL_STATE_INITIAL";
break;
case CLIENT_IN_CHANNEL_STATE_CONNECTED:
str = "CLIENT_IN_CHANNEL_STATE_CONNECTED";
break;
case CLIENT_IN_CHANNEL_STATE_SECURITY:
str = "CLIENT_IN_CHANNEL_STATE_SECURITY";
break;
case CLIENT_IN_CHANNEL_STATE_NEGOTIATED:
str = "CLIENT_IN_CHANNEL_STATE_NEGOTIATED";
break;
case CLIENT_IN_CHANNEL_STATE_OPENED:
str = "CLIENT_IN_CHANNEL_STATE_OPENED";
break;
case CLIENT_IN_CHANNEL_STATE_OPENED_A4W:
str = "CLIENT_IN_CHANNEL_STATE_OPENED_A4W";
break;
case CLIENT_IN_CHANNEL_STATE_FINAL:
str = "CLIENT_IN_CHANNEL_STATE_FINAL";
break;
default:
break;
}
return str;
}
static const char* client_out_state_str(CLIENT_OUT_CHANNEL_STATE state)
{
// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
const char* str = "CLIENT_OUT_CHANNEL_STATE_UNKNOWN";
switch (state)
{
case CLIENT_OUT_CHANNEL_STATE_INITIAL:
str = "CLIENT_OUT_CHANNEL_STATE_INITIAL";
break;
case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
str = "CLIENT_OUT_CHANNEL_STATE_CONNECTED";
break;
case CLIENT_OUT_CHANNEL_STATE_SECURITY:
str = "CLIENT_OUT_CHANNEL_STATE_SECURITY";
break;
case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
str = "CLIENT_OUT_CHANNEL_STATE_NEGOTIATED";
break;
case CLIENT_OUT_CHANNEL_STATE_OPENED:
str = "CLIENT_OUT_CHANNEL_STATE_OPENED";
break;
case CLIENT_OUT_CHANNEL_STATE_OPENED_A6W:
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A6W";
break;
case CLIENT_OUT_CHANNEL_STATE_OPENED_A10W:
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A10W";
break;
case CLIENT_OUT_CHANNEL_STATE_OPENED_B3W:
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_B3W";
break;
case CLIENT_OUT_CHANNEL_STATE_RECYCLED:
str = "CLIENT_OUT_CHANNEL_STATE_RECYCLED";
break;
case CLIENT_OUT_CHANNEL_STATE_FINAL:
str = "CLIENT_OUT_CHANNEL_STATE_FINAL";
break;
default:
break;
}
return str;
}
const char* rpc_vc_state_str(VIRTUAL_CONNECTION_STATE state)
{
// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
const char* str = "VIRTUAL_CONNECTION_STATE_UNKNOWN";
switch (state)
{
case VIRTUAL_CONNECTION_STATE_INITIAL:
str = "VIRTUAL_CONNECTION_STATE_INITIAL";
break;
case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
str = "VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT";
break;
case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
str = "VIRTUAL_CONNECTION_STATE_WAIT_A3W";
break;
case VIRTUAL_CONNECTION_STATE_WAIT_C2:
str = "VIRTUAL_CONNECTION_STATE_WAIT_C2";
break;
case VIRTUAL_CONNECTION_STATE_OPENED:
str = "VIRTUAL_CONNECTION_STATE_OPENED";
break;
case VIRTUAL_CONNECTION_STATE_FINAL:
str = "VIRTUAL_CONNECTION_STATE_FINAL";
break;
default:
break;
}
return str;
}
/*
* [MS-RPCH]: Remote Procedure Call over HTTP Protocol Specification:
* http://msdn.microsoft.com/en-us/library/cc243950/
*
*
*
* Connection Establishment
*
* Client Outbound Proxy Inbound Proxy Server
* | | | |
* |-----------------IN Channel Request--------------->| |
* |---OUT Channel Request-->| |<-Legacy Server Response-|
* | |<--------------Legacy Server Response--------------|
* | | | |
* |---------CONN_A1-------->| | |
* |----------------------CONN_B1--------------------->| |
* | |----------------------CONN_A2--------------------->|
* | | | |
* |<--OUT Channel Response--| |---------CONN_B2-------->|
* |<--------CONN_A3---------| | |
* | |<---------------------CONN_C1----------------------|
* | | |<--------CONN_B3---------|
* |<--------CONN_C2---------| | |
* | | | |
*
*/
void rpc_pdu_header_print(wLog* log, const rpcconn_hdr_t* header)
{
WINPR_ASSERT(header);
WLog_Print(log, WLOG_INFO, "rpc_vers: %" PRIu8 "", header->common.rpc_vers);
WLog_Print(log, WLOG_INFO, "rpc_vers_minor: %" PRIu8 "", header->common.rpc_vers_minor);
if (header->common.ptype > PTYPE_RTS)
WLog_Print(log, WLOG_INFO, "ptype: %s (%" PRIu8 ")", "PTYPE_UNKNOWN", header->common.ptype);
else
WLog_Print(log, WLOG_INFO, "ptype: %s (%" PRIu8 ")", PTYPE_STRINGS[header->common.ptype],
header->common.ptype);
WLog_Print(log, WLOG_INFO, "pfc_flags (0x%02" PRIX8 ") = {", header->common.pfc_flags);
if (header->common.pfc_flags & PFC_FIRST_FRAG)
WLog_Print(log, WLOG_INFO, " PFC_FIRST_FRAG");
if (header->common.pfc_flags & PFC_LAST_FRAG)
WLog_Print(log, WLOG_INFO, " PFC_LAST_FRAG");
if (header->common.pfc_flags & PFC_PENDING_CANCEL)
WLog_Print(log, WLOG_INFO, " PFC_PENDING_CANCEL");
if (header->common.pfc_flags & PFC_RESERVED_1)
WLog_Print(log, WLOG_INFO, " PFC_RESERVED_1");
if (header->common.pfc_flags & PFC_CONC_MPX)
WLog_Print(log, WLOG_INFO, " PFC_CONC_MPX");
if (header->common.pfc_flags & PFC_DID_NOT_EXECUTE)
WLog_Print(log, WLOG_INFO, " PFC_DID_NOT_EXECUTE");
if (header->common.pfc_flags & PFC_OBJECT_UUID)
WLog_Print(log, WLOG_INFO, " PFC_OBJECT_UUID");
WLog_Print(log, WLOG_INFO, " }");
WLog_Print(log, WLOG_INFO,
"packed_drep[4]: %02" PRIX8 " %02" PRIX8 " %02" PRIX8 " %02" PRIX8 "",
header->common.packed_drep[0], header->common.packed_drep[1],
header->common.packed_drep[2], header->common.packed_drep[3]);
WLog_Print(log, WLOG_INFO, "frag_length: %" PRIu16 "", header->common.frag_length);
WLog_Print(log, WLOG_INFO, "auth_length: %" PRIu16 "", header->common.auth_length);
WLog_Print(log, WLOG_INFO, "call_id: %" PRIu32 "", header->common.call_id);
if (header->common.ptype == PTYPE_RESPONSE)
{
WLog_Print(log, WLOG_INFO, "alloc_hint: %" PRIu32 "", header->response.alloc_hint);
WLog_Print(log, WLOG_INFO, "p_cont_id: %" PRIu16 "", header->response.p_cont_id);
WLog_Print(log, WLOG_INFO, "cancel_count: %" PRIu8 "", header->response.cancel_count);
WLog_Print(log, WLOG_INFO, "reserved: %" PRIu8 "", header->response.reserved);
}
}
rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc)
{
rpcconn_common_hdr_t header = WINPR_C_ARRAY_INIT;
WINPR_ASSERT(rpc);
header.rpc_vers = rpc->rpc_vers;
header.rpc_vers_minor = rpc->rpc_vers_minor;
header.packed_drep[0] = rpc->packed_drep[0];
header.packed_drep[1] = rpc->packed_drep[1];
header.packed_drep[2] = rpc->packed_drep[2];
header.packed_drep[3] = rpc->packed_drep[3];
return header;
}
size_t rpc_offset_align(size_t* offset, size_t alignment)
{
size_t pad = 0;
pad = *offset;
*offset = (*offset + alignment - 1) & ~(alignment - 1);
pad = *offset - pad;
return pad;
}
size_t rpc_offset_pad(size_t* offset, size_t pad)
{
*offset += pad;
return pad;
}
/*
* PDU Segments:
* ________________________________
* | |
* | PDU Header |
* |________________________________|
* | |
* | |
* | PDU Body |
* | |
* |________________________________|
* | |
* | Security Trailer |
* |________________________________|
* | |
* | Authentication Token |
* |________________________________|
*/
/*
* PDU Structure with verification trailer
*
* MUST only appear in a request PDU!
* ________________________________
* | |
* | PDU Header |
* |________________________________| _______
* | | /|\
* | | |
* | Stub Data | |
* | | |
* |________________________________| |
* | | PDU Body
* | Stub Pad | |
* |________________________________| |
* | | |
* | Verification Trailer | |
* |________________________________| |
* | | |
* | Authentication Pad | |
* |________________________________| __\|/__
* | |
* | Security Trailer |
* |________________________________|
* | |
* | Authentication Token |
* |________________________________|
*
*/
/*
* Security Trailer:
*
* The sec_trailer structure MUST be placed at the end of the PDU, including past stub data,
* when present. The sec_trailer structure MUST be 4-byte aligned with respect to the beginning
* of the PDU. Padding octets MUST be used to align the sec_trailer structure if its natural
* beginning is not already 4-byte aligned.
*
* All PDUs that carry sec_trailer information share certain common fields:
* frag_length and auth_length. The beginning of the sec_trailer structure for each PDU MUST be
* calculated to start from offset (frag_length auth_length 8) from the beginning of the PDU.
*
* Immediately after the sec_trailer structure, there MUST be a BLOB carrying the authentication
* information produced by the security provider. This BLOB is called the authentication token and
* MUST be of size auth_length. The size MUST also be equal to the length from the first octet
* immediately after the sec_trailer structure all the way to the end of the fragment;
* the two values MUST be the same.
*
* A client or a server that (during composing of a PDU) has allocated more space for the
* authentication token than the security provider fills in SHOULD fill in the rest of
* the allocated space with zero octets. These zero octets are still considered to belong
* to the authentication token part of the PDU.
*
*/
BOOL rpc_get_stub_data_info(rdpRpc* rpc, const rpcconn_hdr_t* header, size_t* poffset,
size_t* length)
{
size_t used = 0;
size_t offset = 0;
BOOL rc = FALSE;
UINT32 frag_length = 0;
UINT32 auth_length = 0;
UINT32 auth_pad_length = 0;
UINT32 sec_trailer_offset = 0;
const rpc_sec_trailer* sec_trailer = nullptr;
WINPR_ASSERT(rpc);
WINPR_ASSERT(header);
WINPR_ASSERT(poffset);
WINPR_ASSERT(length);
offset = RPC_COMMON_FIELDS_LENGTH;
switch (header->common.ptype)
{
case PTYPE_RESPONSE:
offset += 8;
rpc_offset_align(&offset, 8);
sec_trailer = &header->response.auth_verifier;
break;
case PTYPE_REQUEST:
offset += 4;
rpc_offset_align(&offset, 8);
sec_trailer = &header->request.auth_verifier;
break;
case PTYPE_RTS:
offset += 4;
break;
default:
WLog_Print(rpc->log, WLOG_ERROR, "Unknown PTYPE: 0x%02" PRIX8 "", header->common.ptype);
goto fail;
}
frag_length = header->common.frag_length;
auth_length = header->common.auth_length;
if (poffset)
*poffset = offset;
/* The fragment must be larger than the authentication trailer */
used = offset + auth_length + 8ull;
if (sec_trailer)
{
auth_pad_length = sec_trailer->auth_pad_length;
used += sec_trailer->auth_pad_length;
}
if (frag_length < used)
goto fail;
if (!length)
return TRUE;
sec_trailer_offset = frag_length - auth_length - 8;
/*
* According to [MS-RPCE], auth_pad_length is the number of padding
* octets used to 4-byte align the security trailer, but in practice
* we get values up to 15, which indicates 16-byte alignment.
*/
if ((frag_length - (sec_trailer_offset + 8)) != auth_length)
{
WLog_Print(rpc->log, WLOG_ERROR,
"invalid auth_length: actual: %" PRIu32 ", expected: %" PRIu32 "", auth_length,
(frag_length - (sec_trailer_offset + 8)));
}
*length = sec_trailer_offset - auth_pad_length - offset;
rc = TRUE;
fail:
return rc;
}
SSIZE_T rpc_channel_read(RpcChannel* channel, wStream* s, size_t length)
{
int status = 0;
if (!channel || (length > INT32_MAX))
return -1;
ERR_clear_error();
status = BIO_read(channel->tls->bio, Stream_Pointer(s), (INT32)length);
if (status > 0)
{
Stream_Seek(s, (size_t)status);
return status;
}
if (BIO_should_retry(channel->tls->bio))
return 0;
WLog_Print(channel->rpc->log, WLOG_ERROR, "rpc_channel_read: Out of retries");
return -1;
}
SSIZE_T rpc_channel_write_int(RpcChannel* channel, const BYTE* data, size_t length,
const char* file, size_t line, const char* fkt)
{
WINPR_ASSERT(channel);
WINPR_ASSERT(channel->rpc);
const DWORD level = WLOG_TRACE;
if (WLog_IsLevelActive(channel->rpc->log, level))
{
WLog_PrintTextMessage(channel->rpc->log, level, line, file, fkt,
"Sending [%s] %" PRIuz " bytes", fkt, length);
}
return freerdp_tls_write_all(channel->tls, data, length);
}
BOOL rpc_in_channel_transition_to_state(RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state)
{
WINPR_ASSERT(inChannel);
inChannel->State = state;
WLog_Print(inChannel->common.rpc->log, WLOG_DEBUG, "%s", client_in_state_str(state));
return TRUE;
}
static int rpc_channel_rpch_init(RpcClient* client, RpcChannel* channel, const char* inout,
const GUID* guid)
{
HttpContext* http = nullptr;
rdpSettings* settings = nullptr;
UINT32 timeout = 0;
if (!client || !channel || !inout || !client->context || !client->context->settings)
return -1;
settings = client->context->settings;
channel->auth = credssp_auth_new(client->context);
if (!rts_generate_cookie((BYTE*)&channel->Cookie))
return -1;
channel->client = client;
if (!channel->auth)
return -1;
channel->http = http_context_new();
if (!channel->http)
return -1;
http = channel->http;
{
if (!http_context_set_pragma(http, "ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729"))
return -1;
if (guid)
{
RPC_CSTR strguid = nullptr;
RPC_STATUS rpcStatus = UuidToStringA(guid, &strguid);
if (rpcStatus != RPC_S_OK)
return -1;
const BOOL rc = http_context_append_pragma(http, "SessionId=%s", strguid);
RpcStringFreeA(&strguid);
if (!rc)
return -1;
}
if (timeout)
{
if (!http_context_append_pragma(http, "MinConnTimeout=%" PRIu32, timeout))
return -1;
}
if (!http_context_set_rdg_correlation_id(http, guid) ||
!http_context_set_rdg_connection_id(http, guid))
return -1;
}
/* TODO: "/rpcwithcert/rpcproxy.dll". */
if (!http_context_set_method(http, inout) ||
!http_context_set_uri(http, "/rpc/rpcproxy.dll?localhost:3388") ||
!http_context_set_accept(http, "application/rpc") ||
!http_context_set_cache_control(http, "no-cache") ||
!http_context_set_connection(http, "Keep-Alive") ||
!http_context_set_user_agent(http, "MSRPC") ||
!http_context_set_host(http, settings->GatewayHostname))
return -1;
return 1;
}
static int rpc_in_channel_init(rdpRpc* rpc, RpcInChannel* inChannel, const GUID* guid)
{
WINPR_ASSERT(rpc);
WINPR_ASSERT(inChannel);
inChannel->common.rpc = rpc;
inChannel->State = CLIENT_IN_CHANNEL_STATE_INITIAL;
inChannel->BytesSent = 0;
inChannel->SenderAvailableWindow = rpc->ReceiveWindow;
inChannel->PingOriginator.ConnectionTimeout = 30;
inChannel->PingOriginator.KeepAliveInterval = 0;
if (rpc_channel_rpch_init(rpc->client, &inChannel->common, "RPC_IN_DATA", guid) < 0)
return -1;
return 1;
}
static RpcInChannel* rpc_in_channel_new(rdpRpc* rpc, const GUID* guid)
{
RpcInChannel* inChannel = (RpcInChannel*)calloc(1, sizeof(RpcInChannel));
if (inChannel)
{
rpc_in_channel_init(rpc, inChannel, guid);
}
return inChannel;
}
void rpc_channel_free(RpcChannel* channel)
{
if (!channel)
return;
credssp_auth_free(channel->auth);
http_context_free(channel->http);
freerdp_tls_free(channel->tls);
free(channel);
}
BOOL rpc_out_channel_transition_to_state(RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state)
{
WINPR_ASSERT(outChannel);
outChannel->State = state;
WLog_Print(outChannel->common.rpc->log, WLOG_DEBUG, "%s", client_out_state_str(state));
return TRUE;
}
static int rpc_out_channel_init(rdpRpc* rpc, RpcOutChannel* outChannel, const GUID* guid)
{
WINPR_ASSERT(rpc);
WINPR_ASSERT(outChannel);
outChannel->common.rpc = rpc;
outChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL;
outChannel->BytesReceived = 0;
outChannel->ReceiverAvailableWindow = rpc->ReceiveWindow;
outChannel->ReceiveWindow = rpc->ReceiveWindow;
outChannel->ReceiveWindowSize = rpc->ReceiveWindow;
outChannel->AvailableWindowAdvertised = rpc->ReceiveWindow;
if (rpc_channel_rpch_init(rpc->client, &outChannel->common, "RPC_OUT_DATA", guid) < 0)
return -1;
return 1;
}
RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc, const GUID* guid)
{
RpcOutChannel* outChannel = (RpcOutChannel*)calloc(1, sizeof(RpcOutChannel));
if (outChannel)
{
rpc_out_channel_init(rpc, outChannel, guid);
}
return outChannel;
}
BOOL rpc_virtual_connection_transition_to_state(rdpRpc* rpc, RpcVirtualConnection* connection,
VIRTUAL_CONNECTION_STATE state)
{
WINPR_ASSERT(connection);
WINPR_ASSERT(rpc);
connection->State = state;
WLog_Print(rpc->log, WLOG_DEBUG, "%s", rpc_vc_state_str(state));
return TRUE;
}
static void rpc_virtual_connection_free(RpcVirtualConnection* connection)
{
if (!connection)
return;
if (connection->DefaultInChannel)
rpc_channel_free(&connection->DefaultInChannel->common);
if (connection->NonDefaultInChannel)
rpc_channel_free(&connection->NonDefaultInChannel->common);
if (connection->DefaultOutChannel)
rpc_channel_free(&connection->DefaultOutChannel->common);
if (connection->NonDefaultOutChannel)
rpc_channel_free(&connection->NonDefaultOutChannel->common);
free(connection);
}
static RpcVirtualConnection* rpc_virtual_connection_new(rdpRpc* rpc)
{
WINPR_ASSERT(rpc);
RpcVirtualConnection* connection =
(RpcVirtualConnection*)calloc(1, sizeof(RpcVirtualConnection));
if (!connection)
return nullptr;
if (!rts_generate_cookie((BYTE*)&(connection->Cookie)))
goto fail;
if (!rts_generate_cookie((BYTE*)&(connection->AssociationGroupId)))
goto fail;
connection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
connection->DefaultInChannel = rpc_in_channel_new(rpc, &connection->Cookie);
if (!connection->DefaultInChannel)
goto fail;
connection->DefaultOutChannel = rpc_out_channel_new(rpc, &connection->Cookie);
if (!connection->DefaultOutChannel)
goto fail;
return connection;
fail:
rpc_virtual_connection_free(connection);
return nullptr;
}
static BOOL rpc_channel_tls_connect(RpcChannel* channel, UINT32 timeout)
{
if (!channel || !channel->client || !channel->client->context ||
!channel->client->context->settings)
return FALSE;
rdpContext* context = channel->client->context;
WINPR_ASSERT(context);
rdpSettings* settings = context->settings;
WINPR_ASSERT(settings);
const char* proxyUsername = freerdp_settings_get_string(settings, FreeRDP_ProxyUsername);
const char* proxyPassword = freerdp_settings_get_string(settings, FreeRDP_ProxyPassword);
rdpTransport* transport = freerdp_get_transport(context);
rdpTransportLayer* layer =
transport_connect_layer(transport, channel->client->host, channel->client->port, timeout);
if (!layer)
return FALSE;
BIO* layerBio = BIO_new(BIO_s_transport_layer());
if (!layerBio)
{
transport_layer_free(layer);
return FALSE;
}
BIO_set_data(layerBio, layer);
BIO* bufferedBio = BIO_new(BIO_s_buffered_socket());
if (!bufferedBio)
{
BIO_free_all(layerBio);
return FALSE;
}
bufferedBio = BIO_push(bufferedBio, layerBio);
if (!BIO_set_nonblock(bufferedBio, TRUE))
{
BIO_free_all(bufferedBio);
return FALSE;
}
if (channel->client->isProxy)
{
WINPR_ASSERT(settings->GatewayPort <= UINT16_MAX);
if (!proxy_connect(context, bufferedBio, proxyUsername, proxyPassword,
settings->GatewayHostname, (UINT16)settings->GatewayPort))
{
BIO_free_all(bufferedBio);
return FALSE;
}
}
channel->bio = bufferedBio;
rdpTls* tls = channel->tls = freerdp_tls_new(context);
if (!tls)
return FALSE;
tls->hostname = settings->GatewayHostname;
tls->port = WINPR_ASSERTING_INT_CAST(int32_t, MIN(UINT16_MAX, settings->GatewayPort));
tls->isGatewayTransport = TRUE;
int tlsStatus = freerdp_tls_connect(tls, bufferedBio);
if (tlsStatus < 1)
{
if (tlsStatus < 0)
{
freerdp_set_last_error_if_not(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
}
else
{
freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
}
return FALSE;
}
return TRUE;
}
static int rpc_in_channel_connect(RpcInChannel* inChannel, UINT32 timeout)
{
rdpContext* context = nullptr;
if (!inChannel || !inChannel->common.client || !inChannel->common.client->context)
return -1;
context = inChannel->common.client->context;
/* Connect IN Channel */
if (!rpc_channel_tls_connect(&inChannel->common, timeout))
return -1;
rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_CONNECTED);
if (!rpc_ncacn_http_auth_init(context, &inChannel->common))
return -1;
/* Send IN Channel Request */
if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
{
WLog_Print(inChannel->common.rpc->log, WLOG_ERROR,
"rpc_ncacn_http_send_in_channel_request failure");
return -1;
}
if (!rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_SECURITY))
return -1;
return 1;
}
static int rpc_out_channel_connect(RpcOutChannel* outChannel, UINT32 timeout)
{
rdpContext* context = nullptr;
if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
return -1;
context = outChannel->common.client->context;
/* Connect OUT Channel */
if (!rpc_channel_tls_connect(&outChannel->common, timeout))
return -1;
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
if (!rpc_ncacn_http_auth_init(context, &outChannel->common))
return FALSE;
/* Send OUT Channel Request */
if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
{
WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
"rpc_ncacn_http_send_out_channel_request failure");
return FALSE;
}
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
return 1;
}
int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, uint32_t timeout)
{
rdpContext* context = nullptr;
if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
return -1;
context = outChannel->common.client->context;
/* Connect OUT Channel */
if (!rpc_channel_tls_connect(&outChannel->common, timeout))
return -1;
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
if (!rpc_ncacn_http_auth_init(context, (RpcChannel*)outChannel))
return FALSE;
/* Send OUT Channel Request */
if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, TRUE))
{
WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
"rpc_ncacn_http_send_out_channel_request failure");
return FALSE;
}
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
return 1;
}
BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout)
{
RpcInChannel* inChannel = nullptr;
RpcOutChannel* outChannel = nullptr;
RpcVirtualConnection* connection = nullptr;
rpc->VirtualConnection = rpc_virtual_connection_new(rpc);
if (!rpc->VirtualConnection)
return FALSE;
connection = rpc->VirtualConnection;
inChannel = connection->DefaultInChannel;
outChannel = connection->DefaultOutChannel;
rpc_virtual_connection_transition_to_state(rpc, connection, VIRTUAL_CONNECTION_STATE_INITIAL);
if (rpc_in_channel_connect(inChannel, timeout) < 0)
return FALSE;
if (rpc_out_channel_connect(outChannel, timeout) < 0)
return FALSE;
return TRUE;
}
rdpRpc* rpc_new(rdpTransport* transport)
{
rdpContext* context = transport_get_context(transport);
rdpRpc* rpc = nullptr;
WINPR_ASSERT(context);
rpc = (rdpRpc*)calloc(1, sizeof(rdpRpc));
if (!rpc)
return nullptr;
rpc->log = WLog_Get(TAG);
rpc->State = RPC_CLIENT_STATE_INITIAL;
rpc->transport = transport;
rpc->SendSeqNum = 0;
rpc->auth = credssp_auth_new(context);
if (!rpc->auth)
goto out_free;
rpc->PipeCallId = 0;
rpc->StubCallId = 0;
rpc->StubFragCount = 0;
rpc->rpc_vers = 5;
rpc->rpc_vers_minor = 0;
/* little-endian data representation */
rpc->packed_drep[0] = 0x10;
rpc->packed_drep[1] = 0x00;
rpc->packed_drep[2] = 0x00;
rpc->packed_drep[3] = 0x00;
rpc->max_xmit_frag = 0x0FF8;
rpc->max_recv_frag = 0x0FF8;
rpc->ReceiveWindow = 0x00010000;
rpc->ChannelLifetime = 0x40000000;
rpc->KeepAliveInterval = 300000;
rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval;
rpc->CurrentKeepAliveTime = 0;
rpc->CallId = 2;
rpc->client = rpc_client_new(context, rpc->max_recv_frag);
if (!rpc->client)
goto out_free;
return rpc;
out_free:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
rpc_free(rpc);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
void rpc_free(rdpRpc* rpc)
{
if (rpc)
{
rpc_client_free(rpc->client);
credssp_auth_free(rpc->auth);
rpc_virtual_connection_free(rpc->VirtualConnection);
free(rpc);
}
}

View File

@@ -0,0 +1,819 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC over HTTP
*
* Copyright 2012 Fujitsu Technology Solutions GmbH
* Copyright 2012 Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_RPC_H
#define FREERDP_LIB_CORE_GATEWAY_RPC_H
#include <winpr/wtypes.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
#include <winpr/interlocked.h>
#include <freerdp/log.h>
#include <freerdp/utils/ringbuffer.h>
#include "../../crypto/tls.h"
typedef struct rdp_rpc rdpRpc;
#pragma pack(push, 1)
typedef struct
{
BYTE rpc_vers;
BYTE rpc_vers_minor;
BYTE ptype;
BYTE pfc_flags;
BYTE packed_drep[4];
UINT16 frag_length;
UINT16 auth_length;
UINT32 call_id;
} rpcconn_common_hdr_t;
#define RPC_COMMON_FIELDS_LENGTH sizeof(rpcconn_common_hdr_t)
typedef struct
{
rpcconn_common_hdr_t header;
UINT16 Flags;
UINT16 NumberOfCommands;
} rpcconn_rts_hdr_t;
#define RTS_PDU_HEADER_LENGTH 20
#define RPC_PDU_FLAG_STUB 0x00000001
typedef struct
{
wStream* s;
UINT32 Type;
UINT32 Flags;
UINT32 CallId;
} RPC_PDU, *PRPC_PDU;
#pragma pack(pop)
#include "../tcp.h"
#include "../transport.h"
#include "http.h"
#include "../credssp_auth.h"
#include <time.h>
#include <winpr/sspi.h>
#include <winpr/interlocked.h>
#include <freerdp/types.h>
#include <freerdp/settings.h>
#include <freerdp/crypto/crypto.h>
#include <freerdp/api.h>
#include <winpr/print.h>
/**
* CAE Specification
* DCE 1.1: Remote Procedure Call
* Document Number: C706
* http://pubs.opengroup.org/onlinepubs/9629399/
*/
#define PTYPE_REQUEST 0x00
#define PTYPE_PING 0x01
#define PTYPE_RESPONSE 0x02
#define PTYPE_FAULT 0x03
#define PTYPE_WORKING 0x04
#define PTYPE_NOCALL 0x05
#define PTYPE_REJECT 0x06
#define PTYPE_ACK 0x07
#define PTYPE_CL_CANCEL 0x08
#define PTYPE_FACK 0x09
#define PTYPE_CANCEL_ACK 0x0A
#define PTYPE_BIND 0x0B
#define PTYPE_BIND_ACK 0x0C
#define PTYPE_BIND_NAK 0x0D
#define PTYPE_ALTER_CONTEXT 0x0E
#define PTYPE_ALTER_CONTEXT_RESP 0x0F
#define PTYPE_RPC_AUTH_3 0x10
#define PTYPE_SHUTDOWN 0x11
#define PTYPE_CO_CANCEL 0x12
#define PTYPE_ORPHANED 0x13
#define PTYPE_RTS 0x14
#define PFC_FIRST_FRAG 0x01
#define PFC_LAST_FRAG 0x02
#define PFC_PENDING_CANCEL 0x04
#define PFC_SUPPORT_HEADER_SIGN 0x04
#define PFC_RESERVED_1 0x08
#define PFC_CONC_MPX 0x10
#define PFC_DID_NOT_EXECUTE 0x20
#define PFC_MAYBE 0x40
#define PFC_OBJECT_UUID 0x80
/* Minimum fragment sizes */
#define RPC_CO_MUST_RECV_FRAG_SIZE 1432
#define RPC_CL_MUST_RECV_FRAG_SIZE 1464
/**
* The PDU maximum header length is enough
* to contain either the RPC common fields
* or all fields up to the stub data in PDUs
* that use it (request, response, fault)
*/
#define RPC_PDU_HEADER_MAX_LENGTH 32
#pragma pack(push, 1)
typedef UINT16 p_context_id_t;
typedef UINT16 p_reject_reason_t;
typedef struct
{
UINT32 time_low;
UINT16 time_mid;
UINT16 time_hi_and_version;
BYTE clock_seq_hi_and_reserved;
BYTE clock_seq_low;
BYTE node[6];
} p_uuid_t;
#define ndr_c_int_big_endian 0
#define ndr_c_int_little_endian 1
#define ndr_c_float_ieee 0
#define ndr_c_float_vax 1
#define ndr_c_float_cray 2
#define ndr_c_float_ibm 3
#define ndr_c_char_ascii 0
#define ndr_c_char_ebcdic 1
typedef struct
{
BYTE int_rep;
BYTE char_rep;
BYTE float_rep;
BYTE reserved;
} ndr_format_t, *ndr_format_p_t;
typedef struct ndr_context_handle
{
UINT32 context_handle_attributes;
p_uuid_t context_handle_uuid;
} ndr_context_handle;
typedef struct
{
p_uuid_t if_uuid;
UINT32 if_version;
} p_syntax_id_t;
typedef struct
{
p_context_id_t p_cont_id;
BYTE n_transfer_syn; /* number of items */
BYTE reserved; /* alignment pad, m.b.z. */
p_syntax_id_t abstract_syntax; /* transfer syntax list */
p_syntax_id_t* transfer_syntaxes; /* size_is(n_transfer_syn) */
} p_cont_elem_t;
typedef struct
{
BYTE n_context_elem; /* number of items */
BYTE reserved; /* alignment pad, m.b.z. */
UINT16 reserved2; /* alignment pad, m.b.z. */
p_cont_elem_t* p_cont_elem; /* size_is(n_cont_elem) */
} p_cont_list_t;
typedef enum
{
acceptance,
user_rejection,
provider_rejection,
negotiate_ack
} p_cont_def_result_t;
typedef enum
{
reason_not_specified,
abstract_syntax_not_supported,
proposed_transfer_syntaxes_not_supported,
local_limit_exceeded
} p_provider_reason_t;
typedef struct
{
p_cont_def_result_t result;
p_provider_reason_t reason;
p_syntax_id_t transfer_syntax;
} p_result_t;
/* Same order and number of elements as in bind request */
typedef struct
{
BYTE n_results; /* count */
BYTE reserved; /* alignment pad, m.b.z. */
UINT16 reserved2; /* alignment pad, m.b.z. */
p_result_t* p_results; /* size_is(n_results) */
} p_result_list_t;
typedef struct
{
BYTE major;
BYTE minor;
} version_t;
typedef version_t p_rt_version_t;
typedef struct
{
BYTE n_protocols; /* count */
p_rt_version_t* p_protocols; /* size_is(n_protocols) */
} p_rt_versions_supported_t;
typedef struct
{
UINT16 length;
char* port_spec; /* port string spec; size_is(length) */
} port_any_t;
typedef enum
{
REASON_NOT_SPECIFIED = 0,
TEMPORARY_CONGESTION = 1,
LOCAL_LIMIT_EXCEEDED = 2,
CALLED_PADDR_UNKNOWN = 3,
PROTOCOL_VERSION_NOT_SUPPORTED = 4,
DEFAULT_CONTEXT_NOT_SUPPORTED = 5,
USER_DATA_NOT_READABLE = 6,
NO_PSAP_AVAILABLE = 7,
authentication_type_not_recognized = 8,
invalid_checksum = 9
} bind_rejection_t;
typedef UINT16 rpcrt_reason_code_t;
typedef struct
{
BYTE rpc_vers;
BYTE rpc_vers_minor;
BYTE reserved[2];
BYTE packed_drep[4];
UINT32 reject_status;
BYTE reserved2[4];
} rpcrt_optional_data_t;
typedef struct
{
rpcrt_reason_code_t reason_code;
rpcrt_optional_data_t rpc_info;
} rpcconn_reject_optional_data_t;
typedef struct
{
rpcrt_reason_code_t reason_code;
rpcrt_optional_data_t rpc_info;
} rpcconn_disc_optional_data_t;
typedef struct
{
BYTE signature[8];
} rpc_sec_verification_trailer;
struct auth_verifier_co_s
{
/* restore 4-byte alignment */
BYTE auth_type;
BYTE auth_level;
BYTE auth_pad_length;
BYTE auth_reserved;
UINT32 auth_context_id;
BYTE* auth_value;
};
typedef struct auth_verifier_co_s rpc_sec_trailer;
typedef struct auth_verifier_co_s auth_verifier_co_t;
/* Connection-oriented PDU Definitions */
typedef struct
{
rpcconn_common_hdr_t header;
UINT16 max_xmit_frag;
UINT16 max_recv_frag;
UINT32 assoc_group_id;
p_cont_list_t p_context_elem;
auth_verifier_co_t auth_verifier;
} rpcconn_alter_context_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
UINT16 max_xmit_frag;
UINT16 max_recv_frag;
UINT32 assoc_group_id;
port_any_t sec_addr;
/* restore 4-octet alignment */
p_result_list_t p_result_list;
auth_verifier_co_t auth_verifier;
} rpcconn_alter_context_response_hdr_t;
/* bind header */
typedef struct
{
rpcconn_common_hdr_t header;
UINT16 max_xmit_frag;
UINT16 max_recv_frag;
UINT32 assoc_group_id;
p_cont_list_t p_context_elem;
auth_verifier_co_t auth_verifier;
} rpcconn_bind_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
UINT16 max_xmit_frag;
UINT16 max_recv_frag;
UINT32 assoc_group_id;
port_any_t sec_addr;
/* restore 4-octet alignment */
p_result_list_t p_result_list;
auth_verifier_co_t auth_verifier;
} rpcconn_bind_ack_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
UINT16 max_xmit_frag;
UINT16 max_recv_frag;
auth_verifier_co_t auth_verifier;
} rpcconn_rpc_auth_3_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
p_reject_reason_t provider_reject_reason;
p_rt_versions_supported_t versions;
} rpcconn_bind_nak_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
auth_verifier_co_t auth_verifier;
} rpcconn_cancel_hdr_t;
#pragma pack(pop)
/* fault codes */
typedef struct
{
UINT32 code;
const char* name;
const char* category;
} RPC_FAULT_CODE;
#define DEFINE_RPC_FAULT_CODE(_code, cat) \
{ \
_code, #_code, cat \
}
#define nca_s_comm_failure 0x1C010001
#define nca_s_op_rng_error 0x1C010002
#define nca_s_unk_if 0x1C010003
#define nca_s_wrong_boot_time 0x1C010006
#define nca_s_you_crashed 0x1C010009
#define nca_s_proto_error 0x1C01000B
#define nca_s_out_args_too_big 0x1C010013
#define nca_s_server_too_busy 0x1C010014
#define nca_s_fault_string_too_long 0x1C010015
#define nca_s_unsupported_type 0x1C010017
#define nca_s_fault_int_div_by_zero 0x1C000001
#define nca_s_fault_addr_error 0x1C000002
#define nca_s_fault_fp_div_zero 0x1C000003
#define nca_s_fault_fp_underflow 0x1C000004
#define nca_s_fault_fp_overflow 0x1C000005
#define nca_s_fault_invalid_tag 0x1C000006
#define nca_s_fault_invalid_bound 0x1C000007
#define nca_s_rpc_version_mismatch 0x1C000008
#define nca_s_unspec_reject 0x1C000009
#define nca_s_bad_actid 0x1C00000A
#define nca_s_who_are_you_failed 0x1C00000B
#define nca_s_manager_not_entered 0x1C00000C
#define nca_s_fault_cancel 0x1C00000D
#define nca_s_fault_ill_inst 0x1C00000E
#define nca_s_fault_fp_error 0x1C00000F
#define nca_s_fault_int_overflow 0x1C000010
#define nca_s_fault_unspec 0x1C000012
#define nca_s_fault_remote_comm_failure 0x1C000013
#define nca_s_fault_pipe_empty 0x1C000014
#define nca_s_fault_pipe_closed 0x1C000015
#define nca_s_fault_pipe_order 0x1C000016
#define nca_s_fault_pipe_discipline 0x1C000017
#define nca_s_fault_pipe_comm_error 0x1C000018
#define nca_s_fault_pipe_memory 0x1C000019
#define nca_s_fault_context_mismatch 0x1C00001A
#define nca_s_fault_remote_no_memory 0x1C00001B
#define nca_s_invalid_pres_context_id 0x1C00001C
#define nca_s_unsupported_authn_level 0x1C00001D
#define nca_s_invalid_checksum 0x1C00001F
#define nca_s_invalid_crc 0x1C000020
#define nca_s_fault_user_defined 0x1C000021
#define nca_s_fault_tx_open_failed 0x1C000022
#define nca_s_fault_codeset_conv_error 0x1C000023
#define nca_s_fault_object_not_found 0x1C000024
#define nca_s_fault_no_client_stub 0x1C000025
#pragma pack(push, 1)
typedef struct
{
rpcconn_common_hdr_t header;
UINT32 alloc_hint;
p_context_id_t p_cont_id;
BYTE cancel_count;
BYTE reserved;
UINT32 status;
/* align(8) */
BYTE* stub_data;
auth_verifier_co_t auth_verifier;
} rpcconn_fault_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
auth_verifier_co_t auth_verifier;
} rpcconn_orphaned_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
UINT32 alloc_hint;
p_context_id_t p_cont_id;
UINT16 opnum;
/* optional field for request, only present if the PFC_OBJECT_UUID field is non-zero */
p_uuid_t object;
/* align(8) */
BYTE* stub_data;
auth_verifier_co_t auth_verifier;
} rpcconn_request_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
UINT32 alloc_hint;
p_context_id_t p_cont_id;
BYTE cancel_count;
BYTE reserved;
/* align(8) */
BYTE* stub_data;
auth_verifier_co_t auth_verifier;
} rpcconn_response_hdr_t;
typedef struct
{
rpcconn_common_hdr_t header;
} rpcconn_shutdown_hdr_t;
typedef union
{
rpcconn_common_hdr_t common;
rpcconn_alter_context_hdr_t alter_context;
rpcconn_alter_context_response_hdr_t alter_context_response;
rpcconn_bind_hdr_t bind;
rpcconn_bind_ack_hdr_t bind_ack;
rpcconn_rpc_auth_3_hdr_t rpc_auth_3;
rpcconn_bind_nak_hdr_t bind_nak;
rpcconn_cancel_hdr_t cancel;
rpcconn_fault_hdr_t fault;
rpcconn_orphaned_hdr_t orphaned;
rpcconn_request_hdr_t request;
rpcconn_response_hdr_t response;
rpcconn_shutdown_hdr_t shutdown;
rpcconn_rts_hdr_t rts;
} rpcconn_hdr_t;
#pragma pack(pop)
typedef struct
{
UINT32 Id;
LONG EvenLegs;
LONG NumLegs;
} RPC_SECURITY_PROVIDER_INFO;
typedef enum
{
RPC_CLIENT_STATE_INITIAL,
RPC_CLIENT_STATE_ESTABLISHED,
RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK,
RPC_CLIENT_STATE_WAIT_UNSECURE_BIND_ACK,
RPC_CLIENT_STATE_WAIT_SECURE_ALTER_CONTEXT_RESPONSE,
RPC_CLIENT_STATE_CONTEXT_NEGOTIATED,
RPC_CLIENT_STATE_WAIT_RESPONSE,
RPC_CLIENT_STATE_FINAL
} RPC_CLIENT_STATE;
typedef enum
{
RPC_CLIENT_CALL_STATE_INITIAL,
RPC_CLIENT_CALL_STATE_SEND_PDUS,
RPC_CLIENT_CALL_STATE_DISPATCHED,
RPC_CLIENT_CALL_STATE_RECEIVE_PDU,
RPC_CLIENT_CALL_STATE_COMPLETE,
RPC_CLIENT_CALL_STATE_FAULT,
RPC_CLIENT_CALL_STATE_FINAL
} RPC_CLIENT_CALL_STATE;
typedef struct
{
UINT32 CallId;
UINT32 OpNum;
RPC_CLIENT_CALL_STATE State;
} RpcClientCall;
typedef struct
{
rdpContext* context;
RPC_PDU* pdu;
HANDLE PipeEvent;
RingBuffer ReceivePipe;
wStream* ReceiveFragment;
CRITICAL_SECTION PipeLock;
wArrayList* ClientCallList;
char* host;
UINT16 port;
BOOL isProxy;
} RpcClient;
typedef struct
{
RpcClient* client;
BIO* bio;
rdpTls* tls;
rdpCredsspAuth* auth;
HttpContext* http;
GUID Cookie;
rdpRpc* rpc;
} RpcChannel;
/* Ping Originator */
typedef struct
{
UINT32 ConnectionTimeout;
UINT32 LastPacketSentTimestamp;
UINT32 KeepAliveInterval;
} RpcPingOriginator;
/* Client In Channel */
typedef enum
{
CLIENT_IN_CHANNEL_STATE_INITIAL,
CLIENT_IN_CHANNEL_STATE_CONNECTED,
CLIENT_IN_CHANNEL_STATE_SECURITY,
CLIENT_IN_CHANNEL_STATE_NEGOTIATED,
CLIENT_IN_CHANNEL_STATE_OPENED,
CLIENT_IN_CHANNEL_STATE_OPENED_A4W,
CLIENT_IN_CHANNEL_STATE_FINAL
} CLIENT_IN_CHANNEL_STATE;
typedef struct
{
/* Sending Channel */
RpcChannel common;
CLIENT_IN_CHANNEL_STATE State;
UINT32 PlugState;
void* SendQueue;
UINT32 BytesSent;
UINT32 SenderAvailableWindow;
UINT32 PeerReceiveWindow;
/* Ping Originator */
RpcPingOriginator PingOriginator;
} RpcInChannel;
/* Client Out Channel */
typedef enum
{
CLIENT_OUT_CHANNEL_STATE_INITIAL,
CLIENT_OUT_CHANNEL_STATE_CONNECTED,
CLIENT_OUT_CHANNEL_STATE_SECURITY,
CLIENT_OUT_CHANNEL_STATE_NEGOTIATED,
CLIENT_OUT_CHANNEL_STATE_OPENED,
CLIENT_OUT_CHANNEL_STATE_OPENED_A6W,
CLIENT_OUT_CHANNEL_STATE_OPENED_A10W,
CLIENT_OUT_CHANNEL_STATE_OPENED_B3W,
CLIENT_OUT_CHANNEL_STATE_RECYCLED,
CLIENT_OUT_CHANNEL_STATE_FINAL
} CLIENT_OUT_CHANNEL_STATE;
typedef struct
{
/* Receiving Channel */
RpcChannel common;
CLIENT_OUT_CHANNEL_STATE State;
UINT32 ReceiveWindow;
UINT32 ReceiveWindowSize;
UINT32 ReceiverAvailableWindow;
UINT32 BytesReceived;
UINT32 AvailableWindowAdvertised;
} RpcOutChannel;
/* Client Virtual Connection */
typedef enum
{
VIRTUAL_CONNECTION_STATE_INITIAL,
VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT,
VIRTUAL_CONNECTION_STATE_WAIT_A3W,
VIRTUAL_CONNECTION_STATE_WAIT_C2,
VIRTUAL_CONNECTION_STATE_OPENED,
VIRTUAL_CONNECTION_STATE_FINAL
} VIRTUAL_CONNECTION_STATE;
typedef struct
{
GUID Cookie;
GUID AssociationGroupId;
VIRTUAL_CONNECTION_STATE State;
RpcInChannel* DefaultInChannel;
RpcInChannel* NonDefaultInChannel;
RpcOutChannel* DefaultOutChannel;
RpcOutChannel* NonDefaultOutChannel;
} RpcVirtualConnection;
/* Virtual Connection Cookie Table */
#define RPC_UUID_FORMAT_STRING \
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define RPC_UUID_FORMAT_ARGUMENTS(_rpc_uuid) \
_rpc_uuid[0], _rpc_uuid[1], _rpc_uuid[2], _rpc_uuid[3], _rpc_uuid[4], _rpc_uuid[5], \
_rpc_uuid[6], _rpc_uuid[7], _rpc_uuid[8], _rpc_uuid[9], _rpc_uuid[10], _rpc_uuid[11], \
_rpc_uuid[12], _rpc_uuid[13], _rpc_uuid[14], _rpc_uuid[15]
typedef struct
{
GUID Cookie;
UINT32 ReferenceCount;
RpcVirtualConnection* Reference;
} RpcVirtualConnectionCookieEntry;
struct rdp_rpc
{
RPC_CLIENT_STATE State;
UINT32 result;
rdpCredsspAuth* auth;
UINT32 SendSeqNum;
RpcClient* client;
rdpTransport* transport;
UINT32 CallId;
UINT32 PipeCallId;
UINT32 StubCallId;
UINT32 StubFragCount;
BYTE rpc_vers;
BYTE rpc_vers_minor;
BYTE packed_drep[4];
UINT16 max_xmit_frag;
UINT16 max_recv_frag;
UINT32 ReceiveWindow;
UINT32 ChannelLifetime;
UINT32 KeepAliveInterval;
UINT32 CurrentKeepAliveTime;
UINT32 CurrentKeepAliveInterval;
RpcVirtualConnection* VirtualConnection;
wLog* log;
};
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rpc_vc_state_str(VIRTUAL_CONNECTION_STATE state);
FREERDP_LOCAL void rpc_pdu_header_print(wLog* log, const rpcconn_hdr_t* header);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc);
FREERDP_LOCAL size_t rpc_offset_align(size_t* offset, size_t alignment);
FREERDP_LOCAL size_t rpc_offset_pad(size_t* offset, size_t pad);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_get_stub_data_info(rdpRpc* rpc, const rpcconn_hdr_t* header, size_t* offset,
size_t* length);
#define rpc_channel_write(channel, data, length) \
rpc_channel_write_int((channel), (data), (length), __FILE__, __LINE__, __func__)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SSIZE_T rpc_channel_write_int(RpcChannel* channel, const BYTE* data, size_t length,
const char* file, size_t line, const char* fkt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SSIZE_T rpc_channel_read(RpcChannel* channel, wStream* s, size_t length);
FREERDP_LOCAL void rpc_channel_free(RpcChannel* channel);
WINPR_ATTR_MALLOC(rpc_channel_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc, const GUID* guid);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, uint32_t timeout);
FREERDP_LOCAL BOOL rpc_in_channel_transition_to_state(RpcInChannel* inChannel,
CLIENT_IN_CHANNEL_STATE state);
FREERDP_LOCAL BOOL rpc_out_channel_transition_to_state(RpcOutChannel* outChannel,
CLIENT_OUT_CHANNEL_STATE state);
FREERDP_LOCAL BOOL rpc_virtual_connection_transition_to_state(rdpRpc* rpc,
RpcVirtualConnection* connection,
VIRTUAL_CONNECTION_STATE state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout);
FREERDP_LOCAL void rpc_free(rdpRpc* rpc);
WINPR_ATTR_MALLOC(rpc_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpRpc* rpc_new(rdpTransport* transport);
#endif /* FREERDP_LIB_CORE_GATEWAY_RPC_H */

View File

@@ -0,0 +1,471 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC Secure Context Binding
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include "../settings.h"
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <freerdp/log.h>
#include "rpc_client.h"
#include "rts.h"
#include "rpc_bind.h"
#include "../utils.h"
#define TAG FREERDP_TAG("core.gateway.rpc")
#define AUTH_PKG NTLM_SSP_NAME
/**
* Connection-Oriented RPC Protocol Client Details:
* http://msdn.microsoft.com/en-us/library/cc243724/
*/
/* Syntax UUIDs */
const p_uuid_t TSGU_UUID = {
0x44E265DD, /* time_low */
0x7DAF, /* time_mid */
0x42CD, /* time_hi_and_version */
0x85, /* clock_seq_hi_and_reserved */
0x60, /* clock_seq_low */
{ 0x3C, 0xDB, 0x6E, 0x7A, 0x27, 0x29 } /* node[6] */
};
const p_uuid_t NDR_UUID = {
0x8A885D04, /* time_low */
0x1CEB, /* time_mid */
0x11C9, /* time_hi_and_version */
0x9F, /* clock_seq_hi_and_reserved */
0xE8, /* clock_seq_low */
{ 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60 } /* node[6] */
};
const p_uuid_t BTFN_UUID = {
0x6CB71C2C, /* time_low */
0x9812, /* time_mid */
0x4540, /* time_hi_and_version */
0x03, /* clock_seq_hi_and_reserved */
0x00, /* clock_seq_low */
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* node[6] */
};
/**
* Secure Connection-Oriented RPC Packet Sequence
*
* Client Server
* | |
* |-------------------SECURE_BIND-------------------->|
* | |
* |<----------------SECURE_BIND_ACK-------------------|
* | |
* |--------------------RPC_AUTH_3-------------------->|
* | |
* | |
* |------------------REQUEST_PDU_#1------------------>|
* |------------------REQUEST_PDU_#2------------------>|
* | |
* | ... |
* | |
* |<-----------------RESPONSE_PDU_#1------------------|
* |<-----------------RESPONSE_PDU_#2------------------|
* | |
* | ... |
*/
/**
* SECURE_BIND: RPC bind PDU with sec_trailer and auth_token. Auth_token is generated by calling
* the implementation equivalent of the abstract GSS_Init_sec_context call. Upon receiving that, the
* server calls the implementation equivalent of the abstract GSS_Accept_sec_context call, which
* returns an auth_token and continue status in this example. Assume the following:
*
* 1) The client chooses the auth_context_id field in the sec_trailer sent with this PDU to be 1.
*
* 2) The client uses the RPC_C_AUTHN_LEVEL_PKT_PRIVACY authentication level and the
* Authentication Service (AS) NTLM.
*
* 3) The client sets the PFC_SUPPORT_HEADER_SIGN flag in the PDU header.
*/
static int rpc_bind_setup(rdpRpc* rpc)
{
SEC_WINNT_AUTH_IDENTITY identity = WINPR_C_ARRAY_INIT;
WINPR_ASSERT(rpc);
rdpContext* context = transport_get_context(rpc->transport);
WINPR_ASSERT(context);
rdpSettings* settings = context->settings;
WINPR_ASSERT(settings);
freerdp* instance = context->instance;
WINPR_ASSERT(instance);
credssp_auth_free(rpc->auth);
rpc->auth = credssp_auth_new(context);
if (!rpc->auth)
return -1;
auth_status rc = utils_authenticate_gateway(instance, GW_AUTH_RPC);
switch (rc)
{
case AUTH_SUCCESS:
case AUTH_SKIP:
break;
case AUTH_CANCELLED:
freerdp_set_last_error_log(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
return -1;
case AUTH_NO_CREDENTIALS:
WLog_INFO(TAG, "No credentials provided - using nullptr identity");
break;
case AUTH_FAILED:
default:
return -1;
}
if (!credssp_auth_init(rpc->auth, AUTH_PKG, nullptr))
return -1;
if (!identity_set_from_settings(&identity, settings, FreeRDP_GatewayUsername,
FreeRDP_GatewayDomain, FreeRDP_GatewayPassword))
return -1;
SEC_WINNT_AUTH_IDENTITY* identityArg = (settings->GatewayUsername ? &identity : nullptr);
if (!credssp_auth_setup_client(rpc->auth, nullptr, settings->GatewayHostname, identityArg,
nullptr))
{
sspi_FreeAuthIdentity(&identity);
return -1;
}
sspi_FreeAuthIdentity(&identity);
credssp_auth_set_flags(rpc->auth, ISC_REQ_USE_DCE_STYLE | ISC_REQ_DELEGATE |
ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT);
if (credssp_auth_authenticate(rpc->auth) < 0)
return -1;
return 1;
}
int rpc_send_bind_pdu(rdpRpc* rpc, BOOL initial)
{
int status = -1;
wStream* buffer = nullptr;
UINT32 offset = 0;
RpcClientCall* clientCall = nullptr;
p_cont_elem_t* p_cont_elem = nullptr;
rpcconn_bind_hdr_t bind_pdu = WINPR_C_ARRAY_INIT;
RpcVirtualConnection* connection = nullptr;
RpcInChannel* inChannel = nullptr;
const SecBuffer* sbuffer = nullptr;
WINPR_ASSERT(rpc);
connection = rpc->VirtualConnection;
WINPR_ASSERT(connection);
inChannel = connection->DefaultInChannel;
if (initial && rpc_bind_setup(rpc) < 0)
return -1;
WLog_DBG(TAG, initial ? "Sending Bind PDU" : "Sending Alter Context PDU");
sbuffer = credssp_auth_get_output_buffer(rpc->auth);
if (!sbuffer)
goto fail;
bind_pdu.header = rpc_pdu_header_init(rpc);
bind_pdu.header.auth_length = (UINT16)sbuffer->cbBuffer;
bind_pdu.auth_verifier.auth_value = sbuffer->pvBuffer;
bind_pdu.header.ptype = initial ? PTYPE_BIND : PTYPE_ALTER_CONTEXT;
bind_pdu.header.pfc_flags =
PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_SUPPORT_HEADER_SIGN | PFC_CONC_MPX;
bind_pdu.header.call_id = 2;
bind_pdu.max_xmit_frag = rpc->max_xmit_frag;
bind_pdu.max_recv_frag = rpc->max_recv_frag;
bind_pdu.assoc_group_id = 0;
bind_pdu.p_context_elem.n_context_elem = 2;
bind_pdu.p_context_elem.reserved = 0;
bind_pdu.p_context_elem.reserved2 = 0;
bind_pdu.p_context_elem.p_cont_elem =
calloc(bind_pdu.p_context_elem.n_context_elem, sizeof(p_cont_elem_t));
if (!bind_pdu.p_context_elem.p_cont_elem)
goto fail;
p_cont_elem = &bind_pdu.p_context_elem.p_cont_elem[0];
p_cont_elem->p_cont_id = 0;
p_cont_elem->n_transfer_syn = 1;
p_cont_elem->reserved = 0;
CopyMemory(&(p_cont_elem->abstract_syntax.if_uuid), &TSGU_UUID, sizeof(p_uuid_t));
p_cont_elem->abstract_syntax.if_version = TSGU_SYNTAX_IF_VERSION;
p_cont_elem->transfer_syntaxes = malloc(sizeof(p_syntax_id_t));
if (!p_cont_elem->transfer_syntaxes)
goto fail;
CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &NDR_UUID, sizeof(p_uuid_t));
p_cont_elem->transfer_syntaxes[0].if_version = NDR_SYNTAX_IF_VERSION;
p_cont_elem = &bind_pdu.p_context_elem.p_cont_elem[1];
p_cont_elem->p_cont_id = 1;
p_cont_elem->n_transfer_syn = 1;
p_cont_elem->reserved = 0;
CopyMemory(&(p_cont_elem->abstract_syntax.if_uuid), &TSGU_UUID, sizeof(p_uuid_t));
p_cont_elem->abstract_syntax.if_version = TSGU_SYNTAX_IF_VERSION;
p_cont_elem->transfer_syntaxes = malloc(sizeof(p_syntax_id_t));
if (!p_cont_elem->transfer_syntaxes)
goto fail;
CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &BTFN_UUID, sizeof(p_uuid_t));
p_cont_elem->transfer_syntaxes[0].if_version = BTFN_SYNTAX_IF_VERSION;
offset = 116;
bind_pdu.auth_verifier.auth_type =
rpc_auth_pkg_to_security_provider(credssp_auth_pkg_name(rpc->auth));
bind_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
bind_pdu.auth_verifier.auth_reserved = 0x00;
bind_pdu.auth_verifier.auth_context_id = 0x00000000;
offset += (8 + bind_pdu.header.auth_length);
WINPR_ASSERT(offset <= UINT16_MAX);
bind_pdu.header.frag_length = (UINT16)offset;
buffer = Stream_New(nullptr, bind_pdu.header.frag_length);
if (!buffer)
goto fail;
if (!rts_write_pdu_bind(buffer, &bind_pdu))
goto fail;
clientCall = rpc_client_call_new(bind_pdu.header.call_id, 0);
if (!clientCall)
goto fail;
if (!ArrayList_Append(rpc->client->ClientCallList, clientCall))
{
rpc_client_call_free(clientCall);
goto fail;
}
Stream_SealLength(buffer);
status = rpc_in_channel_send_pdu(inChannel, Stream_Buffer(buffer), Stream_Length(buffer));
fail:
if (bind_pdu.p_context_elem.p_cont_elem)
{
free(bind_pdu.p_context_elem.p_cont_elem[0].transfer_syntaxes);
free(bind_pdu.p_context_elem.p_cont_elem[1].transfer_syntaxes);
}
free(bind_pdu.p_context_elem.p_cont_elem);
bind_pdu.p_context_elem.p_cont_elem = nullptr;
Stream_Free(buffer, TRUE);
return (status > 0) ? 1 : -1;
}
/**
* Maximum Transmit/Receive Fragment Size Negotiation
*
* The client determines, and then sends in the bind PDU, its desired maximum size for transmitting
* fragments, and its desired maximum receive fragment size. Similarly, the server determines its
* desired maximum sizes for transmitting and receiving fragments. Transmit and receive sizes may be
* different to help preserve buffering. When the server receives the clients values, it sets its
* operational transmit size to the minimum of the clients receive size (from the bind PDU) and its
* own desired transmit size. Then it sets its actual receive size to the minimum of the clients
* transmit size (from the bind) and its own desired receive size. The server then returns its
* operational values in the bind_ack PDU. The client then sets its operational values from the
* received bind_ack PDU. The received transmit size becomes the clients receive size, and the
* received receive size becomes the clients transmit size. Either party may use receive buffers
* larger than negotiated — although this will not provide any advantage — but may not transmit
* larger fragments than negotiated.
*/
/**
*
* SECURE_BIND_ACK: RPC bind_ack PDU with sec_trailer and auth_token. The PFC_SUPPORT_HEADER_SIGN
* flag in the PDU header is also set in this example. Auth_token is generated by the server in the
* previous step. Upon receiving that PDU, the client calls the implementation equivalent of the
* abstract GSS_Init_sec_context call, which returns an auth_token and continue status in this
* example.
*/
BOOL rpc_recv_bind_ack_pdu(rdpRpc* rpc, wStream* s)
{
BOOL rc = FALSE;
const BYTE* auth_data = nullptr;
size_t pos = 0;
size_t end = 0;
rpcconn_hdr_t header = WINPR_C_ARRAY_INIT;
SecBuffer buffer = WINPR_C_ARRAY_INIT;
WINPR_ASSERT(rpc);
WINPR_ASSERT(rpc->auth);
WINPR_ASSERT(s);
pos = Stream_GetPosition(s);
if (!rts_read_pdu_header(s, &header))
goto fail;
WLog_DBG(TAG, header.common.ptype == PTYPE_BIND_ACK ? "Receiving BindAck PDU"
: "Receiving AlterContextResp PDU");
rpc->max_recv_frag = header.bind_ack.max_xmit_frag;
rpc->max_xmit_frag = header.bind_ack.max_recv_frag;
/* Get the correct offset in the input data and pass that on as input buffer.
* rts_read_pdu_header did already do consistency checks */
end = Stream_GetPosition(s);
Stream_SetPosition(s, pos + header.common.frag_length - header.common.auth_length);
auth_data = Stream_ConstPointer(s);
Stream_SetPosition(s, end);
buffer.cbBuffer = header.common.auth_length;
buffer.pvBuffer = malloc(buffer.cbBuffer);
if (!buffer.pvBuffer)
goto fail;
memcpy(buffer.pvBuffer, auth_data, buffer.cbBuffer);
credssp_auth_take_input_buffer(rpc->auth, &buffer);
if (credssp_auth_authenticate(rpc->auth) < 0)
goto fail;
rc = TRUE;
fail:
rts_free_pdu_header(&header, FALSE);
return rc;
}
/**
* RPC_AUTH_3: The client knows that this is an NTLM that uses three legs. It sends an rpc_auth_3
* PDU with the auth_token obtained in the previous step. Upon receiving this PDU, the server calls
* the implementation equivalent of the abstract GSS_Accept_sec_context call, which returns success
* status in this example.
*/
int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
{
int status = -1;
wStream* buffer = nullptr;
size_t offset = 0;
const SecBuffer* sbuffer = nullptr;
RpcClientCall* clientCall = nullptr;
rpcconn_rpc_auth_3_hdr_t auth_3_pdu = WINPR_C_ARRAY_INIT;
RpcVirtualConnection* connection = nullptr;
RpcInChannel* inChannel = nullptr;
WINPR_ASSERT(rpc);
connection = rpc->VirtualConnection;
WINPR_ASSERT(connection);
inChannel = connection->DefaultInChannel;
WINPR_ASSERT(inChannel);
WLog_DBG(TAG, "Sending RpcAuth3 PDU");
sbuffer = credssp_auth_get_output_buffer(rpc->auth);
if (!sbuffer)
return -1;
auth_3_pdu.header = rpc_pdu_header_init(rpc);
auth_3_pdu.header.auth_length = (UINT16)sbuffer->cbBuffer;
auth_3_pdu.auth_verifier.auth_value = sbuffer->pvBuffer;
auth_3_pdu.header.ptype = PTYPE_RPC_AUTH_3;
auth_3_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
auth_3_pdu.header.call_id = 2;
auth_3_pdu.max_xmit_frag = rpc->max_xmit_frag;
auth_3_pdu.max_recv_frag = rpc->max_recv_frag;
offset = 20;
const size_t align = rpc_offset_align(&offset, 4);
WINPR_ASSERT(align <= UINT8_MAX);
auth_3_pdu.auth_verifier.auth_pad_length = (BYTE)align;
auth_3_pdu.auth_verifier.auth_type =
rpc_auth_pkg_to_security_provider(credssp_auth_pkg_name(rpc->auth));
auth_3_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
auth_3_pdu.auth_verifier.auth_reserved = 0x00;
auth_3_pdu.auth_verifier.auth_context_id = 0x00000000;
offset += (8 + auth_3_pdu.header.auth_length);
WINPR_ASSERT(offset <= UINT16_MAX);
auth_3_pdu.header.frag_length = (UINT16)offset;
buffer = Stream_New(nullptr, auth_3_pdu.header.frag_length);
if (!buffer)
return -1;
if (!rts_write_pdu_auth3(buffer, &auth_3_pdu))
goto fail;
clientCall = rpc_client_call_new(auth_3_pdu.header.call_id, 0);
if (ArrayList_Append(rpc->client->ClientCallList, clientCall))
{
Stream_SealLength(buffer);
status = rpc_in_channel_send_pdu(inChannel, Stream_Buffer(buffer), Stream_Length(buffer));
}
fail:
Stream_Free(buffer, TRUE);
return (status > 0) ? 1 : -1;
}
enum RPC_BIND_STATE rpc_bind_state(rdpRpc* rpc)
{
BOOL complete = 0;
BOOL have_token = 0;
WINPR_ASSERT(rpc);
complete = credssp_auth_is_complete(rpc->auth);
have_token = credssp_auth_have_output_token(rpc->auth);
return complete ? (have_token ? RPC_BIND_STATE_LAST_LEG : RPC_BIND_STATE_COMPLETE)
: RPC_BIND_STATE_INCOMPLETE;
}
BYTE rpc_auth_pkg_to_security_provider(const char* name)
{
if (strcmp(name, CREDSSP_AUTH_PKG_SPNEGO) == 0)
return RPC_C_AUTHN_GSS_NEGOTIATE;
else if (strcmp(name, CREDSSP_AUTH_PKG_NTLM) == 0)
return RPC_C_AUTHN_WINNT;
else if (strcmp(name, CREDSSP_AUTH_PKG_KERBEROS) == 0)
return RPC_C_AUTHN_GSS_KERBEROS;
else if (strcmp(name, CREDSSP_AUTH_PKG_SCHANNEL) == 0)
return RPC_C_AUTHN_GSS_SCHANNEL;
else
return RPC_C_AUTHN_NONE;
}

View File

@@ -0,0 +1,59 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC Secure Context Binding
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_RPC_BIND_H
#define FREERDP_LIB_CORE_GATEWAY_RPC_BIND_H
#include "rpc.h"
#include <winpr/wtypes.h>
#include <freerdp/api.h>
FREERDP_LOCAL extern const p_uuid_t TSGU_UUID;
#define TSGU_SYNTAX_IF_VERSION 0x00030001
FREERDP_LOCAL extern const p_uuid_t NDR_UUID;
#define NDR_SYNTAX_IF_VERSION 0x00000002
FREERDP_LOCAL extern const p_uuid_t BTFN_UUID;
#define BTFN_SYNTAX_IF_VERSION 0x00000001
enum RPC_BIND_STATE
{
RPC_BIND_STATE_INCOMPLETE,
RPC_BIND_STATE_LAST_LEG,
RPC_BIND_STATE_COMPLETE
};
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rpc_send_bind_pdu(rdpRpc* rpc, BOOL initial);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_recv_bind_ack_pdu(rdpRpc* rpc, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL enum RPC_BIND_STATE rpc_bind_state(rdpRpc* rpc);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BYTE rpc_auth_pkg_to_security_provider(const char* name);
#endif /* FREERDP_LIB_CORE_GATEWAY_RPC_BIND_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC Client
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_RPC_CLIENT_H
#define FREERDP_LIB_CORE_GATEWAY_RPC_CLIENT_H
#include <winpr/wtypes.h>
#include <winpr/stream.h>
#include <freerdp/api.h>
#include "rpc.h"
WINPR_ATTR_NODISCARD
FREERDP_LOCAL RpcClientCall* rpc_client_call_find_by_id(RpcClient* client, UINT32 CallId);
FREERDP_LOCAL void rpc_client_call_free(RpcClientCall* clientCall);
WINPR_ATTR_MALLOC(rpc_client_call_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rpc_in_channel_send_pdu(RpcInChannel* inChannel, const BYTE* buffer,
size_t length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rpc_client_in_channel_recv(rdpRpc* rpc);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rpc_client_out_channel_recv(rdpRpc* rpc);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rpc_client_receive_pipe_read(RpcClient* client, BYTE* buffer, size_t length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum);
FREERDP_LOCAL void rpc_client_free(RpcClient* client);
WINPR_ATTR_MALLOC(rpc_client_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL RpcClient* rpc_client_new(rdpContext* context, UINT32 max_recv_frag);
#endif /* FREERDP_LIB_CORE_GATEWAY_RPC_CLIENT_H */

View File

@@ -0,0 +1,428 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC Fault Handling
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <freerdp/log.h>
#include "rpc_fault.h"
#include "rpc.h"
#define TAG FREERDP_TAG("core.gateway.rpc")
ALIGN64
static const RPC_FAULT_CODE RPC_FAULT_CODES[] = {
DEFINE_RPC_FAULT_CODE(nca_s_fault_object_not_found, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_cancel, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_addr_error, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_context_mismatch, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_fp_div_zero, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_fp_error, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_fp_overflow, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_fp_underflow, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_ill_inst, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_int_div_by_zero, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_int_overflow, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_invalid_bound, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_invalid_tag, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_pipe_closed, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_pipe_comm_error, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_pipe_discipline, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_pipe_empty, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_pipe_memory, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_pipe_order, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_remote_no_memory, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_user_defined, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_tx_open_failed, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_codeset_conv_error, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(nca_s_fault_no_client_stub, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_STRING_BINDING, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_WRONG_KIND_OF_BINDING, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_BINDING, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_PROTSEQ_NOT_SUPPORTED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_RPC_PROTSEQ, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_STRING_UUID, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_ENDPOINT_FORMAT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_NET_ADDR, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_ENDPOINT_FOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_TIMEOUT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_OBJECT_NOT_FOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_ALREADY_REGISTERED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_TYPE_ALREADY_REGISTERED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_ALREADY_LISTENING, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_PROTSEQS_REGISTERED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NOT_LISTENING, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNKNOWN_MGR_TYPE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNKNOWN_IF, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_BINDINGS, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_PROTSEQS, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_CANT_CREATE_ENDPOINT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_OUT_OF_RESOURCES, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_SERVER_UNAVAILABLE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_SERVER_TOO_BUSY, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_NETWORK_OPTIONS, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_CALL_ACTIVE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_CALL_FAILED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_CALL_FAILED_DNE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_PROTOCOL_ERROR, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_PROXY_ACCESS_DENIED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNSUPPORTED_TRANS_SYN, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNSUPPORTED_TYPE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_TAG, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_BOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_ENTRY_NAME, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_NAME_SYNTAX, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNSUPPORTED_NAME_SYNTAX, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UUID_NO_ADDRESS, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_DUPLICATE_ENDPOINT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNKNOWN_AUTHN_TYPE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_MAX_CALLS_TOO_SMALL, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_STRING_TOO_LONG, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_PROTSEQ_NOT_FOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_PROCNUM_OUT_OF_RANGE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_BINDING_HAS_NO_AUTH, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNKNOWN_AUTHN_SERVICE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNKNOWN_AUTHN_LEVEL, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_AUTH_IDENTITY, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNKNOWN_AUTHZ_SERVICE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(EPT_S_INVALID_ENTRY, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(EPT_S_CANT_PERFORM_OP, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(EPT_S_NOT_REGISTERED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NOTHING_TO_EXPORT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INCOMPLETE_NAME, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_VERS_OPTION, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_MORE_MEMBERS, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NOT_ALL_OBJS_UNEXPORTED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INTERFACE_NOT_FOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_ENTRY_ALREADY_EXISTS, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_ENTRY_NOT_FOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NAME_SERVICE_UNAVAILABLE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_NAF_ID, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_CANNOT_SUPPORT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_CONTEXT_AVAILABLE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INTERNAL_ERROR, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_ZERO_DIVIDE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_ADDRESS_ERROR, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_FP_DIV_ZERO, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_FP_UNDERFLOW, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_FP_OVERFLOW, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_NO_MORE_ENTRIES, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_SS_CHAR_TRANS_OPEN_FAIL, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_SS_CHAR_TRANS_SHORT_FILE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_SS_IN_NULL_CONTEXT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_SS_CONTEXT_DAMAGED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_SS_HANDLES_MISMATCH, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_SS_CANNOT_GET_CALL_HANDLE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_NULL_REF_POINTER, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_ENUM_VALUE_OUT_OF_RANGE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_BYTE_COUNT_TOO_SMALL, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_BAD_STUB_DATA, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_INTERFACES, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_CALL_CANCELLED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_BINDING_INCOMPLETE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_COMM_FAILURE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNSUPPORTED_AUTHN_LEVEL, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NO_PRINC_NAME, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NOT_RPC_ERROR, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UUID_LOCAL_ONLY, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_SEC_PKG_ERROR, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_NOT_CANCELLED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_INVALID_ES_ACTION, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_WRONG_ES_VERSION, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_WRONG_STUB_VERSION, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_INVALID_PIPE_OBJECT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_WRONG_PIPE_ORDER, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_WRONG_PIPE_VERSION, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_COOKIE_AUTH_FAILED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_GROUP_MEMBER_NOT_FOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(EPT_S_CANT_CREATE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_OBJECT, CAT_GATEWAY)
};
static const RPC_FAULT_CODE RPC_TSG_FAULT_CODES[] = {
DEFINE_RPC_FAULT_CODE(RPC_S_OK, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_ARG, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_OUT_OF_MEMORY, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_OUT_OF_THREADS, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_LEVEL, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_BUFFER_TOO_SMALL, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_SECURITY_DESC, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_ACCESS_DENIED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_SERVER_OUT_OF_MEMORY, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_ASYNC_CALL_PENDING, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_UNKNOWN_PRINCIPAL, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_S_TIMEOUT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_NO_MEMORY, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_INVALID_BOUND, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_INVALID_TAG, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_ENUM_VALUE_TOO_LARGE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_SS_CONTEXT_MISMATCH, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_INVALID_BUFFER, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_PIPE_APP_MEMORY, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(RPC_X_INVALID_PIPE_OPERATION, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(ERROR_ONLY_IF_CONNECTED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(ERROR_GRACEFUL_DISCONNECT, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(ERROR_OPERATION_ABORTED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(ERROR_BAD_ARGUMENTS, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_INTERNALERROR, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_RAP_ACCESSDENIED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_NAP_ACCESSDENIED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_TS_CONNECTFAILED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_ALREADYDISCONNECTED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_QUARANTINE_ACCESSDENIED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_NOCERTAVAILABLE, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_COOKIE_BADPACKET, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_COOKIE_AUTHENTICATION_ACCESS_DENIED, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_UNSUPPORTED_AUTHENTICATION_METHOD, CAT_GATEWAY),
DEFINE_RPC_FAULT_CODE(E_PROXY_CAPABILITYMISMATCH, CAT_GATEWAY),
{ HRESULT_CODE(E_PROXY_NOTSUPPORTED), "E_PROXY_NOTSUPPORTED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_TS_CONNECTFAILED), "E_PROXY_TS_CONNECTFAILED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_MAXCONNECTIONSREACHED), "E_PROXY_MAXCONNECTIONSREACHED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_INTERNALERROR), "E_PROXY_INTERNALERROR", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_SESSIONTIMEOUT), "E_PROXY_SESSIONTIMEOUT", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_REAUTH_AUTHN_FAILED), "E_PROXY_REAUTH_AUTHN_FAILED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_REAUTH_CAP_FAILED), "E_PROXY_REAUTH_CAP_FAILED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_REAUTH_RAP_FAILED), "E_PROXY_REAUTH_RAP_FAILED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_SDR_NOT_SUPPORTED_BY_TS), "E_PROXY_SDR_NOT_SUPPORTED_BY_TS",
CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_REAUTH_NAP_FAILED), "E_PROXY_REAUTH_NAP_FAILED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_CONNECTIONABORTED), "E_PROXY_CONNECTIONABORTED", CAT_GATEWAY },
{ HRESULT_CODE(E_PROXY_NOCERTAVAILABLE), "E_PROXY_NOCERTAVAILABLE", CAT_GATEWAY },
{ HRESULT_CODE(RPC_S_CALL_CANCELLED), "RPC_S_CALL_CANCELLED", CAT_GATEWAY }
};
/**
* [MS-RPCE] 3.1.1.5.5 Returning Win32 Error Values:
* http://msdn.microsoft.com/en-us/library/ee442005/
*/
static UINT32 rpc_map_status_code_to_win32_error_code(UINT32 code)
{
switch (code)
{
case nca_s_comm_failure:
return RPC_S_COMM_FAILURE;
case nca_s_op_rng_error:
return RPC_S_PROCNUM_OUT_OF_RANGE;
case nca_s_unk_if:
return RPC_S_UNKNOWN_IF;
case nca_s_wrong_boot_time:
return nca_s_wrong_boot_time;
case nca_s_you_crashed:
return RPC_S_CALL_FAILED;
case nca_s_proto_error:
return RPC_S_PROTOCOL_ERROR;
case nca_s_out_args_too_big:
return RPC_S_SERVER_OUT_OF_MEMORY;
case nca_s_server_too_busy:
return RPC_S_SERVER_TOO_BUSY;
case nca_s_unsupported_type:
return RPC_S_UNSUPPORTED_TYPE;
case nca_s_fault_int_div_by_zero:
return RPC_S_ZERO_DIVIDE;
case nca_s_fault_addr_error:
return RPC_S_ADDRESS_ERROR;
case nca_s_fault_fp_div_zero:
return RPC_S_FP_DIV_ZERO;
case nca_s_fault_fp_underflow:
return RPC_S_FP_UNDERFLOW;
case nca_s_fault_fp_overflow:
return RPC_S_FP_OVERFLOW;
case nca_s_fault_invalid_tag:
return RPC_S_INVALID_TAG;
case nca_s_fault_invalid_bound:
return RPC_S_INVALID_BOUND;
case nca_s_rpc_version_mismatch:
return RPC_S_PROTOCOL_ERROR;
case nca_s_unspec_reject:
return RPC_S_CALL_FAILED;
case nca_s_bad_actid:
return RPC_S_CALL_FAILED_DNE;
case nca_s_who_are_you_failed:
return RPC_S_CALL_FAILED;
case nca_s_manager_not_entered:
return RPC_S_CALL_FAILED_DNE;
case nca_s_fault_cancel:
return RPC_S_CALL_CANCELLED;
case nca_s_fault_ill_inst:
return RPC_S_ADDRESS_ERROR;
case nca_s_fault_fp_error:
return RPC_S_FP_OVERFLOW;
case nca_s_fault_int_overflow:
return RPC_S_ADDRESS_ERROR;
case nca_s_fault_unspec:
return RPC_S_CALL_FAILED;
case nca_s_fault_remote_comm_failure:
return nca_s_fault_remote_comm_failure;
case nca_s_fault_pipe_empty:
return RPC_X_PIPE_EMPTY;
case nca_s_fault_pipe_closed:
return RPC_X_PIPE_CLOSED;
case nca_s_fault_pipe_order:
return RPC_X_WRONG_PIPE_ORDER;
case nca_s_fault_pipe_discipline:
return RPC_X_PIPE_DISCIPLINE_ERROR;
case nca_s_fault_pipe_comm_error:
return RPC_S_COMM_FAILURE;
case nca_s_fault_pipe_memory:
return RPC_S_OUT_OF_MEMORY;
case nca_s_fault_context_mismatch:
return RPC_X_SS_CONTEXT_MISMATCH;
case nca_s_fault_remote_no_memory:
return RPC_S_SERVER_OUT_OF_MEMORY;
case nca_s_invalid_pres_context_id:
return RPC_S_PROTOCOL_ERROR;
case nca_s_unsupported_authn_level:
return RPC_S_UNSUPPORTED_AUTHN_LEVEL;
case nca_s_invalid_checksum:
return RPC_S_CALL_FAILED_DNE;
case nca_s_invalid_crc:
return RPC_S_CALL_FAILED_DNE;
case nca_s_fault_user_defined:
return nca_s_fault_user_defined;
case nca_s_fault_tx_open_failed:
return nca_s_fault_tx_open_failed;
case nca_s_fault_codeset_conv_error:
return nca_s_fault_codeset_conv_error;
case nca_s_fault_object_not_found:
return nca_s_fault_object_not_found;
case nca_s_fault_no_client_stub:
return nca_s_fault_no_client_stub;
default:
break;
}
return code;
}
const char* rpc_error_to_string(UINT32 code)
{
static char buffer[1024];
for (size_t index = 0; index < ARRAYSIZE(RPC_FAULT_CODES); index++)
{
const RPC_FAULT_CODE* current = &RPC_FAULT_CODES[index];
if (current->code == code)
{
(void)sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name);
goto out;
}
}
for (size_t index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++)
{
const RPC_FAULT_CODE* current = &RPC_TSG_FAULT_CODES[index];
if (current->code == code)
{
(void)sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name);
goto out;
}
}
for (size_t index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++)
{
const RPC_FAULT_CODE* current = &RPC_TSG_FAULT_CODES[index];
if (current->code == HRESULT_CODE(code))
{
(void)sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name);
goto out;
}
}
(void)sprintf_s(buffer, ARRAYSIZE(buffer), "%s [0x%08" PRIX32 "]", "UNKNOWN", code);
out:
return buffer;
}
const char* rpc_error_to_category(UINT32 code)
{
for (size_t index = 0; index < ARRAYSIZE(RPC_FAULT_CODES); index++)
{
const RPC_FAULT_CODE* current = &RPC_FAULT_CODES[index];
if (current->code == code)
return current->category;
}
for (size_t index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++)
{
const RPC_FAULT_CODE* current = &RPC_TSG_FAULT_CODES[index];
if (current->code == code)
return current->category;
}
for (size_t index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++)
{
const RPC_FAULT_CODE* current = &RPC_TSG_FAULT_CODES[index];
if (current->code == HRESULT_CODE(code))
return current->category;
}
return "UNKNOWN";
}
int rpc_recv_fault_pdu(UINT32 status)
{
UINT32 code = rpc_map_status_code_to_win32_error_code(status);
WLog_ERR(TAG, "RPC Fault PDU: status=%s", rpc_error_to_string(code));
return 0;
}

View File

@@ -0,0 +1,34 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RPC Fault Handling
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_RPC_FAULT_H
#define FREERDP_LIB_CORE_GATEWAY_RPC_FAULT_H
#include <winpr/wtypes.h>
#include <freerdp/api.h>
FREERDP_LOCAL int rpc_recv_fault_pdu(UINT32 status);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rpc_error_to_string(UINT32 code);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rpc_error_to_category(UINT32 code);
#endif /* FREERDP_LIB_CORE_GATEWAY_RPC_FAULT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,150 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Request To Send (RTS) PDUs
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_RTS_H
#define FREERDP_LIB_CORE_GATEWAY_RTS_H
#include <freerdp/config.h>
#include <winpr/stream.h>
#include <freerdp/api.h>
#include <freerdp/types.h>
#include <freerdp/log.h>
#include "rpc.h"
#define RTS_FLAG_NONE 0x0000
#define RTS_FLAG_PING 0x0001
#define RTS_FLAG_OTHER_CMD 0x0002
#define RTS_FLAG_RECYCLE_CHANNEL 0x0004
#define RTS_FLAG_IN_CHANNEL 0x0008
#define RTS_FLAG_OUT_CHANNEL 0x0010
#define RTS_FLAG_EOF 0x0020
#define RTS_FLAG_ECHO 0x0040
#define RTS_CMD_RECEIVE_WINDOW_SIZE 0x00000000
#define RTS_CMD_FLOW_CONTROL_ACK 0x00000001
#define RTS_CMD_CONNECTION_TIMEOUT 0x00000002
#define RTS_CMD_COOKIE 0x00000003
#define RTS_CMD_CHANNEL_LIFETIME 0x00000004
#define RTS_CMD_CLIENT_KEEPALIVE 0x00000005
#define RTS_CMD_VERSION 0x00000006
#define RTS_CMD_EMPTY 0x00000007
#define RTS_CMD_PADDING 0x00000008
#define RTS_CMD_NEGATIVE_ANCE 0x00000009
#define RTS_CMD_ANCE 0x0000000A
#define RTS_CMD_CLIENT_ADDRESS 0x0000000B
#define RTS_CMD_ASSOCIATION_GROUP_ID 0x0000000C
#define RTS_CMD_DESTINATION 0x0000000D
#define RTS_CMD_PING_TRAFFIC_SENT_NOTIFY 0x0000000E
#define RTS_CMD_LAST_ID 0x0000000F
#define RTS_CMD_RECEIVE_WINDOW_SIZE_LENGTH 0x00000004
#define RTS_CMD_FLOW_CONTROL_ACK_LENGTH 0x00000018
#define RTS_CMD_CONNECTION_TIMEOUT_LENGTH 0x00000004
#define RTS_CMD_COOKIE_LENGTH 0x00000010
#define RTS_CMD_CHANNEL_LIFETIME_LENGTH 0x00000004
#define RTS_CMD_CLIENT_KEEPALIVE_LENGTH 0x00000004
#define RTS_CMD_VERSION_LENGTH 0x00000004
#define RTS_CMD_EMPTY_LENGTH 0x00000000
#define RTS_CMD_PADDING_LENGTH 0x00000000 /* variable-size */
#define RTS_CMD_NEGATIVE_ANCE_LENGTH 0x00000000
#define RTS_CMD_ANCE_LENGTH 0x00000000
#define RTS_CMD_CLIENT_ADDRESS_LENGTH 0x00000000 /* variable-size */
#define RTS_CMD_ASSOCIATION_GROUP_ID_LENGTH 0x00000010
#define RTS_CMD_DESTINATION_LENGTH 0x00000004
#define RTS_CMD_PING_TRAFFIC_SENT_NOTIFY_LENGTH 0x00000004
#define FDClient 0x00000000
#define FDInProxy 0x00000001
#define FDServer 0x00000002
#define FDOutProxy 0x00000003
FREERDP_LOCAL BOOL rts_generate_cookie(BYTE* cookie);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_write_pdu_auth3(wStream* s, const rpcconn_rpc_auth_3_hdr_t* auth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_write_pdu_bind(wStream* s, const rpcconn_bind_hdr_t* bind);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_read_pdu_header(wStream* s, rpcconn_hdr_t* header);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_read_pdu_header_ex(wStream* s, rpcconn_hdr_t* header, BOOL silent);
FREERDP_LOCAL void rts_free_pdu_header(rpcconn_hdr_t* header, BOOL allocated);
typedef enum
{
RTS_PDU_FAIL = -1,
RTS_PDU_INCOMPLETE = 0,
RTS_PDU_VALID = 1
} rts_pdu_status_t;
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rts_pdu_status_t rts_read_common_pdu_header(wStream* s, rpcconn_common_hdr_t* header,
BOOL ignoreErrors);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_command_length(UINT32 CommandType, wStream* s, size_t* length, BOOL silent);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_send_CONN_A1_pdu(rdpRpc* rpc);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_recv_CONN_A3_pdu(rdpRpc* rpc, wStream* buffer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_send_CONN_B1_pdu(rdpRpc* rpc);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_recv_CONN_C2_pdu(rdpRpc* rpc, wStream* buffer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_send_OUT_R1_A3_pdu(rdpRpc* rpc);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_send_flow_control_ack_pdu(rdpRpc* rpc);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_recv_out_of_sequence_pdu(rdpRpc* rpc, wStream* buffer,
const rpcconn_hdr_t* header);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_recv_ping_pdu(rdpRpc* rpc, wStream* s);
#define Stream_ConditionalCheckAndLogRequiredLength(tag, s, size, silent) \
rts_conditional_check_and_log(tag, s, size, silent, __func__, __FILE__, __LINE__)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_conditional_check_and_log(const char* tag, wStream* s, size_t size,
BOOL silent, const char* fkt, const char* file,
size_t line);
#define Stream_ConditionalSafeSeek(s, size, silent) \
rts_conditional_safe_seek(s, size, silent, __func__, __FILE__, __LINE__)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_conditional_safe_seek(wStream* s, size_t size, BOOL silent, const char* fkt,
const char* file, size_t line);
#endif /* FREERDP_LIB_CORE_GATEWAY_RTS_H */

View File

@@ -0,0 +1,416 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Request To Send (RTS) PDU Signatures
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/assert.h>
#include <winpr/stream.h>
#include <freerdp/log.h>
#include "rts_signature.h"
#define TAG FREERDP_TAG("core.gateway.rts")
const RtsPduSignature RTS_PDU_CONN_A1_SIGNATURE = {
RTS_FLAG_NONE,
4,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_RECEIVE_WINDOW_SIZE, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_CONN_A2_SIGNATURE = { RTS_FLAG_OUT_CHANNEL,
5,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE,
RTS_CMD_COOKIE, RTS_CMD_CHANNEL_LIFETIME,
RTS_CMD_RECEIVE_WINDOW_SIZE, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_CONN_A3_SIGNATURE = {
RTS_FLAG_NONE, 1, { RTS_CMD_CONNECTION_TIMEOUT, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_CONN_B1_SIGNATURE = {
RTS_FLAG_NONE,
6,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_CHANNEL_LIFETIME,
RTS_CMD_CLIENT_KEEPALIVE, RTS_CMD_ASSOCIATION_GROUP_ID, 0, 0 }
};
const RtsPduSignature RTS_PDU_CONN_B2_SIGNATURE = {
RTS_FLAG_IN_CHANNEL,
7,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_RECEIVE_WINDOW_SIZE,
RTS_CMD_CONNECTION_TIMEOUT, RTS_CMD_ASSOCIATION_GROUP_ID, RTS_CMD_CLIENT_ADDRESS, 0 }
};
const RtsPduSignature RTS_PDU_CONN_B3_SIGNATURE = {
RTS_FLAG_NONE, 2, { RTS_CMD_RECEIVE_WINDOW_SIZE, RTS_CMD_VERSION, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_CONN_C1_SIGNATURE = { RTS_FLAG_NONE,
3,
{ RTS_CMD_VERSION, RTS_CMD_RECEIVE_WINDOW_SIZE,
RTS_CMD_CONNECTION_TIMEOUT, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_CONN_C2_SIGNATURE = { RTS_FLAG_NONE,
3,
{ RTS_CMD_VERSION, RTS_CMD_RECEIVE_WINDOW_SIZE,
RTS_CMD_CONNECTION_TIMEOUT, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R1_A1_SIGNATURE = {
RTS_FLAG_RECYCLE_CHANNEL,
4,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_COOKIE, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_IN_R1_A2_SIGNATURE = {
RTS_FLAG_NONE,
4,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_RECEIVE_WINDOW_SIZE,
RTS_CMD_CONNECTION_TIMEOUT, 0, 0 }
};
const RtsPduSignature RTS_PDU_IN_R1_A3_SIGNATURE = { RTS_FLAG_NONE,
4,
{ RTS_CMD_DESTINATION, RTS_CMD_VERSION,
RTS_CMD_RECEIVE_WINDOW_SIZE,
RTS_CMD_CONNECTION_TIMEOUT, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R1_A4_SIGNATURE = { RTS_FLAG_NONE,
4,
{ RTS_CMD_DESTINATION, RTS_CMD_VERSION,
RTS_CMD_RECEIVE_WINDOW_SIZE,
RTS_CMD_CONNECTION_TIMEOUT, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R1_A5_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_COOKIE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R1_A6_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_COOKIE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R1_B1_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_EMPTY, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R1_B2_SIGNATURE = {
RTS_FLAG_NONE, 1, { RTS_CMD_RECEIVE_WINDOW_SIZE, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_IN_R2_A1_SIGNATURE = {
RTS_FLAG_RECYCLE_CHANNEL,
4,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_COOKIE, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_IN_R2_A2_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_COOKIE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R2_A3_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_DESTINATION, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R2_A4_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_DESTINATION, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_IN_R2_A5_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_COOKIE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R1_A1_SIGNATURE = {
RTS_FLAG_RECYCLE_CHANNEL, 1, { RTS_CMD_DESTINATION, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R1_A2_SIGNATURE = {
RTS_FLAG_RECYCLE_CHANNEL, 1, { RTS_CMD_DESTINATION, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R1_A3_SIGNATURE = { RTS_FLAG_RECYCLE_CHANNEL,
5,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE,
RTS_CMD_COOKIE, RTS_CMD_COOKIE,
RTS_CMD_RECEIVE_WINDOW_SIZE, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R1_A4_SIGNATURE = {
RTS_FLAG_RECYCLE_CHANNEL | RTS_FLAG_OUT_CHANNEL,
7,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_COOKIE, RTS_CMD_CHANNEL_LIFETIME,
RTS_CMD_RECEIVE_WINDOW_SIZE, RTS_CMD_CONNECTION_TIMEOUT, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R1_A5_SIGNATURE = {
RTS_FLAG_OUT_CHANNEL,
3,
{ RTS_CMD_DESTINATION, RTS_CMD_VERSION, RTS_CMD_CONNECTION_TIMEOUT, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R1_A6_SIGNATURE = {
RTS_FLAG_OUT_CHANNEL,
3,
{ RTS_CMD_DESTINATION, RTS_CMD_VERSION, RTS_CMD_CONNECTION_TIMEOUT, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R1_A7_SIGNATURE = {
RTS_FLAG_OUT_CHANNEL, 2, { RTS_CMD_DESTINATION, RTS_CMD_COOKIE, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R1_A8_SIGNATURE = {
RTS_FLAG_OUT_CHANNEL, 2, { RTS_CMD_DESTINATION, RTS_CMD_COOKIE, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R1_A9_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_ANCE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R1_A10_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_ANCE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R1_A11_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_ANCE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R2_A1_SIGNATURE = {
RTS_FLAG_RECYCLE_CHANNEL, 1, { RTS_CMD_DESTINATION, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R2_A2_SIGNATURE = {
RTS_FLAG_RECYCLE_CHANNEL, 1, { RTS_CMD_DESTINATION, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R2_A3_SIGNATURE = { RTS_FLAG_RECYCLE_CHANNEL,
5,
{ RTS_CMD_VERSION, RTS_CMD_COOKIE,
RTS_CMD_COOKIE, RTS_CMD_COOKIE,
RTS_CMD_RECEIVE_WINDOW_SIZE, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R2_A4_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_COOKIE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R2_A5_SIGNATURE = {
RTS_FLAG_NONE, 2, { RTS_CMD_DESTINATION, RTS_CMD_ANCE, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R2_A6_SIGNATURE = {
RTS_FLAG_NONE, 2, { RTS_CMD_DESTINATION, RTS_CMD_ANCE, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R2_A7_SIGNATURE = {
RTS_FLAG_NONE, 3, { RTS_CMD_DESTINATION, RTS_CMD_COOKIE, RTS_CMD_VERSION, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R2_A8_SIGNATURE = {
RTS_FLAG_OUT_CHANNEL, 2, { RTS_CMD_DESTINATION, RTS_CMD_COOKIE, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R2_B1_SIGNATURE = { RTS_FLAG_NONE,
1,
{ RTS_CMD_ANCE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R2_B2_SIGNATURE = {
RTS_FLAG_NONE, 1, { RTS_CMD_NEGATIVE_ANCE, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_OUT_R2_B3_SIGNATURE = { RTS_FLAG_EOF,
1,
{ RTS_CMD_ANCE, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_OUT_R2_C1_SIGNATURE = { RTS_FLAG_PING,
1,
{ 0, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_KEEP_ALIVE_SIGNATURE = {
RTS_FLAG_OTHER_CMD, 1, { RTS_CMD_CLIENT_KEEPALIVE, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_PING_TRAFFIC_SENT_NOTIFY_SIGNATURE = {
RTS_FLAG_OTHER_CMD, 1, { RTS_CMD_PING_TRAFFIC_SENT_NOTIFY, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_ECHO_SIGNATURE = { RTS_FLAG_ECHO, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_PING_SIGNATURE = { RTS_FLAG_PING, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
const RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE = {
RTS_FLAG_OTHER_CMD, 1, { RTS_CMD_FLOW_CONTROL_ACK, 0, 0, 0, 0, 0, 0, 0 }
};
const RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE = {
RTS_FLAG_OTHER_CMD, 2, { RTS_CMD_DESTINATION, RTS_CMD_FLOW_CONTROL_ACK, 0, 0, 0, 0, 0, 0 }
};
static const RTS_PDU_SIGNATURE_ENTRY RTS_PDU_SIGNATURE_TABLE[] = {
{ RTS_PDU_CONN_A1, FALSE, &RTS_PDU_CONN_A1_SIGNATURE, "CONN/A1" },
{ RTS_PDU_CONN_A2, FALSE, &RTS_PDU_CONN_A2_SIGNATURE, "CONN/A2" },
{ RTS_PDU_CONN_A3, TRUE, &RTS_PDU_CONN_A3_SIGNATURE, "CONN/A3" },
{ RTS_PDU_CONN_B1, FALSE, &RTS_PDU_CONN_B1_SIGNATURE, "CONN/B1" },
{ RTS_PDU_CONN_B2, FALSE, &RTS_PDU_CONN_B2_SIGNATURE, "CONN/B2" },
{ RTS_PDU_CONN_B3, FALSE, &RTS_PDU_CONN_B3_SIGNATURE, "CONN/B3" },
{ RTS_PDU_CONN_C1, FALSE, &RTS_PDU_CONN_C1_SIGNATURE, "CONN/C1" },
{ RTS_PDU_CONN_C2, TRUE, &RTS_PDU_CONN_C2_SIGNATURE, "CONN/C2" },
{ RTS_PDU_IN_R1_A1, FALSE, &RTS_PDU_IN_R1_A1_SIGNATURE, "IN_R1/A1" },
{ RTS_PDU_IN_R1_A2, FALSE, &RTS_PDU_IN_R1_A2_SIGNATURE, "IN_R1/A2" },
{ RTS_PDU_IN_R1_A3, FALSE, &RTS_PDU_IN_R1_A3_SIGNATURE, "IN_R1/A3" },
{ RTS_PDU_IN_R1_A4, TRUE, &RTS_PDU_IN_R1_A4_SIGNATURE, "IN_R1/A4" },
{ RTS_PDU_IN_R1_A5, TRUE, &RTS_PDU_IN_R1_A5_SIGNATURE, "IN_R1/A5" },
{ RTS_PDU_IN_R1_A6, FALSE, &RTS_PDU_IN_R1_A6_SIGNATURE, "IN_R1/A6" },
{ RTS_PDU_IN_R1_B1, FALSE, &RTS_PDU_IN_R1_B1_SIGNATURE, "IN_R1/B1" },
{ RTS_PDU_IN_R1_B2, FALSE, &RTS_PDU_IN_R1_B2_SIGNATURE, "IN_R1/B2" },
{ RTS_PDU_IN_R2_A1, FALSE, &RTS_PDU_IN_R2_A1_SIGNATURE, "IN_R2/A1" },
{ RTS_PDU_IN_R2_A2, FALSE, &RTS_PDU_IN_R2_A2_SIGNATURE, "IN_R2/A2" },
{ RTS_PDU_IN_R2_A3, FALSE, &RTS_PDU_IN_R2_A3_SIGNATURE, "IN_R2/A3" },
{ RTS_PDU_IN_R2_A4, TRUE, &RTS_PDU_IN_R2_A4_SIGNATURE, "IN_R2/A4" },
{ RTS_PDU_IN_R2_A5, FALSE, &RTS_PDU_IN_R2_A5_SIGNATURE, "IN_R2/A5" },
{ RTS_PDU_OUT_R1_A1, FALSE, &RTS_PDU_OUT_R1_A1_SIGNATURE, "OUT_R1/A1" },
{ RTS_PDU_OUT_R1_A2, TRUE, &RTS_PDU_OUT_R1_A2_SIGNATURE, "OUT_R1/A2" },
{ RTS_PDU_OUT_R1_A3, FALSE, &RTS_PDU_OUT_R1_A3_SIGNATURE, "OUT_R1/A3" },
{ RTS_PDU_OUT_R1_A4, FALSE, &RTS_PDU_OUT_R1_A4_SIGNATURE, "OUT_R1/A4" },
{ RTS_PDU_OUT_R1_A5, FALSE, &RTS_PDU_OUT_R1_A5_SIGNATURE, "OUT_R1/A5" },
{ RTS_PDU_OUT_R1_A6, TRUE, &RTS_PDU_OUT_R1_A6_SIGNATURE, "OUT_R1/A6" },
{ RTS_PDU_OUT_R1_A7, FALSE, &RTS_PDU_OUT_R1_A7_SIGNATURE, "OUT_R1/A7" },
{ RTS_PDU_OUT_R1_A8, FALSE, &RTS_PDU_OUT_R1_A8_SIGNATURE, "OUT_R1/A8" },
{ RTS_PDU_OUT_R1_A9, FALSE, &RTS_PDU_OUT_R1_A9_SIGNATURE, "OUT_R1/A9" },
{ RTS_PDU_OUT_R1_A10, TRUE, &RTS_PDU_OUT_R1_A10_SIGNATURE, "OUT_R1/A10" },
{ RTS_PDU_OUT_R1_A11, FALSE, &RTS_PDU_OUT_R1_A11_SIGNATURE, "OUT_R1/A11" },
{ RTS_PDU_OUT_R2_A1, FALSE, &RTS_PDU_OUT_R2_A1_SIGNATURE, "OUT_R2/A1" },
{ RTS_PDU_OUT_R2_A2, TRUE, &RTS_PDU_OUT_R2_A2_SIGNATURE, "OUT_R2/A2" },
{ RTS_PDU_OUT_R2_A3, FALSE, &RTS_PDU_OUT_R2_A3_SIGNATURE, "OUT_R2/A3" },
{ RTS_PDU_OUT_R2_A4, FALSE, &RTS_PDU_OUT_R2_A4_SIGNATURE, "OUT_R2/A4" },
{ RTS_PDU_OUT_R2_A5, FALSE, &RTS_PDU_OUT_R2_A5_SIGNATURE, "OUT_R2/A5" },
{ RTS_PDU_OUT_R2_A6, TRUE, &RTS_PDU_OUT_R2_A6_SIGNATURE, "OUT_R2/A6" },
{ RTS_PDU_OUT_R2_A7, FALSE, &RTS_PDU_OUT_R2_A7_SIGNATURE, "OUT_R2/A7" },
{ RTS_PDU_OUT_R2_A8, FALSE, &RTS_PDU_OUT_R2_A8_SIGNATURE, "OUT_R2/A8" },
{ RTS_PDU_OUT_R2_B1, FALSE, &RTS_PDU_OUT_R2_B1_SIGNATURE, "OUT_R2/B1" },
{ RTS_PDU_OUT_R2_B2, FALSE, &RTS_PDU_OUT_R2_B2_SIGNATURE, "OUT_R2/B2" },
{ RTS_PDU_OUT_R2_B3, TRUE, &RTS_PDU_OUT_R2_B3_SIGNATURE, "OUT_R2/B3" },
{ RTS_PDU_OUT_R2_C1, FALSE, &RTS_PDU_OUT_R2_C1_SIGNATURE, "OUT_R2/C1" },
{ RTS_PDU_KEEP_ALIVE, TRUE, &RTS_PDU_KEEP_ALIVE_SIGNATURE, "Keep-Alive" },
{ RTS_PDU_PING_TRAFFIC_SENT_NOTIFY, TRUE, &RTS_PDU_PING_TRAFFIC_SENT_NOTIFY_SIGNATURE,
"Ping Traffic Sent Notify" },
{ RTS_PDU_ECHO, TRUE, &RTS_PDU_ECHO_SIGNATURE, "Echo" },
{ RTS_PDU_PING, TRUE, &RTS_PDU_PING_SIGNATURE, "Ping" },
{ RTS_PDU_FLOW_CONTROL_ACK, TRUE, &RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE, "FlowControlAck" },
{ RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION, TRUE,
&RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE, "FlowControlAckWithDestination" }
};
BOOL rts_match_pdu_signature(const RtsPduSignature* signature, wStream* src,
const rpcconn_hdr_t* header)
{
return rts_match_pdu_signature_ex(signature, src, header, nullptr, FALSE);
}
BOOL rts_match_pdu_signature_ex(const RtsPduSignature* signature, wStream* src,
const rpcconn_hdr_t* header, RtsPduSignature* found_signature,
BOOL silent)
{
RtsPduSignature extracted = WINPR_C_ARRAY_INIT;
WINPR_ASSERT(signature);
WINPR_ASSERT(src);
if (!rts_extract_pdu_signature_ex(&extracted, src, header, silent))
return FALSE;
if (found_signature)
*found_signature = extracted;
return memcmp(signature, &extracted, sizeof(extracted)) == 0;
}
BOOL rts_extract_pdu_signature(RtsPduSignature* signature, wStream* src,
const rpcconn_hdr_t* header)
{
return rts_extract_pdu_signature_ex(signature, src, header, FALSE);
}
BOOL rts_extract_pdu_signature_ex(RtsPduSignature* signature, wStream* src,
const rpcconn_hdr_t* header, BOOL silent)
{
BOOL rc = FALSE;
wStream sbuffer = WINPR_C_ARRAY_INIT;
rpcconn_hdr_t rheader = WINPR_C_ARRAY_INIT;
const rpcconn_rts_hdr_t* rts = nullptr;
WINPR_ASSERT(signature);
WINPR_ASSERT(src);
wStream* s = Stream_StaticInit(&sbuffer, Stream_Pointer(src), Stream_GetRemainingLength(src));
if (!header)
{
if (!rts_read_pdu_header_ex(s, &rheader, silent))
goto fail;
header = &rheader;
}
rts = &header->rts;
if (rts->header.frag_length < sizeof(rpcconn_rts_hdr_t))
goto fail;
signature->Flags = rts->Flags;
signature->NumberOfCommands = rts->NumberOfCommands;
for (UINT16 i = 0; i < rts->NumberOfCommands; i++)
{
UINT32 CommandType = 0;
size_t CommandLength = 0;
if (!Stream_ConditionalCheckAndLogRequiredLength(TAG, s, 4, silent))
goto fail;
Stream_Read_UINT32(s, CommandType); /* CommandType (4 bytes) */
/* We only need this for comparison against known command types */
if (i < ARRAYSIZE(signature->CommandTypes))
signature->CommandTypes[i] = CommandType;
if (!rts_command_length(CommandType, s, &CommandLength, silent))
goto fail;
if (!Stream_ConditionalSafeSeek(s, CommandLength, silent))
goto fail;
}
rc = TRUE;
fail:
rts_free_pdu_header(&rheader, FALSE);
return rc;
}
UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature,
const RTS_PDU_SIGNATURE_ENTRY** entry)
{
if (entry)
*entry = nullptr;
for (size_t i = 0; i < ARRAYSIZE(RTS_PDU_SIGNATURE_TABLE); i++)
{
const RTS_PDU_SIGNATURE_ENTRY* current = &RTS_PDU_SIGNATURE_TABLE[i];
const RtsPduSignature* pSignature = current->Signature;
if (!current->SignatureClient)
continue;
if (signature->Flags != pSignature->Flags)
continue;
if (signature->NumberOfCommands != pSignature->NumberOfCommands)
continue;
for (size_t j = 0; j < signature->NumberOfCommands; j++)
{
if (signature->CommandTypes[j] != pSignature->CommandTypes[j])
continue;
}
if (entry)
*entry = current;
return current->SignatureId;
}
return 0;
}
BOOL rts_print_pdu_signature(wLog* log, DWORD level, const RtsPduSignature* signature)
{
UINT32 SignatureId = 0;
const RTS_PDU_SIGNATURE_ENTRY* entry = nullptr;
WINPR_ASSERT(signature);
WLog_Print(log, level,
"RTS PDU Signature: Flags: 0x%04" PRIX16 " NumberOfCommands: %" PRIu16 "",
signature->Flags, signature->NumberOfCommands);
SignatureId = rts_identify_pdu_signature(signature, &entry);
if (SignatureId)
WLog_Print(log, level, "Identified %s RTS PDU", entry->PduName);
return TRUE;
}

View File

@@ -0,0 +1,202 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Request To Send (RTS) PDU Signatures
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_RTS_SIGNATURE_H
#define FREERDP_LIB_CORE_GATEWAY_RTS_SIGNATURE_H
#include "rts.h"
#include <winpr/wtypes.h>
#include <freerdp/api.h>
typedef struct
{
UINT16 Flags;
UINT16 NumberOfCommands;
UINT32 CommandTypes[8];
} RtsPduSignature;
typedef struct
{
UINT32 SignatureId;
BOOL SignatureClient;
const RtsPduSignature* Signature;
const char* PduName;
} RTS_PDU_SIGNATURE_ENTRY;
/* RTS PDU Signature IDs */
#define RTS_PDU_CONN_A 0x10000000
#define RTS_PDU_CONN_A1 (RTS_PDU_CONN_A | 0x00000001)
#define RTS_PDU_CONN_A2 (RTS_PDU_CONN_A | 0x00000002)
#define RTS_PDU_CONN_A3 (RTS_PDU_CONN_A | 0x00000003)
#define RTS_PDU_CONN_B 0x20000000
#define RTS_PDU_CONN_B1 (RTS_PDU_CONN_B | 0x00000001)
#define RTS_PDU_CONN_B2 (RTS_PDU_CONN_B | 0x00000002)
#define RTS_PDU_CONN_B3 (RTS_PDU_CONN_B | 0x00000003)
#define RTS_PDU_CONN_C 0x40000000
#define RTS_PDU_CONN_C1 (RTS_PDU_CONN_C | 0x00000001)
#define RTS_PDU_CONN_C2 (RTS_PDU_CONN_C | 0x00000002)
#define RTS_PDU_IN_R1_A 0x01000000
#define RTS_PDU_IN_R1_A1 (RTS_PDU_IN_R1_A | 0x00000001)
#define RTS_PDU_IN_R1_A2 (RTS_PDU_IN_R1_A | 0x00000002)
#define RTS_PDU_IN_R1_A3 (RTS_PDU_IN_R1_A | 0x00000003)
#define RTS_PDU_IN_R1_A4 (RTS_PDU_IN_R1_A | 0x00000004)
#define RTS_PDU_IN_R1_A5 (RTS_PDU_IN_R1_A | 0x00000005)
#define RTS_PDU_IN_R1_A6 (RTS_PDU_IN_R1_A | 0x00000006)
#define RTS_PDU_IN_R1_B 0x02000000
#define RTS_PDU_IN_R1_B1 (RTS_PDU_IN_R1_B | 0x00000001)
#define RTS_PDU_IN_R1_B2 (RTS_PDU_IN_R1_B | 0x00000002)
#define RTS_PDU_IN_R2_A 0x04000000
#define RTS_PDU_IN_R2_A1 (RTS_PDU_IN_R2_A | 0x00000001)
#define RTS_PDU_IN_R2_A2 (RTS_PDU_IN_R2_A | 0x00000002)
#define RTS_PDU_IN_R2_A3 (RTS_PDU_IN_R2_A | 0x00000003)
#define RTS_PDU_IN_R2_A4 (RTS_PDU_IN_R2_A | 0x00000004)
#define RTS_PDU_IN_R2_A5 (RTS_PDU_IN_R2_A | 0x00000005)
#define RTS_PDU_OUT_R1_A 0x00100000
#define RTS_PDU_OUT_R1_A1 (RTS_PDU_OUT_R1_A | 0x00000001)
#define RTS_PDU_OUT_R1_A2 (RTS_PDU_OUT_R1_A | 0x00000002)
#define RTS_PDU_OUT_R1_A3 (RTS_PDU_OUT_R1_A | 0x00000003)
#define RTS_PDU_OUT_R1_A4 (RTS_PDU_OUT_R1_A | 0x00000004)
#define RTS_PDU_OUT_R1_A5 (RTS_PDU_OUT_R1_A | 0x00000005)
#define RTS_PDU_OUT_R1_A6 (RTS_PDU_OUT_R1_A | 0x00000006)
#define RTS_PDU_OUT_R1_A7 (RTS_PDU_OUT_R1_A | 0x00000007)
#define RTS_PDU_OUT_R1_A8 (RTS_PDU_OUT_R1_A | 0x00000008)
#define RTS_PDU_OUT_R1_A9 (RTS_PDU_OUT_R1_A | 0x00000009)
#define RTS_PDU_OUT_R1_A10 (RTS_PDU_OUT_R1_A | 0x0000000A)
#define RTS_PDU_OUT_R1_A11 (RTS_PDU_OUT_R1_A | 0x0000000B)
#define RTS_PDU_OUT_R2_A 0x00200000
#define RTS_PDU_OUT_R2_A1 (RTS_PDU_OUT_R2_A | 0x00000001)
#define RTS_PDU_OUT_R2_A2 (RTS_PDU_OUT_R2_A | 0x00000002)
#define RTS_PDU_OUT_R2_A3 (RTS_PDU_OUT_R2_A | 0x00000003)
#define RTS_PDU_OUT_R2_A4 (RTS_PDU_OUT_R2_A | 0x00000004)
#define RTS_PDU_OUT_R2_A5 (RTS_PDU_OUT_R2_A | 0x00000005)
#define RTS_PDU_OUT_R2_A6 (RTS_PDU_OUT_R2_A | 0x00000006)
#define RTS_PDU_OUT_R2_A7 (RTS_PDU_OUT_R2_A | 0x00000007)
#define RTS_PDU_OUT_R2_A8 (RTS_PDU_OUT_R2_A | 0x00000008)
#define RTS_PDU_OUT_R2_B 0x00400000
#define RTS_PDU_OUT_R2_B1 (RTS_PDU_OUT_R2_B | 0x00000001)
#define RTS_PDU_OUT_R2_B2 (RTS_PDU_OUT_R2_B | 0x00000002)
#define RTS_PDU_OUT_R2_B3 (RTS_PDU_OUT_R2_B | 0x00000003)
#define RTS_PDU_OUT_R2_C 0x00800000
#define RTS_PDU_OUT_R2_C1 (RTS_PDU_OUT_R2_C | 0x00000001)
#define RTS_PDU_OUT_OF_SEQUENCE 0x00010000
#define RTS_PDU_KEEP_ALIVE (RTS_PDU_OUT_OF_SEQUENCE | 0x00000001)
#define RTS_PDU_PING_TRAFFIC_SENT_NOTIFY (RTS_PDU_OUT_OF_SEQUENCE | 0x00000002)
#define RTS_PDU_ECHO (RTS_PDU_OUT_OF_SEQUENCE | 0x00000003)
#define RTS_PDU_PING (RTS_PDU_OUT_OF_SEQUENCE | 0x00000004)
#define RTS_PDU_FLOW_CONTROL_ACK (RTS_PDU_OUT_OF_SEQUENCE | 0x00000005)
#define RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION (RTS_PDU_OUT_OF_SEQUENCE | 0x00000006)
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_CONN_A1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_CONN_A2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_CONN_A3_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_CONN_B1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_CONN_B2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_CONN_B3_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_CONN_C1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_CONN_C2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R1_A1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R1_A2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R1_A3_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R1_A4_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R1_A5_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R1_A6_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R1_B1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R1_B2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R2_A1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R2_A2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R2_A3_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R2_A4_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_IN_R2_A5_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A3_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A4_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A5_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A6_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A7_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A8_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A9_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A10_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R1_A11_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_A1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_A2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_A3_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_A4_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_A5_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_A6_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_A7_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_A8_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_B1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_B2_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_B3_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_OUT_R2_C1_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_KEEP_ALIVE_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_PING_TRAFFIC_SENT_NOTIFY_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_ECHO_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_PING_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE;
FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE;
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_match_pdu_signature(const RtsPduSignature* signature, wStream* s,
const rpcconn_hdr_t* header);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_match_pdu_signature_ex(const RtsPduSignature* signature, wStream* s,
const rpcconn_hdr_t* header,
RtsPduSignature* found_signature, BOOL silent);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_extract_pdu_signature(RtsPduSignature* signature, wStream* s,
const rpcconn_hdr_t* header);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rts_extract_pdu_signature_ex(RtsPduSignature* signature, wStream* s,
const rpcconn_hdr_t* header, BOOL silent);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature,
const RTS_PDU_SIGNATURE_ENTRY** entry);
FREERDP_LOCAL BOOL rts_print_pdu_signature(wLog* log, DWORD level,
const RtsPduSignature* signature);
#endif /* FREERDP_LIB_CORE_GATEWAY_RTS_SIGNATURE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,132 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Terminal Server Gateway (TSG)
*
* Copyright 2012 Fujitsu Technology Solutions GmbH
* Copyright 2012 Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_TSG_H
#define FREERDP_LIB_CORE_GATEWAY_TSG_H
typedef struct rdp_tsg rdpTsg;
#include "rpc.h"
#include "../transport.h"
#include <winpr/rpc.h>
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
#include <freerdp/types.h>
#include <freerdp/api.h>
typedef enum
{
TSG_STATE_INITIAL,
TSG_STATE_CONNECTED,
TSG_STATE_AUTHORIZED,
TSG_STATE_CHANNEL_CREATED,
TSG_STATE_PIPE_CREATED,
TSG_STATE_TUNNEL_CLOSE_PENDING,
TSG_STATE_CHANNEL_CLOSE_PENDING,
TSG_STATE_FINAL
} TSG_STATE;
static const uint16_t TsProxyCreateTunnelOpnum = 1u;
static const uint16_t TsProxyAuthorizeTunnelOpnum = 2u;
static const uint16_t TsProxyMakeTunnelCallOpnum = 3u;
static const uint16_t TsProxyCreateChannelOpnum = 4u;
static const uint16_t TsProxyUnused5Opnum = 5u;
static const uint16_t TsProxyCloseChannelOpnum = 6u;
static const uint16_t TsProxyCloseTunnelOpnum = 7u;
static const uint16_t TsProxySetupReceivePipeOpnum = 8u;
static const uint16_t TsProxySendToServerOpnum = 9u;
#define TS_GATEWAY_TRANSPORT 0x5452u
#define TSG_ASYNC_MESSAGE_CONSENT_MESSAGE 0x00000001u
#define TSG_ASYNC_MESSAGE_SERVICE_MESSAGE 0x00000002u
#define TSG_ASYNC_MESSAGE_REAUTH 0x00000003u
#define TSG_TUNNEL_CALL_ASYNC_MSG_REQUEST 0x00000001u
#define TSG_TUNNEL_CANCEL_ASYNC_MSG_REQUEST 0x00000002u
#define TSG_NAP_CAPABILITY_QUAR_SOH 0x00000001u
#define TSG_NAP_CAPABILITY_IDLE_TIMEOUT 0x00000002u
#define TSG_MESSAGING_CAP_CONSENT_SIGN 0x00000004u
#define TSG_MESSAGING_CAP_SERVICE_MSG 0x00000008u
#define TSG_MESSAGING_CAP_REAUTH 0x00000010u
#define TSG_MESSAGING_MAX_MESSAGE_LENGTH 65536u
/* Error Codes */
#define E_PROXY_INTERNALERROR 0x800759D8
#define E_PROXY_RAP_ACCESSDENIED 0x800759DA
#define E_PROXY_NAP_ACCESSDENIED 0x800759DB
#define E_PROXY_TS_CONNECTFAILED 0x800759DD
#define E_PROXY_ALREADYDISCONNECTED 0x800759DF
#define E_PROXY_QUARANTINE_ACCESSDENIED 0x800759ED
#define E_PROXY_NOCERTAVAILABLE 0x800759EE
#define E_PROXY_COOKIE_BADPACKET 0x800759F7
#define E_PROXY_COOKIE_AUTHENTICATION_ACCESS_DENIED 0x800759F8
#define E_PROXY_UNSUPPORTED_AUTHENTICATION_METHOD 0x800759F9
#define E_PROXY_CAPABILITYMISMATCH 0x800759E9
#define E_PROXY_NOTSUPPORTED 0x000059E8
#define E_PROXY_MAXCONNECTIONSREACHED 0x000059E6
#define E_PROXY_SESSIONTIMEOUT 0x000059F6
#define E_PROXY_REAUTH_AUTHN_FAILED 0x000059FA
#define E_PROXY_REAUTH_CAP_FAILED 0x000059FB
#define E_PROXY_REAUTH_RAP_FAILED 0x000059FC
#define E_PROXY_SDR_NOT_SUPPORTED_BY_TS 0x000059FD
#define E_PROXY_REAUTH_NAP_FAILED 0x00005A00
#define E_PROXY_CONNECTIONABORTED 0x000004D4
FREERDP_LOCAL void tsg_free(rdpTsg* tsg);
WINPR_ATTR_MALLOC(tsg_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpTsg* tsg_new(rdpTransport* transport);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL tsg_proxy_begin(rdpTsg* tsg);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL tsg_disconnect(rdpTsg* tsg);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL tsg_recv_pdu(rdpTsg* tsg, const RPC_PDU* pdu);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL tsg_check_event_handles(rdpTsg* tsg);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL DWORD tsg_get_event_handles(rdpTsg* tsg, HANDLE* events, DWORD count);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL TSG_STATE tsg_get_state(rdpTsg* tsg);
FREERDP_LOCAL BOOL tsg_set_state(rdpTsg* tsg, TSG_STATE state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BIO* tsg_get_bio(rdpTsg* tsg);
#endif /* FREERDP_LIB_CORE_GATEWAY_TSG_H */

View File

@@ -0,0 +1,495 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Websocket Framing
*
* Copyright 2023 Michael Saxl <mike@mwsys.mine.bz>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "websocket.h"
#include <freerdp/log.h>
#include "../tcp.h"
#define TAG FREERDP_TAG("core.gateway.websocket")
struct s_websocket_context
{
size_t payloadLength;
uint32_t maskingKey;
BOOL masking;
BOOL closeSent;
BYTE opcode;
BYTE fragmentOriginalOpcode;
BYTE lengthAndMaskPosition;
WEBSOCKET_STATE state;
wStream* responseStreamBuffer;
};
static int websocket_write_all(BIO* bio, const BYTE* data, size_t length);
BOOL websocket_context_mask_and_send(BIO* bio, wStream* sPacket, wStream* sDataPacket,
UINT32 maskingKey)
{
const size_t len = Stream_Length(sDataPacket);
Stream_ResetPosition(sDataPacket);
if (!Stream_EnsureRemainingCapacity(sPacket, len))
return FALSE;
/* mask as much as possible with 32bit access */
size_t streamPos = 0;
for (; streamPos + 4 <= len; streamPos += 4)
{
const uint32_t data = Stream_Get_UINT32(sDataPacket);
Stream_Write_UINT32(sPacket, data ^ maskingKey);
}
/* mask the rest byte by byte */
for (; streamPos < len; streamPos++)
{
BYTE data = 0;
BYTE* partialMask = ((BYTE*)&maskingKey) + (streamPos % 4);
Stream_Read_UINT8(sDataPacket, data);
Stream_Write_UINT8(sPacket, data ^ *partialMask);
}
Stream_SealLength(sPacket);
ERR_clear_error();
const size_t size = Stream_Length(sPacket);
const int status = websocket_write_all(bio, Stream_Buffer(sPacket), size);
Stream_Free(sPacket, TRUE);
return !((status < 0) || ((size_t)status != size));
}
wStream* websocket_context_packet_new(size_t len, WEBSOCKET_OPCODE opcode, UINT32* pMaskingKey)
{
WINPR_ASSERT(pMaskingKey);
if (len > INT_MAX)
return nullptr;
size_t fullLen = 0;
if (len < 126)
fullLen = len + 6; /* 2 byte "mini header" + 4 byte masking key */
else if (len < 0x10000)
fullLen = len + 8; /* 2 byte "mini header" + 2 byte length + 4 byte masking key */
else
fullLen = len + 14; /* 2 byte "mini header" + 8 byte length + 4 byte masking key */
UINT32 maskingKey = 0;
if (winpr_RAND(&maskingKey, sizeof(maskingKey)) < 0)
return nullptr;
wStream* sWS = Stream_New(nullptr, fullLen);
if (!sWS)
return nullptr;
Stream_Write_UINT8(sWS, (UINT8)(WEBSOCKET_FIN_BIT | opcode));
if (len < 126)
Stream_Write_UINT8(sWS, (UINT8)len | WEBSOCKET_MASK_BIT);
else if (len < 0x10000)
{
Stream_Write_UINT8(sWS, 126 | WEBSOCKET_MASK_BIT);
Stream_Write_UINT16_BE(sWS, (UINT16)len);
}
else
{
Stream_Write_UINT8(sWS, 127 | WEBSOCKET_MASK_BIT);
Stream_Write_UINT32_BE(sWS, 0); /* payload is limited to INT_MAX */
Stream_Write_UINT32_BE(sWS, (UINT32)len);
}
Stream_Write_UINT32(sWS, maskingKey);
*pMaskingKey = maskingKey;
return sWS;
}
BOOL websocket_context_write_wstream(websocket_context* context, BIO* bio, wStream* sPacket,
WEBSOCKET_OPCODE opcode)
{
WINPR_ASSERT(context);
if (context->closeSent)
return FALSE;
if (opcode == WebsocketCloseOpcode)
context->closeSent = TRUE;
WINPR_ASSERT(bio);
WINPR_ASSERT(sPacket);
const size_t len = Stream_Length(sPacket);
uint32_t maskingKey = 0;
wStream* sWS = websocket_context_packet_new(len, opcode, &maskingKey);
if (!sWS)
return FALSE;
return websocket_context_mask_and_send(bio, sWS, sPacket, maskingKey);
}
int websocket_write_all(BIO* bio, const BYTE* data, size_t length)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(data);
size_t offset = 0;
if (length > INT32_MAX)
return -1;
while (offset < length)
{
ERR_clear_error();
const size_t diff = length - offset;
int status = BIO_write(bio, &data[offset], (int)diff);
if (status > 0)
offset += (size_t)status;
else
{
if (!BIO_should_retry(bio))
return -1;
if (BIO_write_blocked(bio))
{
const long rstatus = BIO_wait_write(bio, 100);
if (rstatus < 0)
return -1;
}
else if (BIO_read_blocked(bio))
return -2; /* Abort write, there is data that must be read */
else
USleep(100);
}
}
return (int)length;
}
int websocket_context_write(websocket_context* context, BIO* bio, const BYTE* buf, int isize,
WEBSOCKET_OPCODE opcode)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(buf);
if (isize < 0)
return -1;
wStream sbuffer = WINPR_C_ARRAY_INIT;
wStream* s = Stream_StaticConstInit(&sbuffer, buf, (size_t)isize);
if (!websocket_context_write_wstream(context, bio, s, opcode))
return -2;
return isize;
}
static int websocket_read_data(BIO* bio, BYTE* pBuffer, size_t size,
websocket_context* encodingContext)
{
int status = 0;
WINPR_ASSERT(bio);
WINPR_ASSERT(pBuffer);
WINPR_ASSERT(encodingContext);
if (encodingContext->payloadLength == 0)
{
encodingContext->state = WebsocketStateOpcodeAndFin;
return 0;
}
const size_t rlen =
(encodingContext->payloadLength < size ? encodingContext->payloadLength : size);
if (rlen > INT32_MAX)
return -1;
ERR_clear_error();
status = BIO_read(bio, pBuffer, (int)rlen);
if ((status <= 0) || ((size_t)status > encodingContext->payloadLength))
return status;
encodingContext->payloadLength -= (size_t)status;
if (encodingContext->payloadLength == 0)
encodingContext->state = WebsocketStateOpcodeAndFin;
return status;
}
static int websocket_read_wstream(BIO* bio, websocket_context* encodingContext)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(encodingContext);
wStream* s = encodingContext->responseStreamBuffer;
WINPR_ASSERT(s);
if (encodingContext->payloadLength == 0)
{
encodingContext->state = WebsocketStateOpcodeAndFin;
return 0;
}
if (!Stream_EnsureRemainingCapacity(s, encodingContext->payloadLength))
{
WLog_WARN(TAG,
"wStream::capacity [%" PRIuz "] != encodingContext::paylaodLangth [%" PRIuz "]",
Stream_GetRemainingCapacity(s), encodingContext->payloadLength);
return -1;
}
const int status = websocket_read_data(bio, Stream_Pointer(s), Stream_GetRemainingCapacity(s),
encodingContext);
if (status < 0)
return status;
if (!Stream_SafeSeek(s, (size_t)status))
return -1;
return status;
}
static BOOL websocket_reply_close(BIO* bio, websocket_context* context, wStream* s)
{
WINPR_ASSERT(bio);
return websocket_context_write_wstream(context, bio, s, WebsocketCloseOpcode);
}
static BOOL websocket_reply_pong(BIO* bio, websocket_context* context, wStream* s)
{
WINPR_ASSERT(bio);
WINPR_ASSERT(s);
if (Stream_GetPosition(s) != 0)
return websocket_context_write_wstream(context, bio, s, WebsocketPongOpcode);
return websocket_reply_close(bio, context, nullptr);
}
static int websocket_handle_payload(BIO* bio, BYTE* pBuffer, size_t size,
websocket_context* encodingContext)
{
int status = 0;
WINPR_ASSERT(bio);
WINPR_ASSERT(pBuffer);
WINPR_ASSERT(encodingContext);
const BYTE effectiveOpcode = ((encodingContext->opcode & 0xf) == WebsocketContinuationOpcode
? encodingContext->fragmentOriginalOpcode & 0xf
: encodingContext->opcode & 0xf);
switch (effectiveOpcode)
{
case WebsocketBinaryOpcode:
{
status = websocket_read_data(bio, pBuffer, size, encodingContext);
if (status < 0)
return status;
return status;
}
case WebsocketPingOpcode:
{
status = websocket_read_wstream(bio, encodingContext);
if (status < 0)
return status;
if (encodingContext->payloadLength == 0)
{
websocket_reply_pong(bio, encodingContext, encodingContext->responseStreamBuffer);
Stream_ResetPosition(encodingContext->responseStreamBuffer);
}
}
break;
case WebsocketPongOpcode:
{
status = websocket_read_wstream(bio, encodingContext);
if (status < 0)
return status;
/* We don´t care about pong response data, discard. */
Stream_ResetPosition(encodingContext->responseStreamBuffer);
}
break;
case WebsocketCloseOpcode:
{
status = websocket_read_wstream(bio, encodingContext);
if (status < 0)
return status;
if (encodingContext->payloadLength == 0)
{
websocket_reply_close(bio, encodingContext, encodingContext->responseStreamBuffer);
encodingContext->closeSent = TRUE;
Stream_ResetPosition(encodingContext->responseStreamBuffer);
}
}
break;
default:
WLog_WARN(TAG, "Unimplemented websocket opcode %" PRIx8 ". Dropping", effectiveOpcode);
status = websocket_read_wstream(bio, encodingContext);
if (status < 0)
return status;
Stream_ResetPosition(encodingContext->responseStreamBuffer);
break;
}
/* return how many bytes have been written to pBuffer.
* Only WebsocketBinaryOpcode writes into it and it returns directly */
return 0;
}
int websocket_context_read(websocket_context* encodingContext, BIO* bio, BYTE* pBuffer, size_t size)
{
int status = 0;
size_t effectiveDataLen = 0;
WINPR_ASSERT(bio);
WINPR_ASSERT(pBuffer);
WINPR_ASSERT(encodingContext);
while (TRUE)
{
switch (encodingContext->state)
{
case WebsocketStateOpcodeAndFin:
{
BYTE buffer[1] = WINPR_C_ARRAY_INIT;
ERR_clear_error();
status = BIO_read(bio, (char*)buffer, sizeof(buffer));
if (status <= 0)
return (effectiveDataLen > 0 ? WINPR_ASSERTING_INT_CAST(int, effectiveDataLen)
: status);
encodingContext->opcode = buffer[0];
if (((encodingContext->opcode & 0xf) != WebsocketContinuationOpcode) &&
(encodingContext->opcode & 0xf) < 0x08)
encodingContext->fragmentOriginalOpcode = encodingContext->opcode;
encodingContext->state = WebsocketStateLengthAndMasking;
}
break;
case WebsocketStateLengthAndMasking:
{
BYTE buffer[1] = WINPR_C_ARRAY_INIT;
ERR_clear_error();
status = BIO_read(bio, (char*)buffer, sizeof(buffer));
if (status <= 0)
return (effectiveDataLen > 0 ? WINPR_ASSERTING_INT_CAST(int, effectiveDataLen)
: status);
encodingContext->masking = ((buffer[0] & WEBSOCKET_MASK_BIT) == WEBSOCKET_MASK_BIT);
encodingContext->lengthAndMaskPosition = 0;
encodingContext->payloadLength = 0;
const BYTE len = buffer[0] & 0x7f;
if (len < 126)
{
encodingContext->payloadLength = len;
encodingContext->state = (encodingContext->masking ? WebSocketStateMaskingKey
: WebSocketStatePayload);
}
else if (len == 126)
encodingContext->state = WebsocketStateShortLength;
else
encodingContext->state = WebsocketStateLongLength;
}
break;
case WebsocketStateShortLength:
case WebsocketStateLongLength:
{
BYTE buffer[1] = WINPR_C_ARRAY_INIT;
const BYTE lenLength =
(encodingContext->state == WebsocketStateShortLength ? 2 : 8);
while (encodingContext->lengthAndMaskPosition < lenLength)
{
ERR_clear_error();
status = BIO_read(bio, (char*)buffer, sizeof(buffer));
if (status <= 0)
return (effectiveDataLen > 0
? WINPR_ASSERTING_INT_CAST(int, effectiveDataLen)
: status);
if (status > UINT8_MAX)
return -1;
encodingContext->payloadLength =
(encodingContext->payloadLength) << 8 | buffer[0];
encodingContext->lengthAndMaskPosition +=
WINPR_ASSERTING_INT_CAST(BYTE, status);
}
encodingContext->state =
(encodingContext->masking ? WebSocketStateMaskingKey : WebSocketStatePayload);
}
break;
case WebSocketStateMaskingKey:
{
WLog_WARN(
TAG, "Websocket Server sends data with masking key. This is against RFC 6455.");
return -1;
}
case WebSocketStatePayload:
{
status = websocket_handle_payload(bio, pBuffer, size, encodingContext);
if (status < 0)
return (effectiveDataLen > 0 ? WINPR_ASSERTING_INT_CAST(int, effectiveDataLen)
: status);
effectiveDataLen += WINPR_ASSERTING_INT_CAST(size_t, status);
if (WINPR_ASSERTING_INT_CAST(size_t, status) >= size)
return WINPR_ASSERTING_INT_CAST(int, effectiveDataLen);
pBuffer += status;
size -= WINPR_ASSERTING_INT_CAST(size_t, status);
}
break;
default:
break;
}
}
/* should be unreachable */
}
websocket_context* websocket_context_new(void)
{
websocket_context* context = calloc(1, sizeof(websocket_context));
if (!context)
goto fail;
context->responseStreamBuffer = Stream_New(nullptr, 1024);
if (!context->responseStreamBuffer)
goto fail;
if (!websocket_context_reset(context))
goto fail;
return context;
fail:
websocket_context_free(context);
return nullptr;
}
void websocket_context_free(websocket_context* context)
{
if (!context)
return;
Stream_Free(context->responseStreamBuffer, TRUE);
free(context);
}
BOOL websocket_context_reset(websocket_context* context)
{
WINPR_ASSERT(context);
context->state = WebsocketStateOpcodeAndFin;
return Stream_SetPosition(context->responseStreamBuffer, 0);
}

View File

@@ -0,0 +1,85 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Websocket Framing
*
* Copyright 2023 Michael Saxl <mike@mwsys.mine.bz>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_WEBSOCKET_H
#define FREERDP_LIB_CORE_GATEWAY_WEBSOCKET_H
#include <winpr/wtypes.h>
#include <winpr/stream.h>
#include <freerdp/api.h>
#include "../../crypto/tls.h"
#define WEBSOCKET_MASK_BIT 0x80
#define WEBSOCKET_FIN_BIT 0x80
typedef enum
{
WebsocketContinuationOpcode = 0x0,
WebsocketTextOpcode = 0x1,
WebsocketBinaryOpcode = 0x2,
WebsocketCloseOpcode = 0x8,
WebsocketPingOpcode = 0x9,
WebsocketPongOpcode = 0xa,
} WEBSOCKET_OPCODE;
typedef enum
{
WebsocketStateOpcodeAndFin,
WebsocketStateLengthAndMasking,
WebsocketStateShortLength,
WebsocketStateLongLength,
WebSocketStateMaskingKey,
WebSocketStatePayload,
} WEBSOCKET_STATE;
typedef struct s_websocket_context websocket_context;
FREERDP_LOCAL void websocket_context_free(websocket_context* context);
WINPR_ATTR_MALLOC(websocket_context_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL websocket_context* websocket_context_new(void);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL websocket_context_reset(websocket_context* context);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL websocket_context_write_wstream(websocket_context* context, BIO* bio,
wStream* sPacket, WEBSOCKET_OPCODE opcode);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int websocket_context_write(websocket_context* context, BIO* bio, const BYTE* buf,
int isize, WEBSOCKET_OPCODE opcode);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int websocket_context_read(websocket_context* encodingContext, BIO* bio,
BYTE* pBuffer, size_t size);
WINPR_ATTR_MALLOC(Stream_Free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* websocket_context_packet_new(size_t len, WEBSOCKET_OPCODE opcode,
UINT32* pMaskingKey);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL websocket_context_mask_and_send(BIO* bio, wStream* sPacket, wStream* sDataPacket,
UINT32 maskingKey);
#endif /* FREERDP_LIB_CORE_GATEWAY_WEBSOCKET_H */

View File

@@ -0,0 +1,944 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Websocket Transport
*
* Copyright 2023 Michael Saxl <mike@mwsys.mine.bz>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <freerdp/config.h>
#include <freerdp/version.h>
#include <winpr/assert.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/print.h>
#include <winpr/stream.h>
#include <winpr/winsock.h>
#include <winpr/cred.h>
#include "../settings.h"
#include <freerdp/log.h>
#include <freerdp/error.h>
#include <freerdp/utils/ringbuffer.h>
#include <freerdp/utils/smartcardlogon.h>
#include "wst.h"
#include "websocket.h"
#include "http.h"
#include "../credssp_auth.h"
#include "../proxy.h"
#include "../rdp.h"
#include "../../crypto/opensslcompat.h"
#include "rpc_fault.h"
#include "../utils.h"
#define TAG FREERDP_TAG("core.gateway.wst")
#define AUTH_PKG NEGO_SSP_NAME
struct rdp_wst
{
rdpContext* context;
BOOL attached;
BIO* frontBio;
rdpTls* tls;
rdpCredsspAuth* auth;
BOOL auth_required;
HttpContext* http;
CRITICAL_SECTION writeSection;
char* gwhostname;
uint16_t gwport;
char* gwpath;
websocket_context* wscontext;
wLog* log;
};
static const char arm_query_param[] = "%s%cClmTk=Bearer%%20%s";
static BOOL wst_get_gateway_credentials(wLog* log, rdpContext* context, rdp_auth_reason reason)
{
WINPR_ASSERT(context);
freerdp* instance = context->instance;
auth_status rc = utils_authenticate_gateway(instance, reason);
switch (rc)
{
case AUTH_SUCCESS:
case AUTH_SKIP:
return TRUE;
case AUTH_CANCELLED:
freerdp_set_last_error_log(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
return FALSE;
case AUTH_NO_CREDENTIALS:
WLog_Print(log, WLOG_INFO, "No credentials provided - using nullptr identity");
return TRUE;
case AUTH_FAILED:
default:
return FALSE;
}
}
static BOOL wst_auth_init(rdpWst* wst, rdpTls* tls, TCHAR* authPkg)
{
WINPR_ASSERT(wst);
WINPR_ASSERT(tls);
WINPR_ASSERT(authPkg);
rdpContext* context = wst->context;
rdpSettings* settings = context->settings;
SEC_WINNT_AUTH_IDENTITY identity = WINPR_C_ARRAY_INIT;
int rc = 0;
wst->auth_required = TRUE;
if (!credssp_auth_init(wst->auth, authPkg, tls->Bindings))
return FALSE;
if (!wst_get_gateway_credentials(wst->log, context, GW_AUTH_RDG))
return FALSE;
if (!identity_set_from_settings(&identity, settings, FreeRDP_GatewayUsername,
FreeRDP_GatewayDomain, FreeRDP_GatewayPassword))
return FALSE;
SEC_WINNT_AUTH_IDENTITY* identityArg = (settings->GatewayUsername ? &identity : nullptr);
if (!credssp_auth_setup_client(wst->auth, "HTTP", wst->gwhostname, identityArg, nullptr))
{
sspi_FreeAuthIdentity(&identity);
return FALSE;
}
sspi_FreeAuthIdentity(&identity);
credssp_auth_set_flags(wst->auth, ISC_REQ_CONFIDENTIALITY | ISC_REQ_MUTUAL_AUTH);
rc = credssp_auth_authenticate(wst->auth);
return (rc >= 0);
}
static BOOL wst_set_auth_header(rdpCredsspAuth* auth, HttpRequest* request)
{
WINPR_ASSERT(auth);
WINPR_ASSERT(request);
const SecBuffer* authToken = credssp_auth_get_output_buffer(auth);
char* base64AuthToken = nullptr;
if (authToken)
{
if (authToken->cbBuffer > INT_MAX)
return FALSE;
base64AuthToken = crypto_base64_encode(authToken->pvBuffer, authToken->cbBuffer);
}
if (base64AuthToken)
{
BOOL rc = http_request_set_auth_scheme(request, credssp_auth_pkg_name(auth)) &&
http_request_set_auth_param(request, base64AuthToken);
free(base64AuthToken);
if (!rc)
return FALSE;
}
return TRUE;
}
static BOOL wst_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
{
size_t len = 0;
size_t authTokenLength = 0;
BYTE* authTokenData = nullptr;
SecBuffer authToken = WINPR_C_ARRAY_INIT;
int rc = 0;
if (!auth || !response)
return FALSE;
const UINT16 StatusCode = http_response_get_status_code(response);
switch (StatusCode)
{
case HTTP_STATUS_DENIED:
case HTTP_STATUS_OK:
break;
default:
http_response_log_error_status(WLog_Get(TAG), WLOG_WARN, response);
return FALSE;
}
const char* token64 = http_response_get_auth_token(response, credssp_auth_pkg_name(auth));
if (!token64)
return FALSE;
len = strlen(token64);
crypto_base64_decode(token64, len, &authTokenData, &authTokenLength);
if (authTokenLength && (authTokenLength <= UINT32_MAX) && authTokenData)
{
authToken.pvBuffer = authTokenData;
authToken.cbBuffer = (UINT32)authTokenLength;
credssp_auth_take_input_buffer(auth, &authToken);
}
else
free(authTokenData);
rc = credssp_auth_authenticate(auth);
return (rc >= 0);
}
static BOOL wst_tls_connect(rdpWst* wst, rdpTls* tls, UINT32 timeout)
{
WINPR_ASSERT(wst);
WINPR_ASSERT(tls);
int sockfd = 0;
long status = 0;
BIO* socketBio = nullptr;
BIO* bufferedBio = nullptr;
rdpSettings* settings = wst->context->settings;
const char* peerHostname = wst->gwhostname;
UINT16 peerPort = wst->gwport;
const char* proxyUsername = nullptr;
const char* proxyPassword = nullptr;
BOOL isProxyConnection =
proxy_prepare(settings, &peerHostname, &peerPort, &proxyUsername, &proxyPassword);
sockfd = freerdp_tcp_connect(wst->context, peerHostname, peerPort, timeout);
WLog_Print(wst->log, WLOG_DEBUG, "connecting to %s %d", peerHostname, peerPort);
if (sockfd < 0)
{
return FALSE;
}
socketBio = BIO_new(BIO_s_simple_socket());
if (!socketBio)
{
closesocket((SOCKET)sockfd);
return FALSE;
}
BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
bufferedBio = BIO_new(BIO_s_buffered_socket());
if (!bufferedBio)
{
BIO_free_all(socketBio);
return FALSE;
}
bufferedBio = BIO_push(bufferedBio, socketBio);
status = BIO_set_nonblock(bufferedBio, TRUE);
if (isProxyConnection)
{
if (!proxy_connect(wst->context, bufferedBio, proxyUsername, proxyPassword, wst->gwhostname,
wst->gwport))
{
BIO_free_all(bufferedBio);
return FALSE;
}
}
if (!status)
{
BIO_free_all(bufferedBio);
return FALSE;
}
tls->hostname = wst->gwhostname;
tls->port = MIN(UINT16_MAX, wst->gwport);
tls->isGatewayTransport = TRUE;
status = freerdp_tls_connect(tls, bufferedBio);
if (status < 1)
{
rdpContext* context = wst->context;
if (status < 0)
{
freerdp_set_last_error_if_not(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
}
else
{
freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
}
return FALSE;
}
return (status >= 1);
}
static wStream* wst_build_http_request(rdpWst* wst)
{
wStream* s = nullptr;
HttpRequest* request = nullptr;
const char* uri = nullptr;
if (!wst)
return nullptr;
uri = http_context_get_uri(wst->http);
request = http_request_new();
if (!request)
return nullptr;
if (!http_request_set_method(request, "GET") || !http_request_set_uri(request, uri))
goto out;
if (wst->auth_required)
{
if (!wst_set_auth_header(wst->auth, request))
goto out;
}
else if (freerdp_settings_get_string(wst->context->settings, FreeRDP_GatewayHttpExtAuthBearer))
{
if (!http_request_set_auth_scheme(request, "Bearer"))
goto out;
if (!http_request_set_auth_param(
request, freerdp_settings_get_string(wst->context->settings,
FreeRDP_GatewayHttpExtAuthBearer)))
goto out;
}
s = http_request_write(wst->http, request);
out:
http_request_free(request);
if (s)
Stream_SealLength(s);
return s;
}
static BOOL wst_send_http_request(rdpWst* wst, rdpTls* tls)
{
WINPR_ASSERT(wst);
WINPR_ASSERT(tls);
wStream* s = wst_build_http_request(wst);
if (!s)
return FALSE;
const size_t sz = Stream_Length(s);
WLog_Print(wst->log, WLOG_TRACE, "header [%" PRIuz "]: %s", sz, Stream_Buffer(s));
const int status = freerdp_tls_write_all(tls, Stream_Buffer(s), sz);
Stream_Free(s, TRUE);
return (status >= 0);
}
static BOOL wst_handle_ok_or_forbidden(rdpWst* wst, HttpResponse** ppresponse, DWORD timeout,
UINT16* pStatusCode)
{
WINPR_ASSERT(wst);
WINPR_ASSERT(ppresponse);
WINPR_ASSERT(*ppresponse);
WINPR_ASSERT(pStatusCode);
/* AVD returns a 403 response with a ARRAffinity cookie set. retry with that cookie */
const char* affinity = http_response_get_setcookie(*ppresponse, "ARRAffinity");
const char* samesite = http_response_get_setcookie(*ppresponse, "ARRAffinitySameSite");
if ((affinity || samesite) &&
freerdp_settings_get_bool(wst->context->settings, FreeRDP_GatewayArmTransport))
{
WLog_Print(wst->log, WLOG_INFO, "Got ARRAffinity cookie %s", affinity);
WLog_Print(wst->log, WLOG_INFO, "Got ARRAffinitySameSite cookie %s", samesite);
if (affinity)
{
if (!http_context_set_cookie(wst->http, "ARRAffinity", affinity))
return FALSE;
}
if (samesite)
{
if (!http_context_set_cookie(wst->http, "ARRAffinitySameSite", samesite))
return FALSE;
}
http_response_free(*ppresponse);
*ppresponse = nullptr;
/* Terminate this connection and make a new one with the Loadbalancing Cookie */
const long fd = BIO_get_fd(wst->tls->bio, nullptr);
if ((fd >= 0) && (fd <= INT32_MAX))
closesocket((SOCKET)fd);
freerdp_tls_free(wst->tls);
wst->tls = freerdp_tls_new(wst->context);
if (!wst_tls_connect(wst, wst->tls, timeout))
return FALSE;
if (freerdp_settings_get_string(wst->context->settings, FreeRDP_GatewayHttpExtAuthBearer) &&
freerdp_settings_get_bool(wst->context->settings, FreeRDP_GatewayArmTransport))
{
char* urlWithAuth = nullptr;
size_t urlLen = 0;
char firstParam = (strchr(wst->gwpath, '?') != nullptr) ? '&' : '?';
const char* bearer = freerdp_settings_get_string(wst->context->settings,
FreeRDP_GatewayHttpExtAuthBearer);
const char* ua =
freerdp_settings_get_string(wst->context->settings, FreeRDP_GatewayHttpMsUserAgent);
winpr_asprintf(&urlWithAuth, &urlLen, arm_query_param, wst->gwpath, firstParam, bearer,
ua);
if (!urlWithAuth)
return FALSE;
free(wst->gwpath);
wst->gwpath = urlWithAuth;
if (!utils_str_is_empty(ua))
{
size_t ualen = 0;
char* uastr = nullptr;
winpr_asprintf(&uastr, &ualen, "%s&X-MS-User-Agent=%s", wst->gwpath, ua);
if (!uastr)
return FALSE;
free(wst->gwpath);
wst->gwpath = uastr;
}
if (!http_context_set_uri(wst->http, wst->gwpath))
return FALSE;
if (!http_context_enable_websocket_upgrade(wst->http, TRUE))
return FALSE;
}
if (!wst_send_http_request(wst, wst->tls))
return FALSE;
*ppresponse = http_response_recv(wst->tls, TRUE);
if (!*ppresponse)
return FALSE;
(void)http_response_extract_cookies(*ppresponse, wst->http);
*pStatusCode = http_response_get_status_code(*ppresponse);
}
return TRUE;
}
static BOOL wst_handle_denied(rdpWst* wst, HttpResponse** ppresponse, UINT16* pStatusCode)
{
WINPR_ASSERT(wst);
WINPR_ASSERT(ppresponse);
WINPR_ASSERT(*ppresponse);
WINPR_ASSERT(pStatusCode);
if (freerdp_settings_get_string(wst->context->settings, FreeRDP_GatewayHttpExtAuthBearer))
return FALSE;
if (!wst_auth_init(wst, wst->tls, AUTH_PKG))
return FALSE;
if (!wst_send_http_request(wst, wst->tls))
return FALSE;
http_response_free(*ppresponse);
*ppresponse = http_response_recv(wst->tls, TRUE);
if (!*ppresponse)
return FALSE;
(void)http_response_extract_cookies(*ppresponse, wst->http);
while (!credssp_auth_is_complete(wst->auth))
{
if (!wst_recv_auth_token(wst->auth, *ppresponse))
return FALSE;
if (credssp_auth_have_output_token(wst->auth))
{
if (!wst_send_http_request(wst, wst->tls))
return FALSE;
http_response_free(*ppresponse);
*ppresponse = http_response_recv(wst->tls, TRUE);
if (!*ppresponse)
return FALSE;
(void)http_response_extract_cookies(*ppresponse, wst->http);
}
}
*pStatusCode = http_response_get_status_code(*ppresponse);
return TRUE;
}
static BOOL wst_handle_http_code(rdpWst* wst, UINT16 StatusCode)
{
switch (StatusCode)
{
case HTTP_STATUS_PAYMENT_REQ:
case HTTP_STATUS_FORBIDDEN:
case HTTP_STATUS_DENIED:
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
break;
case HTTP_STATUS_MOVED:
case HTTP_STATUS_USE_PROXY:
case HTTP_STATUS_BAD_REQUEST:
case HTTP_STATUS_NOT_FOUND:
case HTTP_STATUS_GONE:
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
break;
case HTTP_STATUS_SERVER_ERROR:
case HTTP_STATUS_NOT_SUPPORTED:
case HTTP_STATUS_BAD_GATEWAY:
case HTTP_STATUS_SERVICE_UNAVAIL:
case HTTP_STATUS_VERSION_NOT_SUP:
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
break;
case HTTP_STATUS_GATEWAY_TIMEOUT:
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_ACTIVATION_TIMEOUT);
break;
default:
break;
}
char buffer[64] = WINPR_C_ARRAY_INIT;
WLog_Print(wst->log, WLOG_ERROR, "Unexpected HTTP status: %s",
freerdp_http_status_string_format(StatusCode, buffer, ARRAYSIZE(buffer)));
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_FAILED);
return FALSE;
}
BOOL wst_connect(rdpWst* wst, DWORD timeout)
{
WINPR_ASSERT(wst);
WINPR_ASSERT(wst->context);
if (!wst_tls_connect(wst, wst->tls, timeout))
{
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_FAILED);
return FALSE;
}
if (freerdp_settings_get_bool(wst->context->settings, FreeRDP_GatewayArmTransport))
{
/*
* If we are directed here from a ARM Gateway first
* we need to get a Loadbalancing Cookie (ARRAffinity)
* This is done by a plain GET request on the websocket URL
*/
if (!http_context_enable_websocket_upgrade(wst->http, FALSE))
{
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_FAILED);
return FALSE;
}
}
if (!wst_send_http_request(wst, wst->tls))
{
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_FAILED);
return FALSE;
}
HttpResponse* response = http_response_recv(wst->tls, TRUE);
if (!response)
{
freerdp_set_last_error_if_not(wst->context, FREERDP_ERROR_CONNECT_FAILED);
return FALSE;
}
(void)http_response_extract_cookies(response, wst->http);
UINT16 StatusCode = http_response_get_status_code(response);
BOOL success = TRUE;
switch (StatusCode)
{
case HTTP_STATUS_FORBIDDEN:
case HTTP_STATUS_OK:
success = wst_handle_ok_or_forbidden(wst, &response, timeout, &StatusCode);
break;
case HTTP_STATUS_DENIED:
success = wst_handle_denied(wst, &response, &StatusCode);
break;
default:
http_response_log_error_status(WLog_Get(TAG), WLOG_WARN, response);
break;
}
const BOOL isWebsocket = http_response_is_websocket(wst->http, response);
http_response_free(response);
if (!success)
return wst_handle_http_code(wst, StatusCode);
if (isWebsocket)
return websocket_context_reset(wst->wscontext);
return wst_handle_http_code(wst, StatusCode);
}
DWORD wst_get_event_handles(rdpWst* wst, HANDLE* events, DWORD count)
{
DWORD nCount = 0;
WINPR_ASSERT(wst != nullptr);
if (wst->tls)
{
if (events && (nCount < count))
{
BIO_get_event(wst->tls->bio, &events[nCount]);
nCount++;
}
else
return 0;
}
return nCount;
}
static int wst_bio_write(BIO* bio, const char* buf, int num)
{
int status = 0;
WINPR_ASSERT(bio);
WINPR_ASSERT(buf);
rdpWst* wst = (rdpWst*)BIO_get_data(bio);
WINPR_ASSERT(wst);
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
EnterCriticalSection(&wst->writeSection);
status = websocket_context_write(wst->wscontext, wst->tls->bio, (const BYTE*)buf, num,
WebsocketBinaryOpcode);
LeaveCriticalSection(&wst->writeSection);
if (status < 0)
{
BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
return -1;
}
else if (status < num)
{
BIO_set_flags(bio, BIO_FLAGS_WRITE);
WSASetLastError(WSAEWOULDBLOCK);
}
else
{
BIO_set_flags(bio, BIO_FLAGS_WRITE);
}
return status;
}
static int wst_bio_read(BIO* bio, char* buf, int size)
{
int status = 0;
WINPR_ASSERT(bio);
WINPR_ASSERT(buf);
WINPR_ASSERT(size >= 0);
rdpWst* wst = (rdpWst*)BIO_get_data(bio);
WINPR_ASSERT(wst);
while (status <= 0)
{
status = websocket_context_read(wst->wscontext, wst->tls->bio, (BYTE*)buf, (size_t)size);
if (status <= 0)
{
if (!BIO_should_retry(wst->tls->bio))
return -1;
return 0;
}
}
if (status < 0)
{
BIO_clear_retry_flags(bio);
return -1;
}
else if (status == 0)
{
BIO_set_retry_read(bio);
WSASetLastError(WSAEWOULDBLOCK);
return -1;
}
else
{
BIO_set_flags(bio, BIO_FLAGS_READ);
}
return status;
}
static int wst_bio_puts(BIO* bio, const char* str)
{
WINPR_UNUSED(bio);
WINPR_UNUSED(str);
return -2;
}
// NOLINTNEXTLINE(readability-non-const-parameter)
static int wst_bio_gets(BIO* bio, char* str, int size)
{
WINPR_UNUSED(bio);
WINPR_UNUSED(str);
WINPR_UNUSED(size);
return -2;
}
static long wst_bio_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
long status = -1;
WINPR_ASSERT(bio);
rdpWst* wst = (rdpWst*)BIO_get_data(bio);
WINPR_ASSERT(wst);
rdpTls* tls = wst->tls;
if (cmd == BIO_CTRL_FLUSH)
{
(void)BIO_flush(tls->bio);
status = 1;
}
else if (cmd == BIO_C_SET_NONBLOCK)
{
status = 1;
}
else if (cmd == BIO_C_READ_BLOCKED)
{
status = BIO_read_blocked(tls->bio);
}
else if (cmd == BIO_C_WRITE_BLOCKED)
{
status = BIO_write_blocked(tls->bio);
}
else if (cmd == BIO_C_WAIT_READ)
{
int timeout = (int)arg1;
if (BIO_read_blocked(tls->bio))
return BIO_wait_read(tls->bio, timeout);
status = 1;
}
else if (cmd == BIO_C_WAIT_WRITE)
{
int timeout = (int)arg1;
if (BIO_write_blocked(tls->bio))
status = BIO_wait_write(tls->bio, timeout);
else
status = 1;
}
else if (cmd == BIO_C_GET_EVENT || cmd == BIO_C_GET_FD)
{
status = BIO_ctrl(tls->bio, cmd, arg1, arg2);
}
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
else if (cmd == BIO_CTRL_GET_KTLS_SEND)
{
/* Even though BIO_get_ktls_send says that returning negative values is valid
* openssl internal sources are full of if(!BIO_get_ktls_send && ) stuff. This has some
* nasty sideeffects. return 0 as proper no KTLS offloading flag
*/
status = 0;
}
else if (cmd == BIO_CTRL_GET_KTLS_RECV)
{
/* Even though BIO_get_ktls_recv says that returning negative values is valid
* there is no reason to trust trust negative values are implemented right everywhere
*/
status = 0;
}
#endif
return status;
}
static int wst_bio_new(BIO* bio)
{
BIO_set_init(bio, 1);
BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
return 1;
}
static int wst_bio_free(BIO* bio)
{
WINPR_UNUSED(bio);
return 1;
}
static BIO_METHOD* BIO_s_wst(void)
{
static BIO_METHOD* bio_methods = nullptr;
if (bio_methods == nullptr)
{
if (!(bio_methods = BIO_meth_new(BIO_TYPE_TSG, "WSTransport")))
return nullptr;
BIO_meth_set_write(bio_methods, wst_bio_write);
BIO_meth_set_read(bio_methods, wst_bio_read);
BIO_meth_set_puts(bio_methods, wst_bio_puts);
BIO_meth_set_gets(bio_methods, wst_bio_gets);
BIO_meth_set_ctrl(bio_methods, wst_bio_ctrl);
BIO_meth_set_create(bio_methods, wst_bio_new);
BIO_meth_set_destroy(bio_methods, wst_bio_free);
}
return bio_methods;
}
static BOOL wst_parse_url(rdpWst* wst, const char* url)
{
const char* hostStart = nullptr;
const char* pos = nullptr;
WINPR_ASSERT(wst);
WINPR_ASSERT(url);
free(wst->gwhostname);
wst->gwhostname = nullptr;
free(wst->gwpath);
wst->gwpath = nullptr;
if (strncmp("wss://", url, 6) != 0)
{
if (strncmp("https://", url, 8) != 0)
{
WLog_Print(wst->log, WLOG_ERROR,
"Websocket URL is invalid. Only wss:// or https:// URLs are supported");
return FALSE;
}
else
hostStart = url + 8;
}
else
hostStart = url + 6;
pos = hostStart;
while (*pos != '\0' && *pos != ':' && *pos != '/')
pos++;
free(wst->gwhostname);
wst->gwhostname = nullptr;
if (pos - hostStart == 0)
return FALSE;
wst->gwhostname = strndup(hostStart, WINPR_ASSERTING_INT_CAST(size_t, (pos - hostStart)));
if (!wst->gwhostname)
return FALSE;
if (*pos == ':')
{
char port[6] = WINPR_C_ARRAY_INIT;
char* portNumberEnd = nullptr;
pos++;
const char* portStart = pos;
while (*pos != '\0' && *pos != '/')
pos++;
if (pos - portStart > 5 || pos - portStart == 0)
return FALSE;
strncpy(port, portStart, WINPR_ASSERTING_INT_CAST(size_t, (pos - portStart)));
port[pos - portStart] = '\0';
long _p = strtol(port, &portNumberEnd, 10);
if (portNumberEnd && (*portNumberEnd == '\0') && (_p > 0) && (_p <= UINT16_MAX))
wst->gwport = (uint16_t)_p;
else
return FALSE;
}
else
wst->gwport = 443;
wst->gwpath = _strdup(pos);
return (wst->gwpath != nullptr);
}
rdpWst* wst_new(rdpContext* context)
{
if (!context)
return nullptr;
rdpWst* wst = (rdpWst*)calloc(1, sizeof(rdpWst));
if (!wst)
return nullptr;
wst->log = WLog_Get(TAG);
wst->context = context;
wst->gwhostname = nullptr;
wst->gwport = 443;
wst->gwpath = nullptr;
if (!wst_parse_url(wst, context->settings->GatewayUrl))
goto wst_alloc_error;
wst->tls = freerdp_tls_new(wst->context);
if (!wst->tls)
goto wst_alloc_error;
wst->http = http_context_new();
if (!wst->http)
goto wst_alloc_error;
{
const char* useragent =
freerdp_settings_get_string(context->settings, FreeRDP_GatewayHttpUserAgent);
const char* msuseragent =
freerdp_settings_get_string(context->settings, FreeRDP_GatewayHttpMsUserAgent);
if (!http_context_set_uri(wst->http, wst->gwpath) ||
!http_context_set_accept(wst->http, "*/*") ||
!http_context_set_cache_control(wst->http, "no-cache") ||
!http_context_set_pragma(wst->http, "no-cache") ||
!http_context_set_connection(wst->http, "Keep-Alive") ||
!http_context_set_user_agent(wst->http, useragent) ||
!http_context_set_x_ms_user_agent(wst->http, msuseragent) ||
!http_context_set_host(wst->http, wst->gwhostname) ||
!http_context_enable_websocket_upgrade(wst->http, TRUE))
{
goto wst_alloc_error;
}
}
wst->frontBio = BIO_new(BIO_s_wst());
if (!wst->frontBio)
goto wst_alloc_error;
BIO_set_data(wst->frontBio, wst);
InitializeCriticalSection(&wst->writeSection);
wst->auth = credssp_auth_new(context);
if (!wst->auth)
goto wst_alloc_error;
wst->wscontext = websocket_context_new();
if (!wst->wscontext)
goto wst_alloc_error;
return wst;
wst_alloc_error:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
wst_free(wst);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
void wst_free(rdpWst* wst)
{
if (!wst)
return;
freerdp_tls_free(wst->tls);
http_context_free(wst->http);
credssp_auth_free(wst->auth);
free(wst->gwhostname);
free(wst->gwpath);
if (!wst->attached)
BIO_free_all(wst->frontBio);
DeleteCriticalSection(&wst->writeSection);
websocket_context_free(wst->wscontext);
free(wst);
}
BIO* wst_get_front_bio_and_take_ownership(rdpWst* wst)
{
if (!wst)
return nullptr;
wst->attached = TRUE;
return wst->frontBio;
}

View File

@@ -0,0 +1,50 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Websocket Transport
*
* Copyright 2023 Michael Saxl <mike@mwsys.mine.bz>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GATEWAY_WEBSOCKET_TRANSPORT_H
#define FREERDP_LIB_CORE_GATEWAY_WEBSOCKET_TRANSPORT_H
#include <winpr/wtypes.h>
#include <winpr/stream.h>
#include <winpr/winpr.h>
#include <freerdp/api.h>
#include <freerdp/types.h>
/* needed for BIO */
#include <openssl/ssl.h>
typedef struct rdp_wst rdpWst;
FREERDP_LOCAL void wst_free(rdpWst* wst);
WINPR_ATTR_MALLOC(wst_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpWst* wst_new(rdpContext* context);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BIO* wst_get_front_bio_and_take_ownership(rdpWst* wst);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL wst_connect(rdpWst* wst, DWORD timeout);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL DWORD wst_get_event_handles(rdpWst* wst, HANDLE* events, DWORD count);
#endif /* FREERDP_LIB_CORE_GATEWAY_WEBSOCKET_TRANSPORT_H */

2478
third_party/FreeRDP/libfreerdp/core/gcc.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,51 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* T.124 Generic Conference Control (GCC)
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GCC_H
#define FREERDP_LIB_CORE_GCC_H
#include "mcs.h"
#include <freerdp/crypto/per.h>
#include <freerdp/freerdp.h>
#include <freerdp/settings.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL gcc_read_conference_create_request(wStream* s, rdpMcs* mcs);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL gcc_write_conference_create_request(wStream* s, wStream* userData);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL gcc_read_conference_create_response(wStream* s, rdpMcs* mcs);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL gcc_write_conference_create_response(wStream* s, wStream* userData);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL gcc_write_client_data_blocks(wStream* s, const rdpMcs* mcs);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL gcc_write_server_data_blocks(wStream* s, rdpMcs* mcs);
#endif /* FREERDP_LIB_CORE_GCC_H */

View File

@@ -0,0 +1,221 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Graphical Objects
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <winpr/crt.h>
#include <freerdp/graphics.h>
#include "graphics.h"
/* Bitmap Class */
rdpBitmap* Bitmap_Alloc(rdpContext* context)
{
rdpBitmap* bitmap = nullptr;
rdpGraphics* graphics = nullptr;
graphics = context->graphics;
bitmap = (rdpBitmap*)calloc(1, graphics->Bitmap_Prototype->size);
if (bitmap)
{
*bitmap = *graphics->Bitmap_Prototype;
bitmap->data = nullptr;
}
return bitmap;
}
void Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
{
if (bitmap)
bitmap->Free(context, bitmap);
}
BOOL Bitmap_SetRectangle(rdpBitmap* bitmap, UINT16 left, UINT16 top, UINT16 right, UINT16 bottom)
{
if (!bitmap)
return FALSE;
bitmap->left = left;
bitmap->top = top;
bitmap->right = right;
bitmap->bottom = bottom;
return TRUE;
}
BOOL Bitmap_SetDimensions(rdpBitmap* bitmap, UINT16 width, UINT16 height)
{
if (!bitmap)
return FALSE;
bitmap->right = bitmap->left + width - 1;
bitmap->bottom = bitmap->top + height - 1;
bitmap->width = width;
bitmap->height = height;
return TRUE;
}
void graphics_register_bitmap(rdpGraphics* graphics, const rdpBitmap* bitmap)
{
WINPR_ASSERT(graphics);
WINPR_ASSERT(graphics->Bitmap_Prototype);
WINPR_ASSERT(bitmap);
*graphics->Bitmap_Prototype = *bitmap;
}
/* Pointer Class */
rdpPointer* Pointer_Alloc(rdpContext* context)
{
rdpPointer* pointer = nullptr;
rdpGraphics* graphics = nullptr;
graphics = context->graphics;
pointer = (rdpPointer*)calloc(1, graphics->Pointer_Prototype->size);
if (pointer)
{
*pointer = *graphics->Pointer_Prototype;
}
return pointer;
}
/* static method */
void graphics_register_pointer(rdpGraphics* graphics, const rdpPointer* pointer)
{
WINPR_ASSERT(graphics);
WINPR_ASSERT(graphics->Pointer_Prototype);
WINPR_ASSERT(pointer);
*graphics->Pointer_Prototype = *pointer;
}
/* Glyph Class */
rdpGlyph* Glyph_Alloc(rdpContext* context, INT32 x, INT32 y, UINT32 cx, UINT32 cy, UINT32 cb,
const BYTE* aj)
{
rdpGlyph* glyph = nullptr;
rdpGraphics* graphics = nullptr;
if (!context || !context->graphics)
return nullptr;
graphics = context->graphics;
if (!graphics->Glyph_Prototype)
return nullptr;
glyph = (rdpGlyph*)calloc(1, graphics->Glyph_Prototype->size);
if (!glyph)
return nullptr;
*glyph = *graphics->Glyph_Prototype;
glyph->cb = cb;
glyph->cx = cx;
glyph->cy = cy;
glyph->x = x;
glyph->y = y;
glyph->aj = malloc(glyph->cb);
if (!glyph->aj)
{
free(glyph);
return nullptr;
}
CopyMemory(glyph->aj, aj, cb);
if (!glyph->New(context, glyph))
{
free(glyph->aj);
free(glyph);
return nullptr;
}
return glyph;
}
void graphics_register_glyph(rdpGraphics* graphics, const rdpGlyph* glyph)
{
WINPR_ASSERT(graphics);
WINPR_ASSERT(graphics->Glyph_Prototype);
WINPR_ASSERT(glyph);
*graphics->Glyph_Prototype = *glyph;
}
/* Graphics Module */
rdpGraphics* graphics_new(rdpContext* context)
{
rdpGraphics* graphics = nullptr;
graphics = (rdpGraphics*)calloc(1, sizeof(rdpGraphics));
if (graphics)
{
graphics->context = context;
graphics->Bitmap_Prototype = (rdpBitmap*)calloc(1, sizeof(rdpBitmap));
if (!graphics->Bitmap_Prototype)
{
free(graphics);
return nullptr;
}
graphics->Bitmap_Prototype->size = sizeof(rdpBitmap);
graphics->Pointer_Prototype = (rdpPointer*)calloc(1, sizeof(rdpPointer));
if (!graphics->Pointer_Prototype)
{
free(graphics->Bitmap_Prototype);
free(graphics);
return nullptr;
}
graphics->Pointer_Prototype->size = sizeof(rdpPointer);
graphics->Glyph_Prototype = (rdpGlyph*)calloc(1, sizeof(rdpGlyph));
if (!graphics->Glyph_Prototype)
{
free(graphics->Pointer_Prototype);
free(graphics->Bitmap_Prototype);
free(graphics);
return nullptr;
}
graphics->Glyph_Prototype->size = sizeof(rdpGlyph);
}
return graphics;
}
void graphics_free(rdpGraphics* graphics)
{
if (graphics)
{
free(graphics->Bitmap_Prototype);
free(graphics->Pointer_Prototype);
free(graphics->Glyph_Prototype);
free(graphics);
}
}

View File

@@ -0,0 +1,30 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Client Channels
*
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
* Copyright 2016 Thinast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_GRAPHICS_H
#define FREERDP_LIB_CORE_GRAPHICS_H
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#include <freerdp/graphics.h>
FREERDP_LOCAL void Bitmap_Free(rdpContext* context, rdpBitmap* bitmap);
#endif /* FREERDP_LIB_CORE_GRAPHICS_H */

View File

@@ -0,0 +1,93 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Heartbeat PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include "heartbeat.h"
state_run_t rdp_recv_heartbeat_packet(rdpRdp* rdp, wStream* s)
{
BYTE period = 0;
BYTE count1 = 0;
BYTE count2 = 0;
BOOL rc = 0;
WINPR_ASSERT(rdp);
WINPR_ASSERT(rdp->context);
WINPR_ASSERT(s);
if (!Stream_CheckAndLogRequiredLength(AUTODETECT_TAG, s, 4))
return STATE_RUN_FAILED;
Stream_Seek_UINT8(s); /* reserved (1 byte) */
Stream_Read_UINT8(s, period); /* period (1 byte) */
Stream_Read_UINT8(s, count1); /* count1 (1 byte) */
Stream_Read_UINT8(s, count2); /* count2 (1 byte) */
WLog_VRB(HEARTBEAT_TAG,
"received Heartbeat PDU -> period=%" PRIu8 ", count1=%" PRIu8 ", count2=%" PRIu8 "",
period, count1, count2);
rc = IFCALLRESULT(TRUE, rdp->heartbeat->ServerHeartbeat, rdp->context->instance, period, count1,
count2);
if (!rc)
{
WLog_ERR(HEARTBEAT_TAG, "heartbeat->ServerHeartbeat callback failed!");
return STATE_RUN_FAILED;
}
return STATE_RUN_SUCCESS;
}
BOOL freerdp_heartbeat_send_heartbeat_pdu(freerdp_peer* peer, BYTE period, BYTE count1, BYTE count2)
{
rdpRdp* rdp = peer->context->rdp;
UINT16 sec_flags = 0;
wStream* s = rdp_message_channel_pdu_init(rdp, &sec_flags);
if (!s)
return FALSE;
Stream_Seek_UINT8(s); /* reserved (1 byte) */
Stream_Write_UINT8(s, period); /* period (1 byte) */
Stream_Write_UINT8(s, count1); /* count1 (1 byte) */
Stream_Write_UINT8(s, count2); /* count2 (1 byte) */
WLog_DBG(HEARTBEAT_TAG,
"sending Heartbeat PDU -> period=%" PRIu8 ", count1=%" PRIu8 ", count2=%" PRIu8 "",
period, count1, count2);
return (rdp_send_message_channel_pdu(rdp, s, sec_flags | SEC_HEARTBEAT));
}
rdpHeartbeat* heartbeat_new(void)
{
rdpHeartbeat* heartbeat = (rdpHeartbeat*)calloc(1, sizeof(rdpHeartbeat));
if (heartbeat)
{
}
return heartbeat;
}
void heartbeat_free(rdpHeartbeat* heartbeat)
{
free(heartbeat);
}

View File

@@ -0,0 +1,45 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Heartbeat PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_HEARTBEET_H
#define FREERDP_LIB_CORE_HEARTBEET_H
#include "rdp.h"
#include <freerdp/heartbeat.h>
#include <freerdp/freerdp.h>
#include <freerdp/log.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
#include "state.h"
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_recv_heartbeat_packet(rdpRdp* rdp, wStream* s);
FREERDP_LOCAL void heartbeat_free(rdpHeartbeat* heartbeat);
WINPR_ATTR_MALLOC(heartbeat_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpHeartbeat* heartbeat_new(void);
#define HEARTBEAT_TAG FREERDP_TAG("core.heartbeat")
#endif /* FREERDP_LIB_CORE_HEARTBEET_H */

1602
third_party/FreeRDP/libfreerdp/core/info.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Client Info
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_INFO_H
#define FREERDP_LIB_CORE_INFO_H
#include "rdp.h"
#include <freerdp/freerdp.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
/* Client Address Family */
#define ADDRESS_FAMILY_INET 0x0002
#define ADDRESS_FAMILY_INET6 0x0017
/* Client Info Packet Flags */
#define INFO_MOUSE 0x00000001
#define INFO_DISABLECTRLALTDEL 0x00000002
#define INFO_AUTOLOGON 0x00000008
#define INFO_UNICODE 0x00000010
#define INFO_MAXIMIZESHELL 0x00000020
#define INFO_LOGONNOTIFY 0x00000040
#define INFO_COMPRESSION 0x00000080
#define INFO_ENABLEWINDOWSKEY 0x00000100
#define INFO_REMOTECONSOLEAUDIO 0x00002000
#define INFO_FORCE_ENCRYPTED_CS_PDU 0x00004000
#define INFO_RAIL 0x00008000
#define INFO_LOGONERRORS 0x00010000
#define INFO_MOUSE_HAS_WHEEL 0x00020000
#define INFO_PASSWORD_IS_SC_PIN 0x00040000
#define INFO_NOAUDIOPLAYBACK 0x00080000
#define INFO_USING_SAVED_CREDS 0x00100000
#define INFO_AUDIOCAPTURE 0x00200000
#define INFO_VIDEO_DISABLE 0x00400000
#define INFO_HIDEF_RAIL_SUPPORTED 0x02000000
/* Extended Logon Info */
#define LOGON_EX_AUTORECONNECTCOOKIE 0x00000001
#define LOGON_EX_LOGONERRORS 0x00000002
#define SAVE_SESSION_PDU_VERSION_ONE 0x0001
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_client_info(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_save_session_info(rdpContext* context, UINT32 type, void* data);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_server_status_info(rdpContext* context, UINT32 status);
#endif /* FREERDP_LIB_CORE_INFO_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Input PDUs
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_INPUT_H
#define FREERDP_LIB_CORE_INPUT_H
#include "rdp.h"
#include "fastpath.h"
#include "message.h"
#include <freerdp/input.h>
#include <freerdp/freerdp.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
typedef struct
{
rdpInput common;
/* Internal */
rdpInputProxy* proxy;
wMessageQueue* queue;
UINT64 lastInputTimestamp;
UINT16 lastX;
UINT16 lastY;
wLog* log;
} rdp_input_internal;
WINPR_ATTR_NODISCARD
static inline rdp_input_internal* input_cast(rdpInput* input)
{
union
{
rdpInput* pub;
rdp_input_internal* internal;
} cnv;
WINPR_ASSERT(input);
cnv.pub = input;
return cnv.internal;
}
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL input_recv(rdpInput* input, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int input_process_events(rdpInput* input);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL input_register_client_callbacks(rdpInput* input);
FREERDP_LOCAL void input_free(rdpInput* input);
WINPR_ATTR_MALLOC(input_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpInput* input_new(rdpRdp* rdp);
#endif /* FREERDP_LIB_CORE_INPUT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Licensing
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2022 Armin Novak <armin.novak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_LICENSE_H
#define FREERDP_LIB_CORE_LICENSE_H
#include "rdp.h"
#include "state.h"
#include <freerdp/crypto/crypto.h>
#include <freerdp/log.h>
#include <freerdp/license.h>
#include <winpr/stream.h>
#define CLIENT_RANDOM_LENGTH 32
typedef struct
{
UINT32 dwVersion;
UINT32 cbCompanyName;
BYTE* pbCompanyName;
UINT32 cbProductId;
BYTE* pbProductId;
} LICENSE_PRODUCT_INFO;
typedef struct
{
UINT16 type;
UINT16 length;
BYTE* data;
} LICENSE_BLOB;
typedef struct
{
UINT32 count;
LICENSE_BLOB** array;
} SCOPE_LIST;
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL license_send_valid_client_error_packet(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t license_recv(rdpLicense* license, wStream* s);
/* the configuration is applied from settings. Set FreeRDP_ServerLicense* settings */
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL license_server_configure(rdpLicense* license);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL license_server_send_request(rdpLicense* license);
FREERDP_LOCAL void license_free(rdpLicense* license);
WINPR_ATTR_MALLOC(license_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpLicense* license_new(rdpRdp* rdp);
#define LICENSE_TAG FREERDP_TAG("core.license")
#ifdef WITH_DEBUG_LICENSE
#define DEBUG_LICENSE(...) WLog_INFO(LICENSE_TAG, __VA_ARGS__)
#else
#define DEBUG_LICENSE(...) \
do \
{ \
} while (0)
#endif
#endif /* FREERDP_LIB_CORE_LICENSE_H */

View File

@@ -0,0 +1,559 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Server Listener
*
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <winpr/crt.h>
#include <winpr/windows.h>
#include <freerdp/log.h>
#ifndef _WIN32
#include <netdb.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
#endif
#if defined(HAVE_AF_VSOCK_H)
#include <ctype.h>
#include <linux/vm_sockets.h>
#endif
#include <winpr/handle.h>
#include "listener.h"
#include "utils.h"
#define TAG FREERDP_TAG("core.listener")
static BOOL freerdp_listener_open_from_vsock(WINPR_ATTR_UNUSED freerdp_listener* instance,
WINPR_ATTR_UNUSED const char* bind_address,
WINPR_ATTR_UNUSED UINT16 port)
{
#if defined(HAVE_AF_VSOCK_H)
rdpListener* listener = (rdpListener*)instance->listener;
const int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
if (sockfd == -1)
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
WLog_ERR(TAG, "Error creating socket: %s", winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
return FALSE;
}
const int flags = fcntl(sockfd, F_GETFL, 0);
if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
WLog_ERR(TAG, "Error making socket nonblocking: %s",
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
close(sockfd);
return FALSE;
}
struct sockaddr_vm addr = WINPR_C_ARRAY_INIT;
addr.svm_family = AF_VSOCK;
addr.svm_port = port;
errno = 0;
char* ptr = nullptr;
unsigned long val = strtoul(bind_address, &ptr, 10);
if (errno || (val > UINT32_MAX))
{
/* handle VMADDR_CID_ANY (-1U) */
if ((val == ULONG_MAX) && (errno == 0))
val = UINT32_MAX;
else
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
WLog_ERR(TAG, "could not extract port from '%s', value=%lu, error=%s", bind_address,
val, winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
close(sockfd);
return FALSE;
}
}
addr.svm_cid = WINPR_ASSERTING_INT_CAST(unsigned int, val);
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm)) == -1)
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
WLog_ERR(TAG, "Error binding vsock at cid %u port %d: %s", addr.svm_cid, port,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
close(sockfd);
return FALSE;
}
if (listen(sockfd, 10) == -1)
{
char ebuffer[256] = WINPR_C_ARRAY_INIT;
WLog_ERR(TAG, "Error listening to socket at cid %u port %d: %s", addr.svm_cid, port,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
close(sockfd);
return FALSE;
}
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = WSACreateEvent();
if (!listener->events[listener->num_sockfds])
{
listener->num_sockfds = 0;
}
WSAEventSelect((SOCKET)sockfd, listener->events[listener->num_sockfds],
FD_READ | FD_ACCEPT | FD_CLOSE);
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on %s:%d", bind_address, port);
return TRUE;
#else
WLog_ERR(TAG, "compiled without AF_VSOCK, '%s' not supported", bind_address);
return FALSE;
#endif
}
static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_address, UINT16 port)
{
int ai_flags = 0;
int status = 0;
int sockfd = 0;
char addr[64];
void* sin_addr = nullptr;
int option_value = 0;
struct addrinfo* res = nullptr;
rdpListener* listener = (rdpListener*)instance->listener;
#ifdef _WIN32
u_long arg;
#endif
if (!bind_address)
ai_flags = AI_PASSIVE;
if (utils_is_vsock(bind_address))
{
bind_address = utils_is_vsock(bind_address);
return freerdp_listener_open_from_vsock(instance, bind_address, port);
}
res = freerdp_tcp_resolve_host(bind_address, port, ai_flags);
if (!res)
return FALSE;
for (struct addrinfo* ai = res; ai && (listener->num_sockfds < 5); ai = ai->ai_next)
{
if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6))
continue;
if (listener->num_sockfds == MAX_LISTENER_HANDLES)
{
WLog_ERR(TAG, "too many listening sockets");
continue;
}
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sockfd == -1)
{
WLog_ERR(TAG, "socket");
continue;
}
option_value = 1;
if (ai->ai_family == AF_INET)
sin_addr = &(((struct sockaddr_in*)ai->ai_addr)->sin_addr);
else
{
sin_addr = &(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr);
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&option_value,
sizeof(option_value)) == -1)
WLog_ERR(TAG, "setsockopt");
}
inet_ntop(ai->ai_family, sin_addr, addr, sizeof(addr));
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value,
sizeof(option_value)) == -1)
WLog_ERR(TAG, "setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR)");
#ifndef _WIN32
if (fcntl(sockfd, F_SETFL, O_NONBLOCK) != 0)
WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
#else
arg = 1;
ioctlsocket(sockfd, FIONBIO, &arg);
#endif
status = _bind((SOCKET)sockfd, ai->ai_addr, WINPR_ASSERTING_INT_CAST(int, ai->ai_addrlen));
if (status != 0)
{
closesocket((SOCKET)sockfd);
continue;
}
status = _listen((SOCKET)sockfd, 10);
if (status != 0)
{
WLog_ERR(TAG, "listen");
closesocket((SOCKET)sockfd);
continue;
}
/* FIXME: these file descriptors do not work on Windows */
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = WSACreateEvent();
if (!listener->events[listener->num_sockfds])
{
listener->num_sockfds = 0;
break;
}
WSAEventSelect((SOCKET)sockfd, listener->events[listener->num_sockfds],
FD_READ | FD_ACCEPT | FD_CLOSE);
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on [%s]:%" PRIu16, addr, port);
}
freeaddrinfo(res);
return ((listener->num_sockfds > 0));
}
static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* path)
{
#ifndef _WIN32
int status = 0;
int sockfd = 0;
struct sockaddr_un addr = WINPR_C_ARRAY_INIT;
rdpListener* listener = (rdpListener*)instance->listener;
HANDLE hevent = nullptr;
if (listener->num_sockfds == MAX_LISTENER_HANDLES)
{
WLog_ERR(TAG, "too many listening sockets");
return FALSE;
}
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd == -1)
{
WLog_ERR(TAG, "socket");
return FALSE;
}
int rc = fcntl(sockfd, F_SETFL, O_NONBLOCK);
if (rc != 0)
{
WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
closesocket((SOCKET)sockfd);
return FALSE;
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
unlink(path);
status = _bind((SOCKET)sockfd, (struct sockaddr*)&addr, sizeof(addr));
if (status != 0)
{
WLog_ERR(TAG, "bind");
closesocket((SOCKET)sockfd);
return FALSE;
}
status = _listen((SOCKET)sockfd, 10);
if (status != 0)
{
WLog_ERR(TAG, "listen");
closesocket((SOCKET)sockfd);
return FALSE;
}
hevent = CreateFileDescriptorEvent(nullptr, FALSE, FALSE, sockfd, WINPR_FD_READ);
if (!hevent)
{
WLog_ERR(TAG, "failed to create sockfd event");
closesocket((SOCKET)sockfd);
return FALSE;
}
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = hevent;
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path);
return TRUE;
#else
return TRUE;
#endif
}
static BOOL freerdp_listener_open_from_socket(freerdp_listener* instance, int fd)
{
#ifndef _WIN32
rdpListener* listener = (rdpListener*)instance->listener;
if (listener->num_sockfds == MAX_LISTENER_HANDLES)
{
WLog_ERR(TAG, "too many listening sockets");
return FALSE;
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
return FALSE;
listener->sockfds[listener->num_sockfds] = fd;
listener->events[listener->num_sockfds] = WSACreateEvent();
if (!listener->events[listener->num_sockfds])
return FALSE;
WSAEventSelect((SOCKET)fd, listener->events[listener->num_sockfds],
FD_READ | FD_ACCEPT | FD_CLOSE);
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on socket %d.", fd);
return TRUE;
#else
return FALSE;
#endif
}
static void freerdp_listener_close(freerdp_listener* instance)
{
rdpListener* listener = (rdpListener*)instance->listener;
for (int i = 0; i < listener->num_sockfds; i++)
{
closesocket((SOCKET)listener->sockfds[i]);
(void)CloseHandle(listener->events[i]);
}
listener->num_sockfds = 0;
}
#if defined(WITH_FREERDP_DEPRECATED)
static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
{
rdpListener* listener = (rdpListener*)instance->listener;
if (listener->num_sockfds < 1)
return FALSE;
for (int index = 0; index < listener->num_sockfds; index++)
{
rfds[*rcount] = (void*)(long)(listener->sockfds[index]);
(*rcount)++;
}
return TRUE;
}
#endif
static DWORD freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events,
DWORD nCount)
{
rdpListener* listener = (rdpListener*)instance->listener;
if (listener->num_sockfds < 1)
return 0;
if (listener->num_sockfds > (INT64)nCount)
return 0;
for (int index = 0; index < listener->num_sockfds; index++)
{
events[index] = listener->events[index];
}
return WINPR_ASSERTING_INT_CAST(uint32_t, listener->num_sockfds);
}
BOOL freerdp_peer_set_local_and_hostname(freerdp_peer* client,
const struct sockaddr_storage* peer_addr)
{
const void* sin_addr = nullptr;
const BYTE localhost6_bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
WINPR_ASSERT(client);
WINPR_ASSERT(peer_addr);
if (peer_addr->ss_family == AF_INET)
{
const UINT32* usin_addr = sin_addr = &(((const struct sockaddr_in*)peer_addr)->sin_addr);
if ((*usin_addr) == 0x0100007f)
client->local = TRUE;
}
else if (peer_addr->ss_family == AF_INET6)
{
const struct sockaddr_in6* usin_addr = sin_addr =
&(((const struct sockaddr_in6*)peer_addr)->sin6_addr);
if (memcmp(usin_addr, localhost6_bytes, 16) == 0)
client->local = TRUE;
}
#ifndef _WIN32
#if defined(HAVE_AF_VSOCK_H)
else if (peer_addr->ss_family == AF_UNIX || peer_addr->ss_family == AF_VSOCK)
#else
else if (peer_addr->ss_family == AF_UNIX)
#endif
client->local = TRUE;
#endif
if (client->local)
WLog_INFO(TAG, "Accepting client from localhost");
if (sin_addr)
inet_ntop(peer_addr->ss_family, sin_addr, client->hostname, sizeof(client->hostname));
return TRUE;
}
static BOOL freerdp_check_and_create_client(freerdp_listener* instance, int peer_sockfd,
const struct sockaddr_storage* peer_addr)
{
WINPR_ASSERT(instance);
WINPR_ASSERT(peer_sockfd >= 0);
WINPR_ASSERT(peer_addr);
const BOOL check = IFCALLRESULT(TRUE, instance->CheckPeerAcceptRestrictions, instance);
if (!check)
{
closesocket((SOCKET)peer_sockfd);
return TRUE;
}
freerdp_peer* client = freerdp_peer_new(peer_sockfd);
if (!client)
{
closesocket((SOCKET)peer_sockfd);
return FALSE;
}
if (!freerdp_peer_set_local_and_hostname(client, peer_addr))
{
freerdp_peer_free(client);
return FALSE;
}
const BOOL peer_accepted = IFCALLRESULT(FALSE, instance->PeerAccepted, instance, client);
if (!peer_accepted)
{
WLog_ERR(TAG, "PeerAccepted callback failed");
freerdp_peer_free(client);
}
return TRUE;
}
static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
{
rdpListener* listener = (rdpListener*)instance->listener;
if (listener->num_sockfds < 1)
return FALSE;
for (int i = 0; i < listener->num_sockfds; i++)
{
struct sockaddr_storage peer_addr = WINPR_C_ARRAY_INIT;
(void)WSAResetEvent(listener->events[i]);
int peer_addr_size = sizeof(peer_addr);
SOCKET peer_sockfd =
_accept((SOCKET)listener->sockfds[i], (struct sockaddr*)&peer_addr, &peer_addr_size);
if (peer_sockfd == (SOCKET)-1)
{
char buffer[128] = WINPR_C_ARRAY_INIT;
#ifdef _WIN32
int wsa_error = WSAGetLastError();
/* No data available */
if (wsa_error == WSAEWOULDBLOCK)
continue;
#else
if (errno == EAGAIN || errno == EWOULDBLOCK)
continue;
#endif
WLog_WARN(TAG, "accept failed with %s", winpr_strerror(errno, buffer, sizeof(buffer)));
return FALSE;
}
if (!freerdp_check_and_create_client(instance, (int)peer_sockfd, &peer_addr))
return FALSE;
}
return TRUE;
}
freerdp_listener* freerdp_listener_new(void)
{
freerdp_listener* instance = nullptr;
rdpListener* listener = nullptr;
instance = (freerdp_listener*)calloc(1, sizeof(freerdp_listener));
if (!instance)
return nullptr;
instance->Open = freerdp_listener_open;
instance->OpenLocal = freerdp_listener_open_local;
instance->OpenFromSocket = freerdp_listener_open_from_socket;
#if defined(WITH_FREERDP_DEPRECATED)
instance->GetFileDescriptor = freerdp_listener_get_fds;
#endif
instance->GetEventHandles = freerdp_listener_get_event_handles;
instance->CheckFileDescriptor = freerdp_listener_check_fds;
instance->Close = freerdp_listener_close;
listener = (rdpListener*)calloc(1, sizeof(rdpListener));
if (!listener)
{
free(instance);
return nullptr;
}
listener->instance = instance;
instance->listener = (void*)listener;
return instance;
}
void freerdp_listener_free(freerdp_listener* instance)
{
if (instance)
{
free(instance->listener);
free(instance);
}
}

View File

@@ -0,0 +1,43 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Server Listener
*
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_LISTENER_H
#define FREERDP_LIB_CORE_LISTENER_H
typedef struct rdp_listener rdpListener;
#include "rdp.h"
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <freerdp/listener.h>
#define MAX_LISTENER_HANDLES 5
struct rdp_listener
{
freerdp_listener* instance;
int num_sockfds;
int sockfds[MAX_LISTENER_HANDLES];
HANDLE events[MAX_LISTENER_HANDLES];
};
#endif /* FREERDP_LIB_CORE_LISTENER_H */

1543
third_party/FreeRDP/libfreerdp/core/mcs.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,224 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* T.125 Multipoint Communication Service (MCS) Protocol
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_MCS_H
#define FREERDP_LIB_CORE_MCS_H
typedef struct rdp_mcs rdpMcs;
#include "transport.h"
#include <freerdp/crypto/ber.h>
#include <freerdp/api.h>
#include <freerdp/types.h>
#include <winpr/stream.h>
#include <winpr/wtsapi.h>
enum MCS_Result
{
MCS_Result_successful = 0,
MCS_Result_domain_merging = 1,
MCS_Result_domain_not_hierarchical = 2,
MCS_Result_no_such_channel = 3,
MCS_Result_no_such_domain = 4,
MCS_Result_no_such_user = 5,
MCS_Result_not_admitted = 6,
MCS_Result_other_user_id = 7,
MCS_Result_parameters_unacceptable = 8,
MCS_Result_token_not_available = 9,
MCS_Result_token_not_possessed = 10,
MCS_Result_too_many_channels = 11,
MCS_Result_too_many_tokens = 12,
MCS_Result_too_many_users = 13,
MCS_Result_unspecified_failure = 14,
MCS_Result_user_rejected = 15,
MCS_Result_enum_length = 16
};
typedef enum
{
DomainMCSPDU_invalid = -1,
DomainMCSPDU_PlumbDomainIndication = 0,
DomainMCSPDU_ErectDomainRequest = 1,
DomainMCSPDU_MergeChannelsRequest = 2,
DomainMCSPDU_MergeChannelsConfirm = 3,
DomainMCSPDU_PurgeChannelsIndication = 4,
DomainMCSPDU_MergeTokensRequest = 5,
DomainMCSPDU_MergeTokensConfirm = 6,
DomainMCSPDU_PurgeTokensIndication = 7,
DomainMCSPDU_DisconnectProviderUltimatum = 8,
DomainMCSPDU_RejectMCSPDUUltimatum = 9,
DomainMCSPDU_AttachUserRequest = 10,
DomainMCSPDU_AttachUserConfirm = 11,
DomainMCSPDU_DetachUserRequest = 12,
DomainMCSPDU_DetachUserIndication = 13,
DomainMCSPDU_ChannelJoinRequest = 14,
DomainMCSPDU_ChannelJoinConfirm = 15,
DomainMCSPDU_ChannelLeaveRequest = 16,
DomainMCSPDU_ChannelConveneRequest = 17,
DomainMCSPDU_ChannelConveneConfirm = 18,
DomainMCSPDU_ChannelDisbandRequest = 19,
DomainMCSPDU_ChannelDisbandIndication = 20,
DomainMCSPDU_ChannelAdmitRequest = 21,
DomainMCSPDU_ChannelAdmitIndication = 22,
DomainMCSPDU_ChannelExpelRequest = 23,
DomainMCSPDU_ChannelExpelIndication = 24,
DomainMCSPDU_SendDataRequest = 25,
DomainMCSPDU_SendDataIndication = 26,
DomainMCSPDU_UniformSendDataRequest = 27,
DomainMCSPDU_UniformSendDataIndication = 28,
DomainMCSPDU_TokenGrabRequest = 29,
DomainMCSPDU_TokenGrabConfirm = 30,
DomainMCSPDU_TokenInhibitRequest = 31,
DomainMCSPDU_TokenInhibitConfirm = 32,
DomainMCSPDU_TokenGiveRequest = 33,
DomainMCSPDU_TokenGiveIndication = 34,
DomainMCSPDU_TokenGiveResponse = 35,
DomainMCSPDU_TokenGiveConfirm = 36,
DomainMCSPDU_TokenPleaseRequest = 37,
DomainMCSPDU_TokenPleaseConfirm = 38,
DomainMCSPDU_TokenReleaseRequest = 39,
DomainMCSPDU_TokenReleaseConfirm = 40,
DomainMCSPDU_TokenTestRequest = 41,
DomainMCSPDU_TokenTestConfirm = 42,
DomainMCSPDU_enum_length = 43
} DomainMCSPDU;
typedef struct
{
UINT32 maxChannelIds;
UINT32 maxUserIds;
UINT32 maxTokenIds;
UINT32 numPriorities;
UINT32 minThroughput;
UINT32 maxHeight;
UINT32 maxMCSPDUsize;
UINT32 protocolVersion;
} DomainParameters;
struct rdp_mcs_channel
{
char Name[CHANNEL_NAME_LEN + 1];
UINT32 options;
UINT16 ChannelId;
BOOL joined;
void* handle;
};
typedef struct rdp_mcs_channel rdpMcsChannel;
struct rdp_mcs
{
rdpContext* context;
UINT16 userId;
UINT16 baseChannelId;
UINT16 IOChannelId;
UINT16 messageChannelId;
UINT32 flags;
DomainParameters domainParameters;
DomainParameters targetParameters;
DomainParameters minimumParameters;
DomainParameters maximumParameters;
BOOL userChannelJoined;
BOOL globalChannelJoined;
BOOL messageChannelJoined;
UINT32 channelCount;
UINT32 channelMaxCount;
rdpMcsChannel* channels;
wLog* log;
};
#define MCS_SEND_DATA_HEADER_MAX_LENGTH 8
#define MCS_TYPE_CONNECT_INITIAL 0x65
#define MCS_TYPE_CONNECT_RESPONSE 0x66
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* mcs_domain_pdu_string(DomainMCSPDU pdu);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_server_apply_to_settings(const rdpMcs* mcs, rdpSettings* settings);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_recv_connect_initial(rdpMcs* mcs, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_send_connect_response(rdpMcs* mcs);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_recv_erect_domain_request(rdpMcs* mcs, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_send_erect_domain_request(rdpMcs* mcs);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_recv_attach_user_request(rdpMcs* mcs, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_send_attach_user_request(rdpMcs* mcs);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_recv_attach_user_confirm(rdpMcs* mcs, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_send_attach_user_confirm(rdpMcs* mcs);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_recv_channel_join_request(rdpMcs* mcs, const rdpSettings* settings,
wStream* s, UINT16* channelId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_send_channel_join_request(rdpMcs* mcs, UINT16 channelId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_recv_channel_join_confirm(rdpMcs* mcs, wStream* s, UINT16* channelId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_send_channel_join_confirm(rdpMcs* mcs, UINT16 channelId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_recv_disconnect_provider_ultimatum(rdpMcs* mcs, wStream* s, int* reason);
FREERDP_LOCAL BOOL mcs_send_disconnect_provider_ultimatum(rdpMcs* mcs,
enum Disconnect_Ultimatum reason);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_write_domain_mcspdu_header(wStream* s, DomainMCSPDU domainMCSPDU,
UINT16 length, BYTE options);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL mcs_client_begin(rdpMcs* mcs);
FREERDP_LOCAL void mcs_free(rdpMcs* mcs);
WINPR_ATTR_MALLOC(mcs_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpMcs* mcs_new(rdpContext* context);
#endif /* FREERDP_LIB_CORE_MCS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,170 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Asynchronous Message Queue
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_MESSAGE_H
#define FREERDP_LIB_CORE_MESSAGE_H
#include <freerdp/freerdp.h>
#include <freerdp/message.h>
#include <freerdp/api.h>
/**
* Update Message Queue
*/
/* Update Proxy Interface */
struct rdp_update_proxy
{
rdpUpdate* update;
/* Update */
WINPR_ATTR_NODISCARD pBeginPaint BeginPaint;
WINPR_ATTR_NODISCARD pEndPaint EndPaint;
WINPR_ATTR_NODISCARD pSetBounds SetBounds;
WINPR_ATTR_NODISCARD pSynchronize Synchronize;
WINPR_ATTR_NODISCARD pDesktopResize DesktopResize;
WINPR_ATTR_NODISCARD pBitmapUpdate BitmapUpdate;
WINPR_ATTR_NODISCARD pPalette Palette;
WINPR_ATTR_NODISCARD pPlaySound PlaySound;
WINPR_ATTR_NODISCARD pSetKeyboardIndicators SetKeyboardIndicators;
WINPR_ATTR_NODISCARD pSetKeyboardImeStatus SetKeyboardImeStatus;
WINPR_ATTR_NODISCARD pRefreshRect RefreshRect;
WINPR_ATTR_NODISCARD pSuppressOutput SuppressOutput;
WINPR_ATTR_NODISCARD pSurfaceCommand SurfaceCommand;
WINPR_ATTR_NODISCARD pSurfaceBits SurfaceBits;
WINPR_ATTR_NODISCARD pSurfaceFrameMarker SurfaceFrameMarker;
WINPR_ATTR_NODISCARD pSurfaceFrameAcknowledge SurfaceFrameAcknowledge;
/* Primary Update */
WINPR_ATTR_NODISCARD pDstBlt DstBlt;
WINPR_ATTR_NODISCARD pPatBlt PatBlt;
WINPR_ATTR_NODISCARD pScrBlt ScrBlt;
WINPR_ATTR_NODISCARD pOpaqueRect OpaqueRect;
WINPR_ATTR_NODISCARD pDrawNineGrid DrawNineGrid;
WINPR_ATTR_NODISCARD pMultiDstBlt MultiDstBlt;
WINPR_ATTR_NODISCARD pMultiPatBlt MultiPatBlt;
WINPR_ATTR_NODISCARD pMultiScrBlt MultiScrBlt;
WINPR_ATTR_NODISCARD pMultiOpaqueRect MultiOpaqueRect;
WINPR_ATTR_NODISCARD pMultiDrawNineGrid MultiDrawNineGrid;
WINPR_ATTR_NODISCARD pLineTo LineTo;
WINPR_ATTR_NODISCARD pPolyline Polyline;
WINPR_ATTR_NODISCARD pMemBlt MemBlt;
WINPR_ATTR_NODISCARD pMem3Blt Mem3Blt;
WINPR_ATTR_NODISCARD pSaveBitmap SaveBitmap;
WINPR_ATTR_NODISCARD pGlyphIndex GlyphIndex;
WINPR_ATTR_NODISCARD pFastIndex FastIndex;
WINPR_ATTR_NODISCARD pFastGlyph FastGlyph;
WINPR_ATTR_NODISCARD pPolygonSC PolygonSC;
WINPR_ATTR_NODISCARD pPolygonCB PolygonCB;
WINPR_ATTR_NODISCARD pEllipseSC EllipseSC;
WINPR_ATTR_NODISCARD pEllipseCB EllipseCB;
/* Secondary Update */
WINPR_ATTR_NODISCARD pCacheBitmap CacheBitmap;
WINPR_ATTR_NODISCARD pCacheBitmapV2 CacheBitmapV2;
WINPR_ATTR_NODISCARD pCacheBitmapV3 CacheBitmapV3;
WINPR_ATTR_NODISCARD pCacheColorTable CacheColorTable;
WINPR_ATTR_NODISCARD pCacheGlyph CacheGlyph;
WINPR_ATTR_NODISCARD pCacheGlyphV2 CacheGlyphV2;
WINPR_ATTR_NODISCARD pCacheBrush CacheBrush;
/* Alternate Secondary Update */
WINPR_ATTR_NODISCARD pCreateOffscreenBitmap CreateOffscreenBitmap;
WINPR_ATTR_NODISCARD pSwitchSurface SwitchSurface;
WINPR_ATTR_NODISCARD pCreateNineGridBitmap CreateNineGridBitmap;
WINPR_ATTR_NODISCARD pFrameMarker FrameMarker;
WINPR_ATTR_NODISCARD pStreamBitmapFirst StreamBitmapFirst;
WINPR_ATTR_NODISCARD pStreamBitmapNext StreamBitmapNext;
WINPR_ATTR_NODISCARD pDrawGdiPlusFirst DrawGdiPlusFirst;
WINPR_ATTR_NODISCARD pDrawGdiPlusNext DrawGdiPlusNext;
WINPR_ATTR_NODISCARD pDrawGdiPlusEnd DrawGdiPlusEnd;
WINPR_ATTR_NODISCARD pDrawGdiPlusCacheFirst DrawGdiPlusCacheFirst;
WINPR_ATTR_NODISCARD pDrawGdiPlusCacheNext DrawGdiPlusCacheNext;
WINPR_ATTR_NODISCARD pDrawGdiPlusCacheEnd DrawGdiPlusCacheEnd;
/* Window Update */
WINPR_ATTR_NODISCARD pWindowCreate WindowCreate;
WINPR_ATTR_NODISCARD pWindowUpdate WindowUpdate;
WINPR_ATTR_NODISCARD pWindowIcon WindowIcon;
WINPR_ATTR_NODISCARD pWindowCachedIcon WindowCachedIcon;
WINPR_ATTR_NODISCARD pWindowDelete WindowDelete;
WINPR_ATTR_NODISCARD pNotifyIconCreate NotifyIconCreate;
WINPR_ATTR_NODISCARD pNotifyIconUpdate NotifyIconUpdate;
WINPR_ATTR_NODISCARD pNotifyIconDelete NotifyIconDelete;
WINPR_ATTR_NODISCARD pMonitoredDesktop MonitoredDesktop;
WINPR_ATTR_NODISCARD pNonMonitoredDesktop NonMonitoredDesktop;
/* Pointer Update */
WINPR_ATTR_NODISCARD pPointerPosition PointerPosition;
WINPR_ATTR_NODISCARD pPointerSystem PointerSystem;
WINPR_ATTR_NODISCARD pPointerColor PointerColor;
WINPR_ATTR_NODISCARD pPointerNew PointerNew;
WINPR_ATTR_NODISCARD pPointerCached PointerCached;
WINPR_ATTR_NODISCARD pPointerLarge PointerLarge;
HANDLE thread;
};
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int update_message_queue_process_message(rdpUpdate* update, wMessage* message);
FREERDP_LOCAL int update_message_queue_free_message(wMessage* message);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int update_message_queue_process_pending_messages(rdpUpdate* update);
FREERDP_LOCAL void update_message_proxy_free(rdpUpdateProxy* message);
WINPR_ATTR_MALLOC(update_message_proxy_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpUpdateProxy* update_message_proxy_new(rdpUpdate* update);
/**
* Input Message Queue
*/
/* Input Proxy Interface */
struct rdp_input_proxy
{
rdpInput* input;
/* Input */
pSynchronizeEvent SynchronizeEvent;
pKeyboardEvent KeyboardEvent;
pUnicodeKeyboardEvent UnicodeKeyboardEvent;
pMouseEvent MouseEvent;
pExtendedMouseEvent ExtendedMouseEvent;
pFocusInEvent FocusInEvent;
pKeyboardPauseEvent KeyboardPauseEvent;
};
FREERDP_LOCAL int input_message_queue_process_message(rdpInput* input, wMessage* message);
FREERDP_LOCAL int input_message_queue_free_message(wMessage* message);
FREERDP_LOCAL int input_message_queue_process_pending_messages(rdpInput* input);
#endif /* FREERDP_LIB_CORE_MESSAGE_H */

View File

@@ -0,0 +1,57 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Protocol Metrics
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include "rdp.h"
double metrics_write_bytes(rdpMetrics* metrics, UINT32 UncompressedBytes, UINT32 CompressedBytes)
{
double CompressionRatio = 0.0;
metrics->TotalUncompressedBytes += UncompressedBytes;
metrics->TotalCompressedBytes += CompressedBytes;
if (UncompressedBytes != 0)
CompressionRatio = ((double)CompressedBytes) / ((double)UncompressedBytes);
if (metrics->TotalUncompressedBytes != 0)
metrics->TotalCompressionRatio =
((double)metrics->TotalCompressedBytes) / ((double)metrics->TotalUncompressedBytes);
return CompressionRatio;
}
rdpMetrics* metrics_new(rdpContext* context)
{
rdpMetrics* metrics = nullptr;
metrics = (rdpMetrics*)calloc(1, sizeof(rdpMetrics));
if (metrics)
{
metrics->context = context;
}
return metrics;
}
void metrics_free(rdpMetrics* metrics)
{
free(metrics);
}

View File

@@ -0,0 +1,240 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* MULTITRANSPORT PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <winpr/assert.h>
#include <freerdp/config.h>
#include <freerdp/log.h>
#include "settings.h"
#include "rdp.h"
#include "multitransport.h"
struct rdp_multitransport
{
rdpRdp* rdp;
MultiTransportRequestCb MtRequest;
MultiTransportResponseCb MtResponse;
/* server-side data */
UINT32 reliableReqId;
BYTE reliableCookie[RDPUDP_COOKIE_LEN];
BYTE reliableCookieHash[RDPUDP_COOKIE_HASHLEN];
};
enum
{
RDPTUNNEL_ACTION_CREATEREQUEST = 0x00,
RDPTUNNEL_ACTION_CREATERESPONSE = 0x01,
RDPTUNNEL_ACTION_DATA = 0x02
};
#define TAG FREERDP_TAG("core.multitransport")
state_run_t multitransport_recv_request(rdpMultitransport* multi, wStream* s)
{
WINPR_ASSERT(multi);
rdpSettings* settings = multi->rdp->settings;
if (settings->ServerMode)
{
WLog_ERR(TAG, "not expecting a multi-transport request in server mode");
return STATE_RUN_FAILED;
}
if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
return STATE_RUN_FAILED;
UINT32 requestId = 0;
UINT16 requestedProto = 0;
UINT16 reserved = 0;
const BYTE* cookie = nullptr;
Stream_Read_UINT32(s, requestId); /* requestId (4 bytes) */
Stream_Read_UINT16(s, requestedProto); /* requestedProtocol (2 bytes) */
Stream_Read_UINT16(s, reserved); /* reserved (2 bytes) */
cookie = Stream_ConstPointer(s);
Stream_Seek(s, RDPUDP_COOKIE_LEN); /* securityCookie (16 bytes) */
if (reserved != 0)
{
/*
* If the reserved filed is not 0 the request PDU seems to contain some extra data.
* If the reserved value is 1, then two bytes of 0 (probably a version field)
* are followed by a JSON payload (not null terminated, until the end of the packet.
* There seems to be no dedicated length field)
*
* for now just ignore all that
*/
WLog_WARN(TAG,
"reserved is %" PRIu16 " instead of 0, skipping %" PRIuz "bytes of unknown data",
reserved, Stream_GetRemainingLength(s));
(void)Stream_SafeSeek(s, Stream_GetRemainingLength(s));
}
WINPR_ASSERT(multi->MtRequest);
return multi->MtRequest(multi, requestId, requestedProto, cookie);
}
static BOOL multitransport_request_send(rdpMultitransport* multi, UINT32 reqId, UINT16 reqProto,
const BYTE* cookie)
{
WINPR_ASSERT(multi);
UINT16 sec_flags = 0;
wStream* s = rdp_message_channel_pdu_init(multi->rdp, &sec_flags);
if (!s)
return FALSE;
if (!Stream_EnsureRemainingCapacity(s, 24))
{
Stream_Release(s);
return FALSE;
}
Stream_Write_UINT32(s, reqId); /* requestId (4 bytes) */
Stream_Write_UINT16(s, reqProto); /* requestedProtocol (2 bytes) */
Stream_Zero(s, 2); /* reserved (2 bytes) */
Stream_Write(s, cookie, RDPUDP_COOKIE_LEN); /* securityCookie (16 bytes) */
return rdp_send_message_channel_pdu(multi->rdp, s, sec_flags | SEC_TRANSPORT_REQ);
}
state_run_t multitransport_server_request(rdpMultitransport* multi, UINT16 reqProto)
{
WINPR_ASSERT(multi);
/* TODO: move this static variable to the listener */
static UINT32 reqId = 0;
if (reqProto == INITIATE_REQUEST_PROTOCOL_UDPFECR)
{
multi->reliableReqId = reqId++;
if (winpr_RAND(multi->reliableCookie, sizeof(multi->reliableCookie)) < 0)
return STATE_RUN_FAILED;
return multitransport_request_send(multi, multi->reliableReqId, reqProto,
multi->reliableCookie)
? STATE_RUN_SUCCESS
: STATE_RUN_FAILED;
}
WLog_ERR(TAG, "only reliable transport is supported");
return STATE_RUN_CONTINUE;
}
BOOL multitransport_client_send_response(rdpMultitransport* multi, UINT32 reqId, HRESULT hr)
{
WINPR_ASSERT(multi);
UINT16 sec_flags = 0;
wStream* s = rdp_message_channel_pdu_init(multi->rdp, &sec_flags);
if (!s)
return FALSE;
if (!Stream_EnsureRemainingCapacity(s, 28))
{
Stream_Release(s);
return FALSE;
}
Stream_Write_UINT32(s, reqId); /* requestId (4 bytes) */
/* [MS-RDPBCGR] 2.2.15.2 Client Initiate Multitransport Response PDU defines this as 4byte
* UNSIGNED but https://learn.microsoft.com/en-us/windows/win32/learnwin32/error-codes-in-com
* defines this as signed... assume the spec is (implicitly) assuming twos complement. */
Stream_Write_INT32(s, hr); /* HResult (4 bytes) */
return rdp_send_message_channel_pdu(multi->rdp, s, sec_flags | SEC_TRANSPORT_RSP);
}
state_run_t multitransport_recv_response(rdpMultitransport* multi, wStream* s)
{
WINPR_ASSERT(multi && multi->rdp);
WINPR_ASSERT(s);
rdpSettings* settings = multi->rdp->settings;
WINPR_ASSERT(settings);
if (!settings->ServerMode)
{
WLog_ERR(TAG, "client is not expecting a multi-transport resp packet");
return STATE_RUN_FAILED;
}
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return STATE_RUN_FAILED;
UINT32 requestId = 0;
UINT32 hr = 0;
Stream_Read_UINT32(s, requestId); /* requestId (4 bytes) */
Stream_Read_UINT32(s, hr); /* hrResponse (4 bytes) */
state_run_t res = STATE_RUN_SUCCESS;
IFCALLRET(multi->MtResponse, res, multi, requestId, hr);
return res;
}
static state_run_t multitransport_no_udp(rdpMultitransport* multi, UINT32 reqId,
WINPR_ATTR_UNUSED UINT16 reqProto,
WINPR_ATTR_UNUSED const BYTE* cookie)
{
return multitransport_client_send_response(multi, reqId, E_ABORT) ? STATE_RUN_SUCCESS
: STATE_RUN_FAILED;
}
static state_run_t multitransport_server_handle_response(rdpMultitransport* multi,
WINPR_ATTR_UNUSED UINT32 reqId,
WINPR_ATTR_UNUSED UINT32 hrResponse)
{
rdpRdp* rdp = multi->rdp;
if (!rdp_server_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE_DEMAND_ACTIVE))
return STATE_RUN_FAILED;
return STATE_RUN_CONTINUE;
}
rdpMultitransport* multitransport_new(rdpRdp* rdp, WINPR_ATTR_UNUSED UINT16 protocol)
{
WINPR_ASSERT(rdp);
rdpSettings* settings = rdp->settings;
WINPR_ASSERT(settings);
rdpMultitransport* multi = calloc(1, sizeof(rdpMultitransport));
if (!multi)
return nullptr;
if (settings->ServerMode)
{
multi->MtResponse = multitransport_server_handle_response;
}
else
{
multi->MtRequest = multitransport_no_udp;
}
multi->rdp = rdp;
return multi;
}
void multitransport_free(rdpMultitransport* multitransport)
{
free(multitransport);
}

View File

@@ -0,0 +1,66 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Multitransport PDUs
*
* Copyright 2014 Dell Software <Mike.McDonald@software.dell.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_MULTITRANSPORT_H
#define FREERDP_LIB_CORE_MULTITRANSPORT_H
typedef struct rdp_multitransport rdpMultitransport;
#include "rdp.h"
#include "state.h"
#include <freerdp/freerdp.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
typedef enum
{
INITIATE_REQUEST_PROTOCOL_UDPFECR = 0x01,
INITIATE_REQUEST_PROTOCOL_UDPFECL = 0x02
} MultitransportRequestProtocol;
typedef state_run_t (*MultiTransportRequestCb)(rdpMultitransport* multi, UINT32 reqId,
UINT16 reqProto, const BYTE* cookie);
typedef state_run_t (*MultiTransportResponseCb)(rdpMultitransport* multi, UINT32 reqId,
UINT32 hrResponse);
#define RDPUDP_COOKIE_LEN 16
#define RDPUDP_COOKIE_HASHLEN 32
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t multitransport_recv_request(rdpMultitransport* multi, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t multitransport_server_request(rdpMultitransport* multi, UINT16 reqProto);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t multitransport_recv_response(rdpMultitransport* multi, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL multitransport_client_send_response(rdpMultitransport* multi, UINT32 reqId,
HRESULT hr);
FREERDP_LOCAL void multitransport_free(rdpMultitransport* multi);
WINPR_ATTR_MALLOC(multitransport_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpMultitransport* multitransport_new(rdpRdp* rdp, UINT16 protocol);
#endif /* FREERDP_LIB_CORE_MULTITRANSPORT_H */

2103
third_party/FreeRDP/libfreerdp/core/nego.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,191 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Protocol Security Negotiation
*
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_NEGO_H
#define FREERDP_LIB_CORE_NEGO_H
#include "transport.h"
#include <freerdp/types.h>
#include <freerdp/settings.h>
#include <freerdp/log.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
/* Protocol Security Negotiation Protocols
* [MS-RDPBCGR] 2.2.1.1.1 RDP Negotiation Request (RDP_NEG_REQ)
*/
#define PROTOCOL_RDP 0x00000000
#define PROTOCOL_SSL 0x00000001
#define PROTOCOL_HYBRID 0x00000002
#define PROTOCOL_RDSTLS 0x00000004
#define PROTOCOL_HYBRID_EX 0x00000008
#define PROTOCOL_RDSAAD 0x00000010
#define PROTOCOL_FAILED_NEGO 0x80000000 /* only used internally, not on the wire */
/* Protocol Security Negotiation Failure Codes */
enum RDP_NEG_FAILURE_FAILURECODES
{
SSL_REQUIRED_BY_SERVER = 0x00000001,
SSL_NOT_ALLOWED_BY_SERVER = 0x00000002,
SSL_CERT_NOT_ON_SERVER = 0x00000003,
INCONSISTENT_FLAGS = 0x00000004,
HYBRID_REQUIRED_BY_SERVER = 0x00000005,
SSL_WITH_USER_AUTH_REQUIRED_BY_SERVER = 0x00000006
};
typedef enum
{
NEGO_STATE_INITIAL,
NEGO_STATE_RDSTLS, /* RDSTLS (TLS implicit) */
NEGO_STATE_AAD, /* Azure AD Authentication (TLS implicit) */
NEGO_STATE_EXT, /* Extended NLA (NLA + TLS implicit) */
NEGO_STATE_NLA, /* Network Level Authentication (TLS implicit) */
NEGO_STATE_TLS, /* TLS Encryption without NLA */
NEGO_STATE_RDP, /* Standard Legacy RDP Encryption */
NEGO_STATE_FAIL, /* Negotiation failure */
NEGO_STATE_FINAL
} NEGO_STATE;
/* RDP Negotiation Messages */
enum RDP_NEG_MSG
{
/* X224_TPDU_CONNECTION_REQUEST */
TYPE_RDP_NEG_REQ = 0x1,
/* X224_TPDU_CONNECTION_CONFIRM */
TYPE_RDP_NEG_RSP = 0x2,
TYPE_RDP_NEG_FAILURE = 0x3,
TYPE_RDP_CORRELATION_INFO = 0x6
};
typedef enum
{
EXTENDED_CLIENT_DATA_SUPPORTED = 0x01,
DYNVC_GFX_PROTOCOL_SUPPORTED = 0x02,
RDP_NEGRSP_RESERVED = 0x04,
RESTRICTED_ADMIN_MODE_SUPPORTED = 0x08,
REDIRECTED_AUTHENTICATION_MODE_SUPPORTED = 0x10
} RdpNegRespFlags;
#define PRECONNECTION_PDU_V1_SIZE 16
#define PRECONNECTION_PDU_V2_MIN_SIZE (PRECONNECTION_PDU_V1_SIZE + 2)
#define PRECONNECTION_PDU_V1 1
#define PRECONNECTION_PDU_V2 2
#define RESTRICTED_ADMIN_MODE_REQUIRED 0x01
#define REDIRECTED_AUTHENTICATION_MODE_REQUIRED 0x02
#define CORRELATION_INFO_PRESENT 0x08
typedef struct rdp_nego rdpNego;
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_connect(rdpNego* nego);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_disconnect(rdpNego* nego);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int nego_recv(rdpTransport* transport, wStream* s, void* extra);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_read_request(rdpNego* nego, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_send_negotiation_request(rdpNego* nego);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_send_negotiation_response(rdpNego* nego);
FREERDP_LOCAL void nego_free(rdpNego* nego);
WINPR_ATTR_MALLOC(nego_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpNego* nego_new(rdpTransport* transport);
FREERDP_LOCAL void nego_init(rdpNego* nego);
FREERDP_LOCAL BOOL nego_set_target(rdpNego* nego, const char* hostname, UINT16 port);
FREERDP_LOCAL void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer);
FREERDP_LOCAL void nego_set_restricted_admin_mode_required(rdpNego* nego,
BOOL RestrictedAdminModeRequired);
FREERDP_LOCAL void nego_set_restricted_admin_mode_supported(rdpNego* nego, BOOL enabled);
FREERDP_LOCAL void nego_set_RCG_required(rdpNego* nego, BOOL enabled);
FREERDP_LOCAL void nego_set_RCG_supported(rdpNego* nego, BOOL enabled);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_get_remoteCredentialGuard(const rdpNego* nego);
FREERDP_LOCAL void nego_set_childsession_enabled(rdpNego* nego, BOOL ChildSessionEnabled);
FREERDP_LOCAL void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled);
FREERDP_LOCAL void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal);
FREERDP_LOCAL void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp);
FREERDP_LOCAL void nego_enable_tls(rdpNego* nego, BOOL enable_tls);
FREERDP_LOCAL void nego_enable_nla(rdpNego* nego, BOOL enable_nla);
FREERDP_LOCAL void nego_enable_rdstls(rdpNego* nego, BOOL enable_rdstls);
FREERDP_LOCAL void nego_enable_aad(rdpNego* nego, BOOL enable_aad);
FREERDP_LOCAL void nego_enable_ext(rdpNego* nego, BOOL enable_ext);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const BYTE* nego_get_routing_token(const rdpNego* nego, DWORD* RoutingTokenLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_set_routing_token(rdpNego* nego, const void* RoutingToken,
DWORD RoutingTokenLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_set_cookie(rdpNego* nego, const char* cookie);
FREERDP_LOCAL void nego_set_cookie_max_length(rdpNego* nego, UINT32 CookieMaxLength);
FREERDP_LOCAL void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL SendPreconnectionPdu);
FREERDP_LOCAL void nego_set_preconnection_id(rdpNego* nego, UINT32 PreconnectionId);
FREERDP_LOCAL void nego_set_preconnection_blob(rdpNego* nego, const char* PreconnectionBlob);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL UINT32 nego_get_selected_protocol(const rdpNego* nego);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_set_selected_protocol(rdpNego* nego, UINT32 SelectedProtocol);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL UINT32 nego_get_requested_protocols(const rdpNego* nego);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_set_requested_protocols(rdpNego* nego, UINT32 RequestedProtocols);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nego_update_settings_from_state(rdpNego* nego, rdpSettings* settings);
FREERDP_LOCAL BOOL nego_set_state(rdpNego* nego, NEGO_STATE state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL NEGO_STATE nego_get_state(const rdpNego* nego);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SEC_WINNT_AUTH_IDENTITY* nego_get_identity(rdpNego* nego);
FREERDP_LOCAL void nego_free_nla(rdpNego* nego);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* nego_protocol_to_str(UINT32 protocol, char* buffer, size_t size);
#endif /* FREERDP_LIB_CORE_NEGO_H */

2464
third_party/FreeRDP/libfreerdp/core/nla.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Network Level Authentication (NLA)
*
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_NLA_H
#define FREERDP_LIB_CORE_NLA_H
typedef struct rdp_nla rdpNla;
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#include <winpr/sspi.h>
#include <winpr/stream.h>
#include <winpr/crypto.h>
#include <freerdp/crypto/ber.h>
#include <freerdp/crypto/der.h>
#include <freerdp/crypto/crypto.h>
#include "transport.h"
typedef enum
{
NLA_STATE_INITIAL,
NLA_STATE_NEGO_TOKEN,
NLA_STATE_PUB_KEY_AUTH,
NLA_STATE_EARLY_USER_AUTH,
NLA_STATE_AUTH_INFO,
NLA_STATE_POST_NEGO,
NLA_STATE_FINAL
} NLA_STATE;
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int nla_authenticate(rdpNla* nla);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int nla_client_begin(rdpNla* nla);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int nla_recv_pdu(rdpNla* nla, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SEC_WINNT_AUTH_IDENTITY* nla_get_identity(rdpNla* nla);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL NLA_STATE nla_get_state(const rdpNla* nla);
FREERDP_LOCAL BOOL nla_set_state(rdpNla* nla, NLA_STATE state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* nla_get_state_str(NLA_STATE state);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL DWORD nla_get_error(const rdpNla* nla);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL INT32 nla_get_sspi_error(const rdpNla* nla);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nla_set_service_principal(rdpNla* nla, const char* service,
const char* hostname);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nla_set_sspi_module(rdpNla* nla, const char* sspiModule);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nla_sspi_module_init(rdpNla* nla);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nla_impersonate(rdpNla* nla);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nla_revert_to_self(rdpNla* nla);
FREERDP_LOCAL void nla_free(rdpNla* nla);
WINPR_ATTR_MALLOC(nla_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpNla* nla_new(rdpContext* context, rdpTransport* transport);
FREERDP_LOCAL void nla_set_early_user_auth(rdpNla* nla, BOOL earlyUserAuth);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nla_encrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nla_decrypt(rdpNla* nla, const SecBuffer* inBuffer, SecBuffer* outBuffer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SECURITY_STATUS nla_QueryContextAttributes(rdpNla* nla, DWORD ulAttr, PVOID pBuffer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SECURITY_STATUS nla_FreeContextBuffer(rdpNla* nla, PVOID pBuffer);
#endif /* FREERDP_LIB_CORE_NLA_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,338 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Drawing Orders
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
* Copyright 2016 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_ORDERS_H
#define FREERDP_LIB_CORE_ORDERS_H
#include "rdp.h"
#include <freerdp/types.h>
#include <freerdp/update.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
/* Order Control Flags */
#define ORDER_STANDARD 0x01
#define ORDER_SECONDARY 0x02
#define ORDER_BOUNDS 0x04
#define ORDER_TYPE_CHANGE 0x08
#define ORDER_DELTA_COORDINATES 0x10
#define ORDER_ZERO_BOUNDS_DELTAS 0x20
#define ORDER_ZERO_FIELD_BYTE_BIT0 0x40
#define ORDER_ZERO_FIELD_BYTE_BIT1 0x80
/* Bound Field Flags */
#define BOUND_LEFT 0x01
#define BOUND_TOP 0x02
#define BOUND_RIGHT 0x04
#define BOUND_BOTTOM 0x08
#define BOUND_DELTA_LEFT 0x10
#define BOUND_DELTA_TOP 0x20
#define BOUND_DELTA_RIGHT 0x40
#define BOUND_DELTA_BOTTOM 0x80
/* Field Presence Flags */
#define ORDER_FIELD_01 0x000001
#define ORDER_FIELD_02 0x000002
#define ORDER_FIELD_03 0x000004
#define ORDER_FIELD_04 0x000008
#define ORDER_FIELD_05 0x000010
#define ORDER_FIELD_06 0x000020
#define ORDER_FIELD_07 0x000040
#define ORDER_FIELD_08 0x000080
#define ORDER_FIELD_09 0x000100
#define ORDER_FIELD_10 0x000200
#define ORDER_FIELD_11 0x000400
#define ORDER_FIELD_12 0x000800
#define ORDER_FIELD_13 0x001000
#define ORDER_FIELD_14 0x002000
#define ORDER_FIELD_15 0x004000
#define ORDER_FIELD_16 0x008000
#define ORDER_FIELD_17 0x010000
#define ORDER_FIELD_18 0x020000
#define ORDER_FIELD_19 0x040000
#define ORDER_FIELD_20 0x080000
#define ORDER_FIELD_21 0x100000
#define ORDER_FIELD_22 0x200000
#define ORDER_FIELD_23 0x400000
/* Bitmap Cache Flags */
#define CBR2_8BPP 0x3
#define CBR2_16BPP 0x4
#define CBR2_24BPP 0x5
#define CBR2_32BPP 0x6
#define CBR23_8BPP 0x3
#define CBR23_16BPP 0x4
#define CBR23_24BPP 0x5
#define CBR23_32BPP 0x6
#define CBR3_IGNORABLE_FLAG 0x08
#define CBR3_DO_NOT_CACHE 0x10
/* Primary Drawing Orders */
#define ORDER_TYPE_DSTBLT 0x00
#define ORDER_TYPE_PATBLT 0x01
#define ORDER_TYPE_SCRBLT 0x02
#define ORDER_TYPE_DRAW_NINE_GRID 0x07
#define ORDER_TYPE_MULTI_DRAW_NINE_GRID 0x08
#define ORDER_TYPE_LINE_TO 0x09
#define ORDER_TYPE_OPAQUE_RECT 0x0A
#define ORDER_TYPE_SAVE_BITMAP 0x0B
#define ORDER_TYPE_MEMBLT 0x0D
#define ORDER_TYPE_MEM3BLT 0x0E
#define ORDER_TYPE_MULTI_DSTBLT 0x0F
#define ORDER_TYPE_MULTI_PATBLT 0x10
#define ORDER_TYPE_MULTI_SCRBLT 0x11
#define ORDER_TYPE_MULTI_OPAQUE_RECT 0x12
#define ORDER_TYPE_FAST_INDEX 0x13
#define ORDER_TYPE_POLYGON_SC 0x14
#define ORDER_TYPE_POLYGON_CB 0x15
#define ORDER_TYPE_POLYLINE 0x16
#define ORDER_TYPE_FAST_GLYPH 0x18
#define ORDER_TYPE_ELLIPSE_SC 0x19
#define ORDER_TYPE_ELLIPSE_CB 0x1A
#define ORDER_TYPE_GLYPH_INDEX 0x1B
/* Primary Drawing Orders Fields */
#define DSTBLT_ORDER_FIELDS 5
#define PATBLT_ORDER_FIELDS 12
#define SCRBLT_ORDER_FIELDS 7
#define DRAW_NINE_GRID_ORDER_FIELDS 5
#define MULTI_DRAW_NINE_GRID_ORDER_FIELDS 7
#define LINE_TO_ORDER_FIELDS 10
#define OPAQUE_RECT_ORDER_FIELDS 7
#define SAVE_BITMAP_ORDER_FIELDS 6
#define MEMBLT_ORDER_FIELDS 9
#define MEM3BLT_ORDER_FIELDS 16
#define MULTI_DSTBLT_ORDER_FIELDS 7
#define MULTI_PATBLT_ORDER_FIELDS 14
#define MULTI_SCRBLT_ORDER_FIELDS 9
#define MULTI_OPAQUE_RECT_ORDER_FIELDS 9
#define FAST_INDEX_ORDER_FIELDS 15
#define POLYGON_SC_ORDER_FIELDS 7
#define POLYGON_CB_ORDER_FIELDS 13
#define POLYLINE_ORDER_FIELDS 7
#define FAST_GLYPH_ORDER_FIELDS 15
#define ELLIPSE_SC_ORDER_FIELDS 7
#define ELLIPSE_CB_ORDER_FIELDS 13
#define GLYPH_INDEX_ORDER_FIELDS 22
/* Primary Drawing Orders Field Bytes */
#define DSTBLT_ORDER_FIELD_BYTES 1
#define PATBLT_ORDER_FIELD_BYTES 2
#define SCRBLT_ORDER_FIELD_BYTES 1
#define DRAW_NINE_GRID_ORDER_FIELD_BYTES 1
#define MULTI_DRAW_NINE_GRID_ORDER_FIELD_BYTES 1
#define LINE_TO_ORDER_FIELD_BYTES 2
#define OPAQUE_RECT_ORDER_FIELD_BYTES 1
#define SAVE_BITMAP_ORDER_FIELD_BYTES 1
#define MEMBLT_ORDER_FIELD_BYTES 2
#define MEM3BLT_ORDER_FIELD_BYTES 3
#define MULTI_DSTBLT_ORDER_FIELD_BYTES 1
#define MULTI_PATBLT_ORDER_FIELD_BYTES 2
#define MULTI_SCRBLT_ORDER_FIELD_BYTES 2
#define MULTI_OPAQUE_RECT_ORDER_FIELD_BYTES 2
#define FAST_INDEX_ORDER_FIELD_BYTES 2
#define POLYGON_SC_ORDER_FIELD_BYTES 1
#define POLYGON_CB_ORDER_FIELD_BYTES 2
#define POLYLINE_ORDER_FIELD_BYTES 1
#define FAST_GLYPH_ORDER_FIELD_BYTES 2
#define ELLIPSE_SC_ORDER_FIELD_BYTES 1
#define ELLIPSE_CB_ORDER_FIELD_BYTES 2
#define GLYPH_INDEX_ORDER_FIELD_BYTES 3
/* Secondary Drawing Orders */
#define ORDER_TYPE_BITMAP_UNCOMPRESSED 0x00
#define ORDER_TYPE_CACHE_COLOR_TABLE 0x01
#define ORDER_TYPE_CACHE_BITMAP_COMPRESSED 0x02
#define ORDER_TYPE_CACHE_GLYPH 0x03
#define ORDER_TYPE_BITMAP_UNCOMPRESSED_V2 0x04
#define ORDER_TYPE_BITMAP_COMPRESSED_V2 0x05
#define ORDER_TYPE_CACHE_BRUSH 0x07
#define ORDER_TYPE_BITMAP_COMPRESSED_V3 0x08
/* Alternate Secondary Drawing Orders */
#define ORDER_TYPE_SWITCH_SURFACE 0x00
#define ORDER_TYPE_CREATE_OFFSCREEN_BITMAP 0x01
#define ORDER_TYPE_STREAM_BITMAP_FIRST 0x02
#define ORDER_TYPE_STREAM_BITMAP_NEXT 0x03
#define ORDER_TYPE_CREATE_NINE_GRID_BITMAP 0x04
#define ORDER_TYPE_GDIPLUS_FIRST 0x05
#define ORDER_TYPE_GDIPLUS_NEXT 0x06
#define ORDER_TYPE_GDIPLUS_END 0x07
#define ORDER_TYPE_GDIPLUS_CACHE_FIRST 0x08
#define ORDER_TYPE_GDIPLUS_CACHE_NEXT 0x09
#define ORDER_TYPE_GDIPLUS_CACHE_END 0x0A
#define ORDER_TYPE_WINDOW 0x0B
#define ORDER_TYPE_COMPDESK_FIRST 0x0C
#define ORDER_TYPE_FRAME_MARKER 0x0D
#define CG_GLYPH_UNICODE_PRESENT 0x0010
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BYTE get_primary_drawing_order_field_bytes(UINT32 orderType, BOOL* pValid);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_recv_order(rdpUpdate* update, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_field_flags(wStream* s, UINT32 fieldFlags, BYTE flags,
BYTE fieldBytes);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_bounds(wStream* s, const ORDER_INFO* orderInfo);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_dstblt_order(ORDER_INFO* orderInfo,
const DSTBLT_ORDER* dstblt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_dstblt_order(wStream* s, ORDER_INFO* orderInfo,
const DSTBLT_ORDER* dstblt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_patblt_order(ORDER_INFO* orderInfo, PATBLT_ORDER* patblt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_patblt_order(wStream* s, ORDER_INFO* orderInfo,
PATBLT_ORDER* patblt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_scrblt_order(ORDER_INFO* orderInfo,
const SCRBLT_ORDER* scrblt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_scrblt_order(wStream* s, ORDER_INFO* orderInfo,
const SCRBLT_ORDER* scrblt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_opaque_rect_order(ORDER_INFO* orderInfo,
const OPAQUE_RECT_ORDER* opaque_rect);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo,
const OPAQUE_RECT_ORDER* opaque_rect);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_line_to_order(ORDER_INFO* orderInfo,
const LINE_TO_ORDER* line_to);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_line_to_order(wStream* s, ORDER_INFO* orderInfo,
const LINE_TO_ORDER* line_to);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_memblt_order(ORDER_INFO* orderInfo,
const MEMBLT_ORDER* memblt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_memblt_order(wStream* s, ORDER_INFO* orderInfo,
const MEMBLT_ORDER* memblt);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_glyph_index_order(ORDER_INFO* orderInfo,
const GLYPH_INDEX_ORDER* glyph_index);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_glyph_index_order(wStream* s, ORDER_INFO* orderInfo,
GLYPH_INDEX_ORDER* glyph_index);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_cache_bitmap_order(const CACHE_BITMAP_ORDER* cache_bitmap,
BOOL compressed, const UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_cache_bitmap_order(wStream* s,
const CACHE_BITMAP_ORDER* cache_bitmap_order,
BOOL compressed, UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_cache_bitmap_v2_order(
CACHE_BITMAP_V2_ORDER* cache_bitmap_v2, BOOL compressed, const UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_cache_bitmap_v2_order(wStream* s,
CACHE_BITMAP_V2_ORDER* cache_bitmap_v2_order,
BOOL compressed, UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t
update_approximate_cache_bitmap_v3_order(CACHE_BITMAP_V3_ORDER* cache_bitmap_v3, UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_cache_bitmap_v3_order(wStream* s,
CACHE_BITMAP_V3_ORDER* cache_bitmap_v3_order,
UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_cache_color_table_order(
const CACHE_COLOR_TABLE_ORDER* cache_color_table, const UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_cache_color_table_order(
wStream* s, const CACHE_COLOR_TABLE_ORDER* cache_color_table_order, UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_cache_glyph_order(const CACHE_GLYPH_ORDER* cache_glyph,
const UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_cache_glyph_order(wStream* s,
const CACHE_GLYPH_ORDER* cache_glyph_order,
UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_cache_glyph_v2_order(
const CACHE_GLYPH_V2_ORDER* cache_glyph_v2, const UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_cache_glyph_v2_order(wStream* s,
const CACHE_GLYPH_V2_ORDER* cache_glyph_v2,
UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_cache_brush_order(const CACHE_BRUSH_ORDER* cache_brush,
const UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_cache_brush_order(wStream* s,
const CACHE_BRUSH_ORDER* cache_brush_order,
UINT16* flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t update_approximate_create_offscreen_bitmap_order(
const CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_create_offscreen_bitmap_order(
wStream* s, const CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t
update_approximate_switch_surface_order(const SWITCH_SURFACE_ORDER* switch_surface);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL update_write_switch_surface_order(wStream* s,
const SWITCH_SURFACE_ORDER* switch_surface);
#endif /* FREERDP_LIB_CORE_ORDERS_H */

1618
third_party/FreeRDP/libfreerdp/core/peer.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Server Peer
*
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_PEER_H
#define FREERDP_LIB_CORE_PEER_H
#include "rdp.h"
#include "mcs.h"
#include "server.h"
#include <freerdp/peer.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_peer_handle_state_demand_active(freerdp_peer* client);
#endif /* FREERDP_LIB_CORE_PEER_H */

View File

@@ -0,0 +1,995 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* HTTP Proxy support
*
* Copyright 2016 Christian Plattner <ccpp@gmx.at>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <openssl/err.h>
#include "settings.h"
#include "proxy.h"
#include <freerdp/settings.h>
#include <freerdp/utils/proxy_utils.h>
#include <freerdp/crypto/crypto.h>
#include "tcp.h"
#include <winpr/assert.h>
#include <winpr/sysinfo.h>
#include <winpr/environment.h> /* For GetEnvironmentVariableA */
#define CRLF "\r\n"
#include <freerdp/log.h>
#define TAG FREERDP_TAG("core.proxy")
/* SOCKS Proxy auth methods by rfc1928 */
enum
{
AUTH_M_NO_AUTH = 0,
AUTH_M_GSSAPI = 1,
AUTH_M_USR_PASS = 2
};
enum
{
SOCKS_CMD_CONNECT = 1,
SOCKS_CMD_BIND = 2,
SOCKS_CMD_UDP_ASSOCIATE = 3
};
enum
{
SOCKS_ADDR_IPV4 = 1,
SOCKS_ADDR_FQDN = 3,
SOCKS_ADDR_IPV6 = 4,
};
static const char logprefix[] = "SOCKS Proxy:";
/* CONN REQ replies in enum. order */
static const char* rplstat[] = { "succeeded",
"general SOCKS server failure",
"connection not allowed by ruleset",
"Network unreachable",
"Host unreachable",
"Connection refused",
"TTL expired",
"Command not supported",
"Address type not supported" };
static BOOL http_proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port);
static BOOL socks_proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port);
static void proxy_read_environment(rdpSettings* settings, char* envname);
BOOL proxy_prepare(rdpSettings* settings, const char** lpPeerHostname, UINT16* lpPeerPort,
const char** lpProxyUsername, const char** lpProxyPassword)
{
if (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType) == PROXY_TYPE_IGNORE)
return FALSE;
/* For TSGateway, find the system HTTPS proxy automatically */
if (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType) == PROXY_TYPE_NONE)
proxy_read_environment(settings, "https_proxy");
if (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType) == PROXY_TYPE_NONE)
proxy_read_environment(settings, "HTTPS_PROXY");
if (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType) != PROXY_TYPE_NONE)
proxy_read_environment(settings, "no_proxy");
if (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType) != PROXY_TYPE_NONE)
proxy_read_environment(settings, "NO_PROXY");
if (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType) != PROXY_TYPE_NONE)
{
*lpPeerHostname = freerdp_settings_get_string(settings, FreeRDP_ProxyHostname);
*lpPeerPort = freerdp_settings_get_uint16(settings, FreeRDP_ProxyPort);
*lpProxyUsername = freerdp_settings_get_string(settings, FreeRDP_ProxyUsername);
*lpProxyPassword = freerdp_settings_get_string(settings, FreeRDP_ProxyPassword);
return TRUE;
}
return FALSE;
}
static BOOL value_to_int(const char* value, LONGLONG* result, LONGLONG min, LONGLONG max)
{
long long rc = 0;
if (!value || !result)
return FALSE;
errno = 0;
rc = _strtoi64(value, nullptr, 0);
if (errno != 0)
return FALSE;
if ((rc < min) || (rc > max))
return FALSE;
*result = rc;
return TRUE;
}
static BOOL cidr4_match(const struct in_addr* addr, const struct in_addr* net, BYTE bits)
{
if (bits == 0)
return TRUE;
const uint32_t mask = htonl(0xFFFFFFFFu << (32 - bits));
const uint32_t amask = addr->s_addr & mask;
const uint32_t nmask = net->s_addr & mask;
return amask == nmask;
}
static BOOL cidr6_match(const struct in6_addr* address, const struct in6_addr* network,
uint8_t bits)
{
const uint32_t* a = (const uint32_t*)address;
const uint32_t* n = (const uint32_t*)network;
const size_t bits_whole = bits >> 5;
const size_t bits_incomplete = bits & 0x1F;
if (bits_whole)
{
if (memcmp(a, n, bits_whole << 2) != 0)
return FALSE;
}
if (bits_incomplete)
{
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
if ((a[bits_whole] ^ n[bits_whole]) & mask)
return FALSE;
}
return TRUE;
}
static BOOL option_ends_with(const char* str, const char* ext)
{
WINPR_ASSERT(str);
WINPR_ASSERT(ext);
const size_t strLen = strlen(str);
const size_t extLen = strlen(ext);
if (strLen < extLen)
return FALSE;
return _strnicmp(&str[strLen - extLen], ext, extLen) == 0;
}
/* no_proxy has no proper definition, so use curl as reference:
* https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/
*/
static BOOL no_proxy_match_host(const char* val, const char* hostname)
{
WINPR_ASSERT(val);
WINPR_ASSERT(hostname);
/* match all */
if (_stricmp("*", val) == 0)
return TRUE;
/* Strip leading . */
if (val[0] == '.')
val++;
/* Match suffix */
return option_ends_with(hostname, val);
}
static BOOL starts_with(const char* val, const char* prefix)
{
const size_t plen = strlen(prefix);
const size_t vlen = strlen(val);
if (vlen < plen)
return FALSE;
return _strnicmp(val, prefix, plen) == 0;
}
static BOOL no_proxy_match_ip(const char* val, const char* hostname)
{
WINPR_ASSERT(val);
WINPR_ASSERT(hostname);
struct sockaddr_in sa4 = WINPR_C_ARRAY_INIT;
struct sockaddr_in6 sa6 = WINPR_C_ARRAY_INIT;
if (inet_pton(AF_INET, hostname, &sa4.sin_addr) == 1)
{
/* Prefix match */
if (starts_with(hostname, val))
return TRUE;
char* sub = strchr(val, '/');
if (sub)
*sub++ = '\0';
struct sockaddr_in mask = WINPR_C_ARRAY_INIT;
if (inet_pton(AF_INET, val, &mask.sin_addr) == 0)
return FALSE;
/* IP address match */
if (memcmp(&mask, &sa4, sizeof(mask)) == 0)
return TRUE;
if (sub)
{
const unsigned long usub = strtoul(sub, nullptr, 0);
if ((errno == 0) && (usub <= UINT8_MAX))
return cidr4_match(&sa4.sin_addr, &mask.sin_addr, (UINT8)usub);
}
}
else if (inet_pton(AF_INET6, hostname, &sa6.sin6_addr) == 1)
{
if (val[0] == '[')
val++;
char str[INET6_ADDRSTRLEN + 1] = WINPR_C_ARRAY_INIT;
strncpy(str, val, INET6_ADDRSTRLEN);
const size_t len = strnlen(str, INET6_ADDRSTRLEN);
if (len > 0)
{
if (str[len - 1] == ']')
str[len - 1] = '\0';
}
/* Prefix match */
if (starts_with(hostname, str))
return TRUE;
char* sub = strchr(str, '/');
if (sub)
*sub++ = '\0';
struct sockaddr_in6 mask = WINPR_C_ARRAY_INIT;
if (inet_pton(AF_INET6, str, &mask.sin6_addr) == 0)
return FALSE;
/* Address match */
if (memcmp(&mask, &sa6, sizeof(mask)) == 0)
return TRUE;
if (sub)
{
const unsigned long usub = strtoul(sub, nullptr, 0);
if ((errno == 0) && (usub <= UINT8_MAX))
return cidr6_match(&sa6.sin6_addr, &mask.sin6_addr, (UINT8)usub);
}
}
return FALSE;
}
static BOOL check_no_proxy(rdpSettings* settings, const char* no_proxy)
{
const char* delimiter = ", ";
BOOL result = FALSE;
char* context = nullptr;
if (!no_proxy || !settings)
return FALSE;
char* copy = _strdup(no_proxy);
if (!copy)
return FALSE;
char* current = strtok_s(copy, delimiter, &context);
while (current && !result)
{
const size_t currentlen = strlen(current);
if (currentlen > 0)
{
WLog_DBG(TAG, "%s => %s (%" PRIuz ")", settings->ServerHostname, current, currentlen);
if (no_proxy_match_host(current, settings->ServerHostname))
result = TRUE;
else if (no_proxy_match_ip(current, settings->ServerHostname))
result = TRUE;
}
current = strtok_s(nullptr, delimiter, &context);
}
free(copy);
return result;
}
void proxy_read_environment(rdpSettings* settings, char* envname)
{
const DWORD envlen = GetEnvironmentVariableA(envname, nullptr, 0);
if (!envlen || (envlen <= 1))
return;
char* env = calloc(1, envlen);
if (!env)
{
WLog_ERR(TAG, "Not enough memory");
return;
}
if (GetEnvironmentVariableA(envname, env, envlen) == envlen - 1)
{
if (_strnicmp("NO_PROXY", envname, 9) == 0)
{
if (check_no_proxy(settings, env))
{
WLog_INFO(TAG, "deactivating proxy: %s [%s=%s]",
freerdp_settings_get_string(settings, FreeRDP_ServerHostname), envname,
env);
if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_NONE))
WLog_WARN(TAG, "failed to set FreeRDP_ProxyType=PROXY_TYPE_NONE");
}
}
else
{
if (!proxy_parse_uri(settings, env))
{
WLog_WARN(
TAG, "Error while parsing proxy URI from environment variable; ignoring proxy");
}
}
}
free(env);
}
BOOL proxy_parse_uri(rdpSettings* settings, const char* uri_in)
{
BOOL rc = FALSE;
const char* protocol = "";
UINT16 port = 0;
if (!settings || !uri_in)
return FALSE;
char* uri_copy = _strdup(uri_in);
char* uri = uri_copy;
if (!uri)
goto fail;
{
char* p = strstr(uri, "://");
if (p)
{
*p = '\0';
if (_stricmp("no_proxy", uri) == 0)
{
if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_IGNORE))
goto fail;
}
if (_stricmp("http", uri) == 0)
{
if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP))
goto fail;
protocol = "http";
}
else if (_stricmp("socks5", uri) == 0)
{
if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_SOCKS))
goto fail;
protocol = "socks5";
}
else
{
WLog_ERR(TAG, "Only HTTP and SOCKS5 proxies supported by now");
goto fail;
}
uri = p + 3;
}
else
{
/* default proxy protocol is http */
if (!freerdp_settings_set_uint32(settings, FreeRDP_ProxyType, PROXY_TYPE_HTTP))
goto fail;
protocol = "http";
}
}
/* uri is now [user:password@]hostname:port */
{
char* atPtr = strrchr(uri, '@');
if (atPtr)
{
/* got a login / password,
* atPtr
* v
* [user:password@]hostname:port
* ^
* colonPtr
*/
char* colonPtr = strchr(uri, ':');
if (!colonPtr || (colonPtr > atPtr))
{
WLog_ERR(TAG, "invalid syntax for proxy (contains no password)");
goto fail;
}
*colonPtr = '\0';
if (!freerdp_settings_set_string(settings, FreeRDP_ProxyUsername, uri))
{
WLog_ERR(TAG, "unable to allocate proxy username");
goto fail;
}
*atPtr = '\0';
if (!freerdp_settings_set_string(settings, FreeRDP_ProxyPassword, colonPtr + 1))
{
WLog_ERR(TAG, "unable to allocate proxy password");
goto fail;
}
uri = atPtr + 1;
}
}
{
char* p = strchr(uri, ':');
if (p)
{
LONGLONG val = 0;
if (!value_to_int(&p[1], &val, 0, UINT16_MAX))
{
WLog_ERR(TAG, "invalid syntax for proxy (invalid port)");
goto fail;
}
if (val == 0)
{
WLog_ERR(TAG, "invalid syntax for proxy (port missing)");
goto fail;
}
port = (UINT16)val;
*p = '\0';
}
else
{
if (_stricmp("http", protocol) == 0)
{
/* The default is 80. Also for Proxies. */
port = 80;
}
else
{
port = 1080;
}
WLog_DBG(TAG, "setting default proxy port: %" PRIu16, port);
}
if (!freerdp_settings_set_uint16(settings, FreeRDP_ProxyPort, port))
goto fail;
}
{
char* p = strchr(uri, '/');
if (p)
*p = '\0';
if (!freerdp_settings_set_string(settings, FreeRDP_ProxyHostname, uri))
goto fail;
}
if (_stricmp("", uri) == 0)
{
WLog_ERR(TAG, "invalid syntax for proxy (hostname missing)");
goto fail;
}
if (freerdp_settings_get_string(settings, FreeRDP_ProxyUsername))
{
WLog_INFO(TAG, "Parsed proxy configuration: %s://%s:%s@%s:%" PRIu16, protocol,
freerdp_settings_get_string(settings, FreeRDP_ProxyUsername), "******",
freerdp_settings_get_string(settings, FreeRDP_ProxyHostname),
freerdp_settings_get_uint16(settings, FreeRDP_ProxyPort));
}
else
{
WLog_INFO(TAG, "Parsed proxy configuration: %s://%s:%" PRIu16, protocol,
freerdp_settings_get_string(settings, FreeRDP_ProxyHostname),
freerdp_settings_get_uint16(settings, FreeRDP_ProxyPort));
}
rc = TRUE;
fail:
if (!rc)
WLog_WARN(TAG, "Failed to parse proxy configuration: %s://%s:%" PRIu16, protocol, uri,
port);
free(uri_copy);
return rc;
}
BOOL proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port)
{
WINPR_ASSERT(context);
rdpSettings* settings = context->settings;
switch (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType))
{
case PROXY_TYPE_NONE:
case PROXY_TYPE_IGNORE:
return TRUE;
case PROXY_TYPE_HTTP:
return http_proxy_connect(context, bufferedBio, proxyUsername, proxyPassword, hostname,
port);
case PROXY_TYPE_SOCKS:
return socks_proxy_connect(context, bufferedBio, proxyUsername, proxyPassword, hostname,
port);
default:
WLog_ERR(TAG, "Invalid internal proxy configuration");
return FALSE;
}
}
static const char* get_response_header(char* response)
{
char* current_pos = strchr(response, '\r');
if (!current_pos)
current_pos = strchr(response, '\n');
if (current_pos)
*current_pos = '\0';
return response;
}
static BOOL http_proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port)
{
BOOL rc = FALSE;
int status = 0;
wStream* s = nullptr;
char port_str[10] = WINPR_C_ARRAY_INIT;
char recv_buf[256] = WINPR_C_ARRAY_INIT;
char* eol = nullptr;
size_t resultsize = 0;
size_t reserveSize = 0;
size_t portLen = 0;
size_t hostLen = 0;
const char connect[] = "CONNECT ";
const char httpheader[] = " HTTP/1.1" CRLF "Host: ";
WINPR_ASSERT(context);
WINPR_ASSERT(bufferedBio);
WINPR_ASSERT(hostname);
const UINT32 timeout =
freerdp_settings_get_uint32(context->settings, FreeRDP_TcpConnectTimeout);
_itoa_s(port, port_str, sizeof(port_str), 10);
hostLen = strlen(hostname);
portLen = strnlen(port_str, sizeof(port_str));
reserveSize = strlen(connect) + (hostLen + 1ull + portLen) * 2ull + strlen(httpheader);
s = Stream_New(nullptr, reserveSize);
if (!s)
goto fail;
Stream_Write(s, connect, strlen(connect));
Stream_Write(s, hostname, hostLen);
Stream_Write_UINT8(s, ':');
Stream_Write(s, port_str, portLen);
Stream_Write(s, httpheader, strlen(httpheader));
Stream_Write(s, hostname, hostLen);
Stream_Write_UINT8(s, ':');
Stream_Write(s, port_str, portLen);
if (proxyUsername && proxyPassword)
{
const int length = _scprintf("%s:%s", proxyUsername, proxyPassword);
if (length > 0)
{
const size_t size = (size_t)length + 1ull;
char* creds = (char*)malloc(size);
if (!creds)
goto fail;
else
{
const char basic[] = CRLF "Proxy-Authorization: Basic ";
char* base64 = nullptr;
(void)sprintf_s(creds, size, "%s:%s", proxyUsername, proxyPassword);
base64 = crypto_base64_encode((const BYTE*)creds, size - 1);
if (!base64 || !Stream_EnsureRemainingCapacity(s, strlen(basic) + strlen(base64)))
{
free(base64);
free(creds);
goto fail;
}
Stream_Write(s, basic, strlen(basic));
Stream_Write(s, base64, strlen(base64));
free(base64);
}
free(creds);
}
}
if (!Stream_EnsureRemainingCapacity(s, 4))
goto fail;
Stream_Write(s, CRLF CRLF, 4);
ERR_clear_error();
{
const size_t pos = Stream_GetPosition(s);
if (pos > INT32_MAX)
goto fail;
status = BIO_write(bufferedBio, Stream_Buffer(s), WINPR_ASSERTING_INT_CAST(int, pos));
}
if ((status < 0) || ((size_t)status != Stream_GetPosition(s)))
{
WLog_ERR(TAG, "HTTP proxy: failed to write CONNECT request");
goto fail;
}
/* Read result until CR-LF-CR-LF.
* Keep recv_buf a null-terminated string. */
{
const UINT64 start = GetTickCount64();
while (strstr(recv_buf, CRLF CRLF) == nullptr)
{
if (resultsize >= sizeof(recv_buf) - 1)
{
WLog_ERR(TAG, "HTTP Reply headers too long: %s", get_response_header(recv_buf));
goto fail;
}
const size_t rdsize = sizeof(recv_buf) - resultsize - 1ULL;
ERR_clear_error();
WINPR_ASSERT(rdsize <= INT32_MAX);
status = BIO_read(bufferedBio, (BYTE*)recv_buf + resultsize, (int)rdsize);
if (status < 0)
{
/* Error? */
if (!freerdp_shall_disconnect_context(context) && BIO_should_retry(bufferedBio))
{
USleep(100);
continue;
}
WLog_ERR(TAG, "Failed reading reply from HTTP proxy (Status %d)", status);
goto fail;
}
else if (status == 0)
{
const UINT64 now = GetTickCount64();
const UINT64 diff = now - start;
if (freerdp_shall_disconnect_context(context) || (now < start) || (diff > timeout))
{
/* Error? */
WLog_ERR(TAG, "Failed reading reply from HTTP proxy (BIO_read returned zero)");
goto fail;
}
Sleep(10);
}
resultsize += WINPR_ASSERTING_INT_CAST(size_t, status);
}
}
/* Extract HTTP status line */
eol = strchr(recv_buf, '\r');
if (!eol)
{
/* should never happen */
goto fail;
}
*eol = '\0';
WLog_INFO(TAG, "HTTP Proxy: %s", recv_buf);
if (strnlen(recv_buf, sizeof(recv_buf)) < 12)
goto fail;
recv_buf[7] = 'X';
if (strncmp(recv_buf, "HTTP/1.X 200", 12) != 0)
goto fail;
rc = TRUE;
fail:
Stream_Free(s, TRUE);
return rc;
}
static int recv_socks_reply(rdpContext* context, BIO* bufferedBio, BYTE* buf, int len, char* reason,
BYTE checkVer)
{
int status = 0;
WINPR_ASSERT(context);
const UINT32 timeout =
freerdp_settings_get_uint32(context->settings, FreeRDP_TcpConnectTimeout);
const UINT64 start = GetTickCount64();
for (;;)
{
ERR_clear_error();
status = BIO_read(bufferedBio, buf, len);
if (status > 0)
{
break;
}
else if (status < 0)
{
/* Error? */
if (!freerdp_shall_disconnect_context(context) && BIO_should_retry(bufferedBio))
{
USleep(100);
continue;
}
WLog_ERR(TAG, "Failed reading %s reply from SOCKS proxy (Status %d)", reason, status);
return -1;
}
else if (status == 0)
{
const UINT64 now = GetTickCount64();
const UINT64 diff = now - start;
if (freerdp_shall_disconnect_context(context) || (now < start) || (diff > timeout))
{
/* Error? */
WLog_ERR(TAG, "Failed reading %s reply from SOCKS proxy (BIO_read returned zero)",
reason);
return status;
}
Sleep(10);
}
else // if (status == 0)
{
/* Error? */
WLog_ERR(TAG, "Failed reading %s reply from SOCKS proxy (BIO_read returned zero)",
reason);
return -1;
}
}
if (status < 2)
{
WLog_ERR(TAG, "SOCKS Proxy reply packet too short (%s)", reason);
return -1;
}
if (buf[0] != checkVer)
{
WLog_ERR(TAG, "SOCKS Proxy version is not 5 (%s)", reason);
return -1;
}
return status;
}
static BOOL socks_proxy_userpass(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword)
{
WINPR_ASSERT(context);
WINPR_ASSERT(bufferedBio);
if (!proxyUsername || !proxyPassword)
{
WLog_ERR(TAG, "%s invalid username (%p) or password (%p)", logprefix,
WINPR_CXX_COMPAT_CAST(const void*, proxyUsername),
WINPR_CXX_COMPAT_CAST(const void*, proxyPassword));
return FALSE;
}
const size_t usernameLen = (BYTE)strnlen(proxyUsername, 256);
if (usernameLen > 255)
{
WLog_ERR(TAG, "%s username too long (%" PRIuz ", max=255)", logprefix, usernameLen);
return FALSE;
}
const size_t userpassLen = (BYTE)strnlen(proxyPassword, 256);
if (userpassLen > 255)
{
WLog_ERR(TAG, "%s password too long (%" PRIuz ", max=255)", logprefix, userpassLen);
return FALSE;
}
/* user/password v1 method */
{
BYTE buf[2 * 255 + 3] = WINPR_C_ARRAY_INIT;
size_t offset = 0;
buf[offset++] = 1;
buf[offset++] = WINPR_ASSERTING_INT_CAST(uint8_t, usernameLen);
memcpy(&buf[offset], proxyUsername, usernameLen);
offset += usernameLen;
buf[offset++] = WINPR_ASSERTING_INT_CAST(uint8_t, userpassLen);
memcpy(&buf[offset], proxyPassword, userpassLen);
offset += userpassLen;
ERR_clear_error();
const int ioffset = WINPR_ASSERTING_INT_CAST(int, offset);
const int status = BIO_write(bufferedBio, buf, ioffset);
if (status != ioffset)
{
WLog_ERR(TAG, "%s error writing user/password request", logprefix);
return FALSE;
}
}
BYTE buf[2] = WINPR_C_ARRAY_INIT;
const int status = recv_socks_reply(context, bufferedBio, buf, sizeof(buf), "AUTH REQ", 1);
if (status < 2)
return FALSE;
if (buf[1] != 0x00)
{
WLog_ERR(TAG, "%s invalid user/password", logprefix);
return FALSE;
}
return TRUE;
}
static BOOL socks_proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port)
{
BYTE nauthMethods = 1;
const size_t hostnlen = strnlen(hostname, 255);
if (proxyUsername || proxyPassword)
nauthMethods++;
/* select auth. method */
{
const BYTE buf[] = { 5, /* SOCKS version */
nauthMethods, /* #of methods offered */
AUTH_M_NO_AUTH, AUTH_M_USR_PASS };
size_t writeLen = sizeof(buf);
if (nauthMethods <= 1)
writeLen--;
ERR_clear_error();
const int iwriteLen = WINPR_ASSERTING_INT_CAST(int, writeLen);
const int status = BIO_write(bufferedBio, buf, iwriteLen);
if (status != iwriteLen)
{
WLog_ERR(TAG, "%s SOCKS proxy: failed to write AUTH METHOD request", logprefix);
return FALSE;
}
}
{
BYTE buf[2] = WINPR_C_ARRAY_INIT;
const int status = recv_socks_reply(context, bufferedBio, buf, sizeof(buf), "AUTH REQ", 5);
if (status <= 0)
return FALSE;
switch (buf[1])
{
case AUTH_M_NO_AUTH:
WLog_DBG(TAG, "%s (NO AUTH) method was selected", logprefix);
break;
case AUTH_M_USR_PASS:
if (nauthMethods < 2)
{
WLog_ERR(TAG, "%s USER/PASS method was not proposed to server", logprefix);
return FALSE;
}
if (!socks_proxy_userpass(context, bufferedBio, proxyUsername, proxyPassword))
return FALSE;
break;
default:
WLog_ERR(TAG, "%s unknown method 0x%x was selected by proxy", logprefix, buf[1]);
return FALSE;
}
}
/* CONN request */
{
BYTE buf[262] = WINPR_C_ARRAY_INIT;
size_t offset = 0;
buf[offset++] = 5; /* SOCKS version */
buf[offset++] = SOCKS_CMD_CONNECT; /* command */
buf[offset++] = 0; /* 3rd octet is reserved x00 */
if (inet_pton(AF_INET6, hostname, &buf[offset + 1]) == 1)
{
buf[offset++] = SOCKS_ADDR_IPV6;
offset += 16;
}
else if (inet_pton(AF_INET, hostname, &buf[offset + 1]) == 1)
{
buf[offset++] = SOCKS_ADDR_IPV4;
offset += 4;
}
else
{
buf[offset++] = SOCKS_ADDR_FQDN;
buf[offset++] = WINPR_ASSERTING_INT_CAST(uint8_t, hostnlen);
memcpy(&buf[offset], hostname, hostnlen);
offset += hostnlen;
}
if (offset > sizeof(buf) - 2)
return FALSE;
/* follows DST.PORT in netw. format */
buf[offset++] = (port >> 8) & 0xff;
buf[offset++] = port & 0xff;
ERR_clear_error();
const int ioffset = WINPR_ASSERTING_INT_CAST(int, offset);
const int status = BIO_write(bufferedBio, buf, ioffset);
if ((status < 0) || (status != ioffset))
{
WLog_ERR(TAG, "%s SOCKS proxy: failed to write CONN REQ", logprefix);
return FALSE;
}
}
BYTE buf[255] = WINPR_C_ARRAY_INIT;
const int status = recv_socks_reply(context, bufferedBio, buf, sizeof(buf), "CONN REQ", 5);
if (status < 4)
return FALSE;
if (buf[1] == 0)
{
WLog_INFO(TAG, "Successfully connected to %s:%" PRIu16, hostname, port);
return TRUE;
}
if ((buf[1] > 0) && (buf[1] < 9))
WLog_INFO(TAG, "SOCKS Proxy replied: %s", rplstat[buf[1]]);
else
WLog_INFO(TAG, "SOCKS Proxy replied: %" PRIu8 " status not listed in rfc1928", buf[1]);
return FALSE;
}

View File

@@ -0,0 +1,35 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* HTTP proxy support
*
* Copyright 2014 Christian Plattner <ccpp@gmx.at>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_HTTP_PROXY_H
#define FREERDP_LIB_CORE_HTTP_PROXY_H
#include "freerdp/settings.h"
#include <openssl/bio.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL proxy_prepare(rdpSettings* settings, const char** lpPeerHostname,
UINT16* lpPeerPort, const char** lpProxyUsername,
const char** lpProxyPassword);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL proxy_connect(rdpContext* context, BIO* bio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port);
#endif /* FREERDP_LIB_CORE_HTTP_PROXY_H */

3155
third_party/FreeRDP/libfreerdp/core/rdp.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,367 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Core
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_RDP_H
#define FREERDP_LIB_CORE_RDP_H
#include <winpr/json.h>
#include <winpr/stream.h>
#include <winpr/crypto.h>
#include <freerdp/config.h>
#include <freerdp/api.h>
#include <freerdp/license.h>
#include <freerdp/freerdp.h>
#include <freerdp/settings.h>
#include <freerdp/log.h>
#include "nla.h"
#include "aad.h"
#include "mcs.h"
#include "tpkt.h"
#include "../codec/bulk.h"
#include "fastpath.h"
#include "tpdu.h"
#include "nego.h"
#include "input.h"
#include "update.h"
#include "license.h"
#include "errinfo.h"
#include "autodetect.h"
#include "heartbeat.h"
#include "multitransport.h"
#include "security.h"
#include "transport.h"
#include "connection.h"
#include "redirection.h"
#include "capabilities.h"
#include "channels.h"
#include "timer.h"
/* Security Header Flags */
#define SEC_EXCHANGE_PKT 0x0001
#define SEC_TRANSPORT_REQ 0x0002
#define SEC_TRANSPORT_RSP 0x0004
#define SEC_ENCRYPT 0x0008
#define SEC_RESET_SEQNO 0x0010
#define SEC_IGNORE_SEQNO 0x0020
#define SEC_INFO_PKT 0x0040
#define SEC_LICENSE_PKT 0x0080
#define SEC_LICENSE_ENCRYPT_CS 0x0200
#define SEC_LICENSE_ENCRYPT_SC 0x0200
#define SEC_REDIRECTION_PKT 0x0400
#define SEC_SECURE_CHECKSUM 0x0800
#define SEC_AUTODETECT_REQ 0x1000
#define SEC_AUTODETECT_RSP 0x2000
#define SEC_HEARTBEAT 0x4000
#define SEC_FLAGSHI_VALID 0x8000
#define SEC_PKT_CS_MASK (SEC_EXCHANGE_PKT | SEC_INFO_PKT)
#define SEC_PKT_SC_MASK (SEC_LICENSE_PKT | SEC_REDIRECTION_PKT)
#define SEC_PKT_MASK (SEC_PKT_CS_MASK | SEC_PKT_SC_MASK)
#define RDP_SECURITY_HEADER_LENGTH 4
#define RDP_SHARE_CONTROL_HEADER_LENGTH 6
#define RDP_SHARE_DATA_HEADER_LENGTH 12
#define RDP_PACKET_HEADER_MAX_LENGTH (TPDU_DATA_LENGTH + MCS_SEND_DATA_HEADER_MAX_LENGTH)
#define PDU_TYPE_DEMAND_ACTIVE 0x1
#define PDU_TYPE_CONFIRM_ACTIVE 0x3
#define PDU_TYPE_DEACTIVATE_ALL 0x6
#define PDU_TYPE_DATA 0x7
#define PDU_TYPE_SERVER_REDIRECTION 0xA
#define PDU_TYPE_FLOW_TEST 0x41
#define PDU_TYPE_FLOW_RESPONSE 0x42
#define PDU_TYPE_FLOW_STOP 0x43
typedef enum
{
FINALIZE_SC_SYNCHRONIZE_PDU = 0x01,
FINALIZE_SC_CONTROL_COOPERATE_PDU = 0x02,
FINALIZE_SC_CONTROL_GRANTED_PDU = 0x04,
FINALIZE_SC_FONT_MAP_PDU = 0x08,
FINALIZE_CS_SYNCHRONIZE_PDU = 0x10,
FINALIZE_CS_CONTROL_COOPERATE_PDU = 0x20,
FINALIZE_CS_CONTROL_REQUEST_PDU = 0x40,
FINALIZE_CS_PERSISTENT_KEY_LIST_PDU = 0x80,
FINALIZE_CS_FONT_LIST_PDU = 0x100,
FINALIZE_DEACTIVATE_REACTIVATE = 0x200
} rdpFinalizePduType;
/* Data PDU Types */
typedef enum
{
DATA_PDU_TYPE_UPDATE = 0x02,
DATA_PDU_TYPE_CONTROL = 0x14,
DATA_PDU_TYPE_POINTER = 0x1B,
DATA_PDU_TYPE_INPUT = 0x1C,
DATA_PDU_TYPE_SYNCHRONIZE = 0x1F,
DATA_PDU_TYPE_REFRESH_RECT = 0x21,
DATA_PDU_TYPE_PLAY_SOUND = 0x22,
DATA_PDU_TYPE_SUPPRESS_OUTPUT = 0x23,
DATA_PDU_TYPE_SHUTDOWN_REQUEST = 0x24,
DATA_PDU_TYPE_SHUTDOWN_DENIED = 0x25,
DATA_PDU_TYPE_SAVE_SESSION_INFO = 0x26,
DATA_PDU_TYPE_FONT_LIST = 0x27,
DATA_PDU_TYPE_FONT_MAP = 0x28,
DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS = 0x29,
DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST = 0x2B,
DATA_PDU_TYPE_BITMAP_CACHE_ERROR = 0x2C,
DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS = 0x2D,
DATA_PDU_TYPE_OFFSCREEN_CACHE_ERROR = 0x2E,
DATA_PDU_TYPE_SET_ERROR_INFO = 0x2F,
DATA_PDU_TYPE_DRAW_NINEGRID_ERROR = 0x30,
DATA_PDU_TYPE_DRAW_GDIPLUS_ERROR = 0x31,
DATA_PDU_TYPE_ARC_STATUS = 0x32,
DATA_PDU_TYPE_STATUS_INFO = 0x36,
DATA_PDU_TYPE_MONITOR_LAYOUT = 0x37,
DATA_PDU_TYPE_FRAME_ACKNOWLEDGE = 0x38
} rdpPduType;
/* Stream Identifiers */
#define STREAM_UNDEFINED 0x00
#define STREAM_LOW 0x01
#define STREAM_MED 0x02
#define STREAM_HI 0x04
struct rdp_rdp
{
CONNECTION_STATE state;
rdpContext* context;
rdpNla* nla;
rdpAad* aad;
rdpMcs* mcs;
rdpNego* nego;
rdpBulk* bulk;
rdpInput* input;
rdpUpdate* update;
rdpFastPath* fastpath;
rdpLicense* license;
rdpRedirection* redirection;
rdpSettings* settings;
rdpSettings* originalSettings;
rdpSettings* remoteSettings;
rdpTransport* transport;
rdpAutoDetect* autodetect;
rdpHeartbeat* heartbeat;
rdpMultitransport* multitransport;
WINPR_RC4_CTX* rc4_decrypt_key;
UINT32 decrypt_use_count;
UINT32 decrypt_checksum_use_count;
WINPR_RC4_CTX* rc4_encrypt_key;
UINT32 encrypt_use_count;
UINT32 encrypt_checksum_use_count;
WINPR_CIPHER_CTX* fips_encrypt;
WINPR_CIPHER_CTX* fips_decrypt;
BOOL do_crypt;
BOOL do_crypt_license;
BOOL do_secure_checksum;
BYTE sign_key[16];
BYTE decrypt_key[16];
BYTE encrypt_key[16];
BYTE decrypt_update_key[16];
BYTE encrypt_update_key[16];
size_t rc4_key_len;
BYTE fips_sign_key[20];
BYTE fips_encrypt_key[24];
BYTE fips_decrypt_key[24];
UINT32 errorInfo;
UINT32 finalize_sc_pdus;
BOOL resendFocus;
UINT64 inBytes;
UINT64 inPackets;
UINT64 outBytes;
UINT64 outPackets;
CRITICAL_SECTION critical;
rdpTransportIo* io;
void* ioContext;
HANDLE abortEvent;
wPubSub* pubSub;
BOOL monitor_layout_pdu;
BOOL was_deactivated;
UINT32 deactivated_width;
UINT32 deactivated_height;
wLog* log;
char log_context[64];
WINPR_JSON* wellknown;
FreeRDPTimer* timer;
WINPR_ATTR_NODISCARD pGetCommonAccessToken GetCommonAccessToken;
};
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_read_security_header(rdpRdp* rdp, wStream* s, UINT16* flags, UINT16* length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_write_security_header(rdpRdp* rdp, wStream* s, UINT16 flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_read_share_control_header(rdpRdp* rdp, wStream* s, UINT16* tpktLength,
UINT16* remainingLength, UINT16* type,
UINT16* channel_id);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_read_share_data_header(rdpRdp* rdp, wStream* s, UINT16* length, BYTE* type,
UINT32* shareId, BYTE* compressedType,
UINT16* compressedLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send(rdpRdp* rdp, wStream* s, UINT16 channelId, UINT16 sec_flags);
WINPR_ATTR_MALLOC(rdp_send, 2)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* rdp_send_stream_init(rdpRdp* rdp, UINT16* sec_flags);
WINPR_ATTR_MALLOC(Stream_Release, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* rdp_send_stream_pdu_init(rdpRdp* rdp, UINT16* sec_flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_write_header(rdpRdp* rdp, wStream* s, size_t length, UINT16 channelId,
UINT16 sec_flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_pdu(rdpRdp* rdp, wStream* s, UINT16 type, UINT16 channel_id,
UINT16 sec_flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_data_pdu(rdpRdp* rdp, wStream* s, BYTE type, UINT16 channel_id,
UINT16 sec_flags);
WINPR_ATTR_MALLOC(rdp_send_data_pdu, 2)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* rdp_data_pdu_init(rdpRdp* rdp, UINT16* sec_flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_recv_data_pdu(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_channel_data(rdpRdp* rdp, UINT16 channelId, const BYTE* data,
size_t size);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_channel_send_packet(rdpRdp* rdp, UINT16 channelId, size_t totalSize,
UINT32 flags, const BYTE* data, size_t chunkSize);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_send_message_channel_pdu(rdpRdp* rdp, wStream* s, UINT16 sec_flags);
WINPR_ATTR_MALLOC(rdp_send_message_channel_pdu, 2)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL wStream* rdp_message_channel_pdu_init(rdpRdp* rdp, UINT16* sec_flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_recv_message_channel_pdu(rdpRdp* rdp, wStream* s,
UINT16 securityFlags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s, UINT16 pduType,
UINT16 length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rdp_check_fds(rdpRdp* rdp);
FREERDP_LOCAL void rdp_free(rdpRdp* rdp);
WINPR_ATTR_MALLOC(rdp_free, 1)
FREERDP_LOCAL rdpRdp* rdp_new(rdpContext* context);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_reset(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_io_callback_set_event(rdpRdp* rdp, BOOL reset);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const rdpTransportIo* rdp_get_io_callbacks(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_set_io_callbacks(rdpRdp* rdp, const rdpTransportIo* io_callbacks);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_set_io_callback_context(rdpRdp* rdp, void* usercontext);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL void* rdp_get_io_callback_context(rdpRdp* rdp);
#define RDP_TAG FREERDP_TAG("core.rdp")
#ifdef WITH_DEBUG_RDP
#define DEBUG_RDP(rdp, ...) WLog_Print(rdp->log, WLOG_DEBUG, __VA_ARGS__)
#else
#define DEBUG_RDP(rdp, ...) \
do \
{ \
} while (0)
#endif
WINPR_ATTR_NODISCARD FREERDP_LOCAL const char* data_pdu_type_to_string(UINT8 type);
WINPR_ATTR_NODISCARD FREERDP_LOCAL const char* pdu_type_to_str(UINT16 pduType, char* buffer,
size_t length);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL rdp_finalize_reset_flags(rdpRdp* rdp, BOOL clearAll);
FREERDP_LOCAL BOOL rdp_finalize_set_flag(rdpRdp* rdp, UINT32 flag);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL rdp_finalize_is_flag_set(rdpRdp* rdp, UINT32 flag);
WINPR_ATTR_NODISCARD FREERDP_LOCAL const char* rdp_finalize_flags_to_str(UINT32 flags, char* buffer,
size_t size);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, UINT16* pLength,
UINT16 securityFlags);
FREERDP_LOCAL BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL rdp_send_error_info(rdpRdp* rdp);
void rdp_free_rc4_encrypt_keys(rdpRdp* rdp);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL rdp_reset_rc4_encrypt_keys(rdpRdp* rdp);
void rdp_free_rc4_decrypt_keys(rdpRdp* rdp);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL rdp_reset_rc4_decrypt_keys(rdpRdp* rdp);
WINPR_ATTR_NODISCARD FREERDP_LOCAL const char* rdp_security_flag_string(UINT32 securityFlags,
char* buffer, size_t size);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL rdp_set_backup_settings(rdpRdp* rdp);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL rdp_reset_runtime_settings(rdpRdp* rdp);
FREERDP_LOCAL void rdp_log_build_warnings(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL size_t rdp_get_event_handles(rdpRdp* rdp, HANDLE* handles, uint32_t count);
#endif /* FREERDP_LIB_CORE_RDP_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDSTLS Security protocol
*
* Copyright 2023 Joan Torres <joan.torres@suse.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_RDSTLS_H
#define FREERDP_LIB_CORE_RDSTLS_H
typedef struct rdp_rdstls rdpRdstls;
#include <freerdp/freerdp.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL SSIZE_T rdstls_parse_pdu(wLog* log, wStream* s);
FREERDP_LOCAL void rdstls_free(rdpRdstls* rdstls);
WINPR_ATTR_MALLOC(rdstls_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpRdstls* rdstls_new(rdpContext* context, rdpTransport* transport);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rdstls_authenticate(rdpRdstls* rdstls);
#endif /* FREERDP_LIB_CORE_RDSTLS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,66 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Server Redirection
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_REDIRECTION_H
#define FREERDP_LIB_CORE_REDIRECTION_H
typedef struct rdp_redirection rdpRedirection;
#include "rdp.h"
#include <freerdp/freerdp.h>
#include <freerdp/log.h>
#include <freerdp/api.h>
#include <winpr/wlog.h>
#include <winpr/stream.h>
#define CERT_cert_file_element 32
#define CERT_crl_file_element 33
#define CERT_ctl_file_element 34
#define CERT_keyid_file_element 35
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rdp_redirection_apply_settings(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL state_run_t rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL
rdp_write_enhanced_security_redirection_packet(wStream* s, const rdpRedirection* redirection);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_redirection_read_target_cert(rdpCertificate** ptargetCertificate,
const BYTE* data, size_t length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rdp_set_target_certificate(rdpSettings* settings, const rdpCertificate* tcert);
#define REDIR_TAG FREERDP_TAG("core.redirection")
#ifdef WITH_DEBUG_REDIR
#define DEBUG_REDIR(...) WLog_DBG(REDIR_TAG, __VA_ARGS__)
#else
#define DEBUG_REDIR(...) \
do \
{ \
} while (0)
#endif
#endif /* FREERDP_LIB_CORE_REDIRECTION_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RDP Security
*
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_SECURITY_H
#define FREERDP_LIB_CORE_SECURITY_H
#include "rdp.h"
#include <freerdp/crypto/crypto.h>
#include <freerdp/freerdp.h>
#include <freerdp/api.h>
#include <winpr/stream.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_master_secret(const BYTE* premaster_secret, size_t pre_len,
const BYTE* client_random, size_t client_len,
const BYTE* server_random, size_t server_len,
BYTE* output, size_t out_len);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_session_key_blob(const BYTE* master_secret, size_t master_len,
const BYTE* client_random, size_t client_len,
const BYTE* server_random, size_t server_len,
BYTE* output, size_t out_len);
FREERDP_LOCAL void security_mac_salt_key(const BYTE* session_key_blob, size_t session_len,
const BYTE* client_random, size_t client_len,
const BYTE* server_random, size_t server_len, BYTE* output,
size_t out_len);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_licensing_encryption_key(const BYTE* session_key_blob,
size_t session_len, const BYTE* client_random,
size_t client_len, const BYTE* server_random,
size_t server_len, BYTE* output,
size_t out_len);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_mac_data(const BYTE* mac_salt_key, size_t mac_salt_key_length,
const BYTE* data, size_t length, BYTE* output,
size_t output_length);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32 length,
BYTE* output, size_t out_len);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_salted_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32 length,
BOOL encryption, BYTE* output, size_t out_len);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_establish_keys(rdpRdp* rdp);
FREERDP_LOCAL void security_lock(rdpRdp* rdp);
FREERDP_LOCAL void security_unlock(rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_hmac_signature(const BYTE* data, size_t length, BYTE* output,
size_t out_len, rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_fips_encrypt(BYTE* data, size_t length, rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_fips_decrypt(BYTE* data, size_t length, rdpRdp* rdp);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL security_fips_check_signature(const BYTE* data, size_t length, const BYTE* sig,
size_t sig_len, rdpRdp* rdp);
#endif /* FREERDP_LIB_CORE_SECURITY_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,404 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Server Channels
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Copyright 2015 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_SERVER_H
#define FREERDP_LIB_CORE_SERVER_H
#include <freerdp/freerdp.h>
#include <freerdp/api.h>
#include <freerdp/channels/wtsvc.h>
#include <winpr/synch.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
typedef struct rdp_peer_channel rdpPeerChannel;
typedef struct WTSVirtualChannelManager WTSVirtualChannelManager;
#include "rdp.h"
#include "mcs.h"
enum
{
RDP_PEER_CHANNEL_TYPE_SVC = 0,
RDP_PEER_CHANNEL_TYPE_DVC = 1
};
enum
{
DVC_OPEN_STATE_NONE = 0,
DVC_OPEN_STATE_SUCCEEDED = 1,
DVC_OPEN_STATE_FAILED = 2,
DVC_OPEN_STATE_CLOSED = 3
};
struct rdp_peer_channel
{
WTSVirtualChannelManager* vcm;
freerdp_peer* client;
void* extra;
UINT16 index;
UINT32 channelId;
UINT16 channelType;
UINT32 channelFlags;
wStream* receiveData;
wMessageQueue* queue;
BYTE dvc_open_state;
INT32 creationStatus;
UINT32 dvc_total_length;
rdpMcsChannel* mcsChannel;
char channelName[128];
CRITICAL_SECTION writeLock;
};
struct WTSVirtualChannelManager
{
rdpRdp* rdp;
freerdp_peer* client;
DWORD SessionId;
wMessageQueue* queue;
rdpPeerChannel* drdynvc_channel;
BYTE drdynvc_state;
LONG dvc_channel_id_seq;
UINT16 dvc_spoken_version;
WINPR_ATTR_NODISCARD psDVCCreationStatusCallback dvc_creation_status;
void* dvc_creation_status_userdata;
wHashTable* dynamicVirtualChannels;
};
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionW(LPWSTR pTargetServerName,
ULONG TargetLogonId, BYTE HotkeyVk,
USHORT HotkeyModifiers);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionA(LPSTR pTargetServerName,
ULONG TargetLogonId, BYTE HotkeyVk,
USHORT HotkeyModifiers);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExW(LPWSTR pTargetServerName,
ULONG TargetLogonId,
BYTE HotkeyVk,
USHORT HotkeyModifiers,
DWORD flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionExA(LPSTR pTargetServerName,
ULONG TargetLogonId,
BYTE HotkeyVk,
USHORT HotkeyModifiers,
DWORD flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSStopRemoteControlSession(ULONG LogonId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSConnectSessionW(ULONG LogonId, ULONG TargetLogonId,
PWSTR pPassword, BOOL bWait);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSConnectSessionA(ULONG LogonId, ULONG TargetLogonId,
PSTR pPassword, BOOL bWait);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved,
DWORD Version,
PWTS_SERVER_INFOW* ppServerInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateServersA(LPSTR pDomainName, DWORD Reserved,
DWORD Version,
PWTS_SERVER_INFOA* ppServerInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HANDLE WINAPI FreeRDP_WTSOpenServerW(LPWSTR pServerName);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HANDLE WINAPI FreeRDP_WTSOpenServerA(LPSTR pServerName);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HANDLE WINAPI FreeRDP_WTSOpenServerExW(LPWSTR pServerName);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HANDLE WINAPI FreeRDP_WTSOpenServerExA(LPSTR pServerName);
FREERDP_LOCAL VOID WINAPI FreeRDP_WTSCloseServer(HANDLE hServer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved,
DWORD Version,
PWTS_SESSION_INFOW* ppSessionInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved,
DWORD Version,
PWTS_SESSION_INFOA* ppSessionInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateSessionsExW(HANDLE hServer, DWORD* pLevel,
DWORD Filter,
PWTS_SESSION_INFO_1W* ppSessionInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateSessionsExA(HANDLE hServer, DWORD* pLevel,
DWORD Filter,
PWTS_SESSION_INFO_1A* ppSessionInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved,
DWORD Version,
PWTS_PROCESS_INFOW* ppProcessInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved,
DWORD Version,
PWTS_PROCESS_INFOA* ppProcessInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSTerminateProcess(HANDLE hServer, DWORD ProcessId,
DWORD ExitCode);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSQuerySessionInformationW(HANDLE hServer, DWORD SessionId,
WTS_INFO_CLASS WTSInfoClass,
LPWSTR* ppBuffer,
DWORD* pBytesReturned);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSQuerySessionInformationA(HANDLE hServer, DWORD SessionId,
WTS_INFO_CLASS WTSInfoClass,
LPSTR* ppBuffer,
DWORD* pBytesReturned);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSQueryUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
WTS_CONFIG_CLASS WTSConfigClass,
LPWSTR* ppBuffer, DWORD* pBytesReturned);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSQueryUserConfigA(LPSTR pServerName, LPSTR pUserName,
WTS_CONFIG_CLASS WTSConfigClass,
LPSTR* ppBuffer, DWORD* pBytesReturned);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSSetUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
WTS_CONFIG_CLASS WTSConfigClass, LPWSTR pBuffer,
DWORD DataLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSSetUserConfigA(LPSTR pServerName, LPSTR pUserName,
WTS_CONFIG_CLASS WTSConfigClass, LPSTR pBuffer,
DWORD DataLength);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSSendMessageW(HANDLE hServer, DWORD SessionId, LPWSTR pTitle,
DWORD TitleLength, LPWSTR pMessage,
DWORD MessageLength, DWORD Style, DWORD Timeout,
DWORD* pResponse, BOOL bWait);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSSendMessageA(HANDLE hServer, DWORD SessionId, LPSTR pTitle,
DWORD TitleLength, LPSTR pMessage,
DWORD MessageLength, DWORD Style, DWORD Timeout,
DWORD* pResponse, BOOL bWait);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSLogoffSession(HANDLE hServer, DWORD SessionId, BOOL bWait);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSShutdownSystem(HANDLE hServer, DWORD ShutdownFlag);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSWaitSystemEvent(HANDLE hServer, DWORD EventMask,
DWORD* pEventFlags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId,
LPSTR pVirtualName);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName,
DWORD flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSVirtualChannelClose(HANDLE hChannelHandle);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut,
PCHAR Buffer, ULONG BufferSize,
PULONG pBytesRead);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer,
ULONG Length, PULONG pBytesWritten);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSVirtualChannelQuery(HANDLE hChannelHandle,
WTS_VIRTUAL_CLASS WtsVirtualClass,
PVOID* ppBuffer, DWORD* pBytesReturned);
FREERDP_LOCAL VOID WINAPI FreeRDP_WTSFreeMemory(PVOID pMemory);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
ULONG NumberOfEntries);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
ULONG NumberOfEntries);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotification(HWND hWnd);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd,
DWORD dwFlags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSUnRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSQueryUserToken(ULONG SessionId, PHANDLE phToken);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateProcessesExW(HANDLE hServer, DWORD* pLevel,
DWORD SessionId, LPWSTR* ppProcessInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateProcessesExA(HANDLE hServer, DWORD* pLevel,
DWORD SessionId, LPSTR* ppProcessInfo,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateListenersW(HANDLE hServer, PVOID pReserved,
DWORD Reserved,
PWTSLISTENERNAMEW pListeners,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSEnumerateListenersA(HANDLE hServer, PVOID pReserved,
DWORD Reserved,
PWTSLISTENERNAMEA pListeners,
DWORD* pCount);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSQueryListenerConfigW(HANDLE hServer, PVOID pReserved,
DWORD Reserved, LPWSTR pListenerName,
PWTSLISTENERCONFIGW pBuffer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSQueryListenerConfigA(HANDLE hServer, PVOID pReserved,
DWORD Reserved, LPSTR pListenerName,
PWTSLISTENERCONFIGA pBuffer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSCreateListenerW(HANDLE hServer, PVOID pReserved,
DWORD Reserved, LPWSTR pListenerName,
PWTSLISTENERCONFIGW pBuffer, DWORD flag);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSCreateListenerA(HANDLE hServer, PVOID pReserved,
DWORD Reserved, LPSTR pListenerName,
PWTSLISTENERCONFIGA pBuffer, DWORD flag);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSSetListenerSecurityW(HANDLE hServer, PVOID pReserved,
DWORD Reserved, LPWSTR pListenerName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSSetListenerSecurityA(HANDLE hServer, PVOID pReserved,
DWORD Reserved, LPSTR pListenerName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSGetListenerSecurityW(HANDLE hServer, PVOID pReserved,
DWORD Reserved, LPWSTR pListenerName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength, LPDWORD lpnLengthNeeded);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSGetListenerSecurityA(HANDLE hServer, PVOID pReserved,
DWORD Reserved, LPSTR pListenerName,
SECURITY_INFORMATION SecurityInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength, LPDWORD lpnLengthNeeded);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL CDECL FreeRDP_WTSEnableChildSessions(BOOL bEnable);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL CDECL FreeRDP_WTSIsChildSessionsEnabled(PBOOL pbEnabled);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL CDECL FreeRDP_WTSGetChildSessionId(PULONG pSessionId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL DWORD WINAPI FreeRDP_WTSGetActiveConsoleSessionId(void);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSLogoffUser(HANDLE hServer);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL WINAPI FreeRDP_WTSLogonUser(HANDLE hServer, LPCSTR username, LPCSTR password,
LPCSTR domain);
FREERDP_LOCAL void server_channel_common_free(rdpPeerChannel*);
WINPR_ATTR_MALLOC(server_channel_common_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpPeerChannel* server_channel_common_new(freerdp_peer* client, UINT16 index,
UINT32 channelId, size_t chunkSize,
const wObject* callback, const char* name);
#endif /* FREERDP_LIB_CORE_SERVER_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Internal settings header for functions not exported
*
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
* Copyright 2018 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_LIB_CORE_SETTINGS_H
#define FREERDP_LIB_CORE_SETTINGS_H
#include <winpr/string.h>
#include <winpr/sspi.h>
#include <freerdp/config.h>
#define FREERDP_SETTINGS_INTERNAL_USE
#include <freerdp/settings_types_private.h>
#include <freerdp/types.h>
#include <freerdp/settings.h>
#include <freerdp/api.h>
#include <string.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_settings_enforce_consistency(rdpSettings* settings);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_settings_enforce_monitor_exists(rdpSettings* settings);
FREERDP_LOCAL void freerdp_settings_print_warnings(const rdpSettings* settings);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_settings_check_client_after_preconnect(const rdpSettings* settings);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_settings_set_default_order_support(rdpSettings* settings);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_settings_clone_keys(rdpSettings* dst, const rdpSettings* src);
FREERDP_LOCAL void freerdp_settings_free_keys(rdpSettings* dst, BOOL cleanup);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_settings_set_string_(rdpSettings* settings,
FreeRDP_Settings_Keys_String id, const char* val,
size_t len);
FREERDP_LOCAL BOOL freerdp_settings_set_string_copy_(rdpSettings* settings,
FreeRDP_Settings_Keys_String id,
const char* val, size_t len, BOOL cleanup);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_capability_buffer_resize(rdpSettings* settings, size_t count,
BOOL force);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL identity_set_from_settings_with_pwd(SEC_WINNT_AUTH_IDENTITY_W* identity,
const rdpSettings* settings,
FreeRDP_Settings_Keys_String UserId,
FreeRDP_Settings_Keys_String DomainId,
const WCHAR* Password, size_t pwdLen);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL identity_set_from_settings(SEC_WINNT_AUTH_IDENTITY_W* identity,
const rdpSettings* settings,
FreeRDP_Settings_Keys_String UserId,
FreeRDP_Settings_Keys_String DomainId,
FreeRDP_Settings_Keys_String PwdId);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL identity_set_from_smartcard_hash(SEC_WINNT_AUTH_IDENTITY_W* identity,
const rdpSettings* settings,
FreeRDP_Settings_Keys_String userId,
FreeRDP_Settings_Keys_String domainId,
FreeRDP_Settings_Keys_String pwdId,
const BYTE* certSha1, size_t sha1len);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* freerdp_settings_glyph_level_string(UINT32 level, char* buffer,
size_t size);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_settings_set_pointer_len_(rdpSettings* settings,
FreeRDP_Settings_Keys_Pointer id,
FreeRDP_Settings_Keys_UInt32 lenId,
const void* data, size_t len, size_t size);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_target_net_adresses_reset(rdpSettings* settings, size_t size);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_target_net_addresses_resize(rdpSettings* settings, size_t count);
#endif /* FREERDP_LIB_CORE_SETTINGS_H */

View File

@@ -0,0 +1,43 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* SIMD support detection header
*
* Copyright 2024 Armin Novak <anovak@thincast.com>
* Copyright 2024 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <freerdp/config.h>
#include <freerdp/log.h>
#define PRIM_TAG FREERDP_TAG("primitives")
/* https://sourceforge.net/p/predef/wiki/Architectures/
*
* contains a list of defined symbols for each compiler
*/
#if defined(WITH_SIMD)
#if defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64) || defined(_M_IX86_AMD64) || \
defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || \
defined(__i686__) || defined(__ia64__)
#define SSE_AVX_INTRINSICS_ENABLED
#endif
// Inspired by llvm arm_neon.h header checks
#if defined(__ARM_NEON) && defined(__ARM_FP)
#define NEON_INTRINSICS_ENABLED
#endif
#endif

View File

@@ -0,0 +1,959 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Logging in with smartcards
*
* Copyright 2022 David Fort <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <winpr/error.h>
#include <winpr/ncrypt.h>
#include <winpr/string.h>
#include <winpr/wlog.h>
#include <winpr/crypto.h>
#include <winpr/path.h>
#include <freerdp/log.h>
#include <freerdp/freerdp.h>
#include <winpr/print.h>
#include <freerdp/utils/smartcardlogon.h>
#include <freerdp/crypto/crypto.h>
#include <freerdp/utils/helpers.h>
#include <openssl/obj_mac.h>
#define TAG FREERDP_TAG("smartcardlogon")
struct SmartcardKeyInfo_st
{
char* certPath;
char* keyPath;
};
static void delete_file(char* path)
{
if (!path)
return;
/* Overwrite data in files before deletion */
{
FILE* fp = winpr_fopen(path, "r+");
if (fp)
{
const char buffer[8192] = WINPR_C_ARRAY_INIT;
INT64 size = 0;
int rs = _fseeki64(fp, 0, SEEK_END);
if (rs == 0)
size = _ftelli64(fp);
(void)_fseeki64(fp, 0, SEEK_SET);
for (INT64 x = 0; x < size; x += sizeof(buffer))
{
const size_t dnmemb = (size_t)(size - x);
const size_t nmemb = MIN(sizeof(buffer), dnmemb);
const size_t count = fwrite(buffer, nmemb, 1, fp);
if (count != 1)
break;
}
(void)fclose(fp);
}
}
winpr_DeleteFile(path);
free(path);
}
static void smartcardKeyInfo_Free(SmartcardKeyInfo* key_info)
{
if (!key_info)
return;
delete_file(key_info->certPath);
delete_file(key_info->keyPath);
free(key_info);
}
void smartcardCertInfo_Free(SmartcardCertInfo* scCert)
{
if (!scCert)
return;
free(scCert->csp);
free(scCert->reader);
freerdp_certificate_free(scCert->certificate);
free(scCert->pkinitArgs);
free(scCert->keyName);
free(scCert->containerName);
free(scCert->upn);
free(scCert->userHint);
free(scCert->domainHint);
free(scCert->subject);
free(scCert->issuer);
smartcardKeyInfo_Free(scCert->key_info);
free(scCert);
}
void smartcardCertList_Free(SmartcardCertInfo** pscCert, size_t count)
{
if (!pscCert)
return;
for (size_t i = 0; i < count; i++)
{
SmartcardCertInfo* cert = pscCert[i];
smartcardCertInfo_Free(cert);
}
free((void*)pscCert);
}
static BOOL add_cert_to_list(SmartcardCertInfo*** certInfoList, size_t* count,
SmartcardCertInfo* certInfo)
{
size_t curCount = *count;
SmartcardCertInfo** curInfoList = *certInfoList;
/* Check if the certificate is already in the list */
for (size_t i = 0; i < curCount; ++i)
{
if (_wcscmp(curInfoList[i]->containerName, certInfo->containerName) == 0)
{
smartcardCertInfo_Free(certInfo);
return TRUE;
}
}
{
SmartcardCertInfo** tmpInfoList = (SmartcardCertInfo**)realloc(
(void*)curInfoList, sizeof(SmartcardCertInfo*) * (curCount + 1));
if (!tmpInfoList)
{
WLog_ERR(TAG, "unable to reallocate certs");
return FALSE;
}
curInfoList = tmpInfoList;
}
curInfoList[curCount++] = certInfo;
*certInfoList = curInfoList;
*count = curCount;
return TRUE;
}
static BOOL treat_sc_cert(SmartcardCertInfo* scCert)
{
WINPR_ASSERT(scCert);
scCert->upn = freerdp_certificate_get_upn(scCert->certificate);
if (!scCert->upn)
{
WLog_DBG(TAG, "%s has no UPN, trying emailAddress", scCert->keyName);
scCert->upn = freerdp_certificate_get_email(scCert->certificate);
}
if (scCert->upn)
{
size_t userLen = 0;
const char* atPos = strchr(scCert->upn, '@');
if (!atPos)
{
WLog_ERR(TAG, "invalid UPN, for key %s (no @)", scCert->keyName);
return FALSE;
}
userLen = (size_t)(atPos - scCert->upn);
scCert->userHint = malloc(userLen + 1);
scCert->domainHint = _strdup(atPos + 1);
if (!scCert->userHint || !scCert->domainHint)
{
WLog_ERR(TAG, "error allocating userHint or domainHint, for key %s", scCert->keyName);
return FALSE;
}
memcpy(scCert->userHint, scCert->upn, userLen);
scCert->userHint[userLen] = 0;
}
scCert->subject = freerdp_certificate_get_subject(scCert->certificate);
scCert->issuer = freerdp_certificate_get_issuer(scCert->certificate);
return TRUE;
}
static BOOL set_info_certificate(SmartcardCertInfo* cert, BYTE* certBytes, DWORD cbCertBytes,
const char* userFilter, const char* domainFilter)
{
if (!winpr_Digest(WINPR_MD_SHA1, certBytes, cbCertBytes, cert->sha1Hash,
sizeof(cert->sha1Hash)))
{
WLog_ERR(TAG, "unable to compute certificate sha1 for key %s", cert->keyName);
return FALSE;
}
cert->certificate = freerdp_certificate_new_from_der(certBytes, cbCertBytes);
if (!cert->certificate)
{
WLog_ERR(TAG, "unable to parse X509 certificate for key %s", cert->keyName);
return FALSE;
}
if (!freerdp_certificate_check_eku(cert->certificate, NID_ms_smartcard_login))
{
WLog_DBG(TAG, "discarding certificate without Smartcard Login EKU for key %s",
cert->keyName);
return FALSE;
}
if (!treat_sc_cert(cert))
{
WLog_DBG(TAG, "error treating cert");
return FALSE;
}
if (userFilter && (!cert->upn || (strcmp(cert->upn, userFilter) != 0)))
{
if (cert->userHint && strcmp(cert->userHint, userFilter) != 0)
{
WLog_DBG(TAG, "discarding non matching cert by user %s@%s", cert->userHint,
cert->domainHint);
return FALSE;
}
}
if (domainFilter && cert->domainHint && strcmp(cert->domainHint, domainFilter) != 0)
{
WLog_DBG(TAG, "discarding non matching cert by domain(%s) %s@%s", domainFilter,
cert->userHint, cert->domainHint);
return FALSE;
}
return TRUE;
}
#ifndef _WIN32
static BOOL build_pkinit_args(NCRYPT_PROV_HANDLE provider, SmartcardCertInfo* scCert)
{
/* pkinit args only under windows
* PKCS11:module_name=opensc-pkcs11.so
*/
const char* pkModule = winpr_NCryptGetModulePath(provider);
size_t size = 0;
return (winpr_asprintf(&scCert->pkinitArgs, &size, "PKCS11:module_name=%s:slotid=%" PRIu16,
pkModule, (UINT16)scCert->slotId) > 0);
}
#endif /* _WIN32 */
#ifdef _WIN32
static BOOL list_capi_provider_keys(const rdpSettings* settings, LPCWSTR csp, LPCWSTR scope,
const char* userFilter, const char* domainFilter,
SmartcardCertInfo*** pcerts, size_t* pcount)
{
BOOL ret = FALSE;
HCRYPTKEY hKey = 0;
HCRYPTPROV hProvider = 0;
SmartcardCertInfo* cert = nullptr;
BYTE* certBytes = nullptr;
CHAR* readerName = nullptr;
if (!CryptAcquireContextW(&hProvider, scope, csp, PROV_RSA_FULL, CRYPT_SILENT))
{
WLog_DBG(TAG, "Unable to acquire context: %d", GetLastError());
goto out;
}
cert = calloc(1, sizeof(SmartcardCertInfo));
if (!cert)
goto out;
cert->csp = _wcsdup(csp);
if (!cert->csp)
goto out;
/* ====== retrieve key's reader ====== */
DWORD dwDataLen = 0;
if (!CryptGetProvParam(hProvider, PP_SMARTCARD_READER, nullptr, &dwDataLen, 0))
{
WLog_DBG(TAG, "Unable to get provider param: %d", GetLastError());
goto out;
}
readerName = malloc(dwDataLen);
if (!readerName)
goto out;
if (!CryptGetProvParam(hProvider, PP_SMARTCARD_READER, readerName, &dwDataLen, 0))
{
WLog_DBG(TAG, "Unable to get reader name: %d", GetLastError());
goto out;
}
cert->reader = ConvertUtf8ToWCharAlloc(readerName, nullptr);
if (!cert->reader)
goto out;
/* ====== retrieve key container name ====== */
dwDataLen = 0;
if (!CryptGetProvParam(hProvider, PP_CONTAINER, nullptr, &dwDataLen, 0))
{
WLog_DBG(TAG, "Unable to get provider param: %d", GetLastError());
goto out;
}
cert->keyName = malloc(dwDataLen);
if (!cert->keyName)
goto out;
if (!CryptGetProvParam(hProvider, PP_CONTAINER, cert->keyName, &dwDataLen, 0))
{
WLog_DBG(TAG, "Unable to get container name: %d", GetLastError());
goto out;
}
cert->containerName = ConvertUtf8ToWCharAlloc(cert->keyName, nullptr);
if (!cert->containerName)
goto out;
/* ========= retrieve the certificate ===============*/
if (!CryptGetUserKey(hProvider, AT_KEYEXCHANGE, &hKey))
{
WLog_DBG(TAG, "Unable to get user key for %s: %d", cert->keyName, GetLastError());
goto out;
}
dwDataLen = 0;
if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, nullptr, &dwDataLen, 0))
{
WLog_DBG(TAG, "Unable to get key param for key %s: %d", cert->keyName, GetLastError());
goto out;
}
certBytes = malloc(dwDataLen);
if (!certBytes)
{
WLog_ERR(TAG, "unable to allocate %" PRIu32 " certBytes for key %s", dwDataLen,
cert->keyName);
goto out;
}
if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, certBytes, &dwDataLen, 0))
{
WLog_ERR(TAG, "unable to retrieve certificate for key %s", cert->keyName);
goto out;
}
if (!set_info_certificate(cert, certBytes, dwDataLen, userFilter, domainFilter))
goto out;
if (!add_cert_to_list(pcerts, pcount, cert))
goto out;
ret = TRUE;
out:
free(readerName);
free(certBytes);
if (hKey)
CryptDestroyKey(hKey);
if (hProvider)
CryptReleaseContext(hProvider, 0);
if (!ret)
smartcardCertInfo_Free(cert);
return ret;
}
#endif /* _WIN32 */
static BOOL list_provider_keys(WINPR_ATTR_UNUSED const rdpSettings* settings,
NCRYPT_PROV_HANDLE provider, LPCWSTR csp, LPCWSTR scope,
const char* userFilter, const char* domainFilter,
SmartcardCertInfo*** pcerts, size_t* pcount)
{
BOOL ret = FALSE;
NCryptKeyName* keyName = nullptr;
PVOID enumState = nullptr;
SmartcardCertInfo** cert_list = *pcerts;
size_t count = *pcount;
while (NCryptEnumKeys(provider, scope, &keyName, &enumState, NCRYPT_SILENT_FLAG) ==
ERROR_SUCCESS)
{
NCRYPT_KEY_HANDLE phKey = 0;
PBYTE certBytes = nullptr;
DWORD dwFlags = NCRYPT_SILENT_FLAG;
DWORD cbOutput = 0;
SmartcardCertInfo* cert = nullptr;
BOOL haveError = TRUE;
SECURITY_STATUS status = 0;
cert = calloc(1, sizeof(SmartcardCertInfo));
if (!cert)
goto out;
cert->keyName = ConvertWCharToUtf8Alloc(keyName->pszName, nullptr);
if (!cert->keyName)
goto endofloop;
WLog_DBG(TAG, "opening key %s", cert->keyName);
status =
NCryptOpenKey(provider, &phKey, keyName->pszName, keyName->dwLegacyKeySpec, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_DBG(TAG,
"unable to NCryptOpenKey(dwLegacyKeySpec=0x%08" PRIx32 " dwFlags=0x%08" PRIx32
"), status=%s, skipping",
keyName->dwLegacyKeySpec, keyName->dwFlags,
winpr_NCryptSecurityStatusError(status));
goto endofloop;
}
cert->csp = _wcsdup(csp);
if (!cert->csp)
goto endofloop;
#ifndef _WIN32
status = NCryptGetProperty(phKey, NCRYPT_WINPR_SLOTID, (PBYTE)&cert->slotId, 4, &cbOutput,
dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve slotId for key %s, status=%s", cert->keyName,
winpr_NCryptSecurityStatusError(status));
goto endofloop;
}
#endif /* _WIN32 */
/* ====== retrieve key's reader ====== */
cbOutput = 0;
status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, nullptr, 0, &cbOutput, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_DBG(TAG, "unable to retrieve reader's name length for key %s", cert->keyName);
goto endofloop;
}
cert->reader = calloc(1, cbOutput + 2);
if (!cert->reader)
{
WLog_ERR(TAG, "unable to allocate reader's name for key %s", cert->keyName);
goto endofloop;
}
status = NCryptGetProperty(phKey, NCRYPT_READER_PROPERTY, (PBYTE)cert->reader, cbOutput + 2,
&cbOutput, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve reader's name for key %s", cert->keyName);
goto endofloop;
}
/* ====== retrieve key container name ====== */
/* When using PKCS11, this will try to return what Windows would use for the key's name */
cbOutput = 0;
status = NCryptGetProperty(phKey, NCRYPT_NAME_PROPERTY, nullptr, 0, &cbOutput, dwFlags);
if (status == ERROR_SUCCESS)
{
cert->containerName = calloc(1, cbOutput + sizeof(WCHAR));
if (!cert->containerName)
{
WLog_ERR(TAG, "unable to allocate key container name for key %s", cert->keyName);
goto endofloop;
}
status = NCryptGetProperty(phKey, NCRYPT_NAME_PROPERTY, (BYTE*)cert->containerName,
cbOutput, &cbOutput, dwFlags);
}
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve key container name for key %s", cert->keyName);
goto endofloop;
}
/* ========= retrieve the certificate ===============*/
cbOutput = 0;
status =
NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, nullptr, 0, &cbOutput, dwFlags);
if (status != ERROR_SUCCESS)
{
/* can happen that key don't have certificates */
WLog_DBG(TAG, "unable to retrieve certificate property len, status=%s, skipping",
winpr_NCryptSecurityStatusError(status));
goto endofloop;
}
certBytes = calloc(1, cbOutput);
if (!certBytes)
{
WLog_ERR(TAG, "unable to allocate %" PRIu32 " certBytes for key %s", cbOutput,
cert->keyName);
goto endofloop;
}
status = NCryptGetProperty(phKey, NCRYPT_CERTIFICATE_PROPERTY, certBytes, cbOutput,
&cbOutput, dwFlags);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to retrieve certificate for key %s", cert->keyName);
goto endofloop;
}
if (!set_info_certificate(cert, certBytes, cbOutput, userFilter, domainFilter))
goto endofloop;
#ifndef _WIN32
if (!build_pkinit_args(provider, cert))
{
WLog_ERR(TAG, "error build pkinit args");
goto endofloop;
}
#endif
haveError = FALSE;
endofloop:
free(certBytes);
NCryptFreeBuffer(keyName);
if (phKey)
NCryptFreeObject((NCRYPT_HANDLE)phKey);
if (haveError)
smartcardCertInfo_Free(cert);
else
{
if (!add_cert_to_list(&cert_list, &count, cert))
goto out;
}
}
ret = TRUE;
out:
if (count == 0)
{
char cspa[128] = WINPR_C_ARRAY_INIT;
(void)ConvertWCharToUtf8(csp, cspa, sizeof(cspa));
char scopea[128] = WINPR_C_ARRAY_INIT;
(void)ConvertWCharToUtf8(scope, scopea, sizeof(scopea));
WLog_WARN(TAG, "%s [%s] no certificates found", cspa, scopea);
}
*pcount = count;
*pcerts = cert_list;
NCryptFreeBuffer(enumState);
return ret;
}
static BOOL smartcard_hw_enumerateCerts(const rdpSettings* settings, LPCWSTR csp,
const char* reader, const char* userFilter,
const char* domainFilter, SmartcardCertInfo*** scCerts,
size_t* retCount)
{
BOOL ret = FALSE;
LPWSTR scope = nullptr;
NCRYPT_PROV_HANDLE provider = 0;
SECURITY_STATUS status = 0;
size_t count = 0;
SmartcardCertInfo** cert_list = nullptr;
const char* Pkcs11Module = freerdp_settings_get_string(settings, FreeRDP_Pkcs11Module);
WINPR_ASSERT(scCerts);
WINPR_ASSERT(retCount);
if (reader)
{
size_t readerSz = strlen(reader);
char* scopeStr = malloc(4 + readerSz + 1 + 1);
if (!scopeStr)
goto out;
(void)_snprintf(scopeStr, readerSz + 6, "\\\\.\\%s\\", reader);
scope = ConvertUtf8NToWCharAlloc(scopeStr, readerSz + 6, nullptr);
free(scopeStr);
if (!scope)
goto out;
}
if (Pkcs11Module)
{
/* load a unique CSP by pkcs11 module path */
LPCSTR paths[] = { Pkcs11Module, nullptr };
if (!csp)
csp = MS_SCARD_PROV;
status = winpr_NCryptOpenStorageProviderEx(&provider, csp, 0, paths);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "unable to open provider given by pkcs11 module");
goto out;
}
status = list_provider_keys(settings, provider, csp, scope, userFilter, domainFilter,
&cert_list, &count);
NCryptFreeObject((NCRYPT_HANDLE)provider);
if (!status)
{
WLog_ERR(TAG, "error listing keys from CSP loaded from %s", Pkcs11Module);
goto out;
}
}
else
{
NCryptProviderName* names = nullptr;
DWORD nproviders = 0;
#ifdef _WIN32
/* On Windows, mstsc first enumerates the legacy CAPI providers for usable certificates. */
DWORD provType, cbProvName = 0;
for (DWORD i = 0; CryptEnumProvidersW(i, nullptr, 0, &provType, nullptr, &cbProvName); ++i)
{
char providerNameStr[256] = WINPR_C_ARRAY_INIT;
LPWSTR szProvName = malloc(cbProvName * sizeof(WCHAR));
if (!CryptEnumProvidersW(i, nullptr, 0, &provType, szProvName, &cbProvName))
{
free(szProvName);
break;
}
if (ConvertWCharToUtf8(szProvName, providerNameStr, ARRAYSIZE(providerNameStr)) < 0)
{
_snprintf(providerNameStr, sizeof(providerNameStr), "<unknown>");
WLog_ERR(TAG, "unable to convert provider name to char*, will show it as '%s'",
providerNameStr);
}
WLog_DBG(TAG, "exploring CSP '%s'", providerNameStr);
if (provType != PROV_RSA_FULL || (csp && _wcscmp(szProvName, csp) != 0))
{
WLog_DBG(TAG, "CSP '%s' filtered out", providerNameStr);
goto end_of_loop;
}
if (!list_capi_provider_keys(settings, szProvName, scope, userFilter, domainFilter,
&cert_list, &count))
WLog_INFO(TAG, "error when retrieving keys in CSP '%s'", providerNameStr);
end_of_loop:
free(szProvName);
}
#endif
status = NCryptEnumStorageProviders(&nproviders, &names, NCRYPT_SILENT_FLAG);
if (status != ERROR_SUCCESS)
{
WLog_ERR(TAG, "error listing providers");
goto out;
}
for (DWORD i = 0; i < nproviders; i++)
{
char providerNameStr[256] = WINPR_C_ARRAY_INIT;
const NCryptProviderName* name = &names[i];
if (ConvertWCharToUtf8(name->pszName, providerNameStr, ARRAYSIZE(providerNameStr)) < 0)
{
(void)_snprintf(providerNameStr, sizeof(providerNameStr), "<unknown>");
WLog_ERR(TAG, "unable to convert provider name to char*, will show it as '%s'",
providerNameStr);
}
WLog_DBG(TAG, "exploring CSP '%s'", providerNameStr);
if (csp && _wcscmp(name->pszName, csp) != 0)
{
WLog_DBG(TAG, "CSP '%s' filtered out", providerNameStr);
continue;
}
status = NCryptOpenStorageProvider(&provider, name->pszName, 0);
if (status != ERROR_SUCCESS)
continue;
if (!list_provider_keys(settings, provider, name->pszName, scope, userFilter,
domainFilter, &cert_list, &count))
WLog_INFO(TAG, "error when retrieving keys in CSP '%s'", providerNameStr);
NCryptFreeObject((NCRYPT_HANDLE)provider);
}
NCryptFreeBuffer(names);
}
*scCerts = cert_list;
*retCount = count;
ret = TRUE;
out:
if (!ret)
smartcardCertList_Free(cert_list, count);
free(scope);
return ret;
}
static char* create_temporary_file(void)
{
BYTE buffer[32] = WINPR_C_ARRAY_INIT;
char* path = nullptr;
if (winpr_RAND(buffer, sizeof(buffer)) < 0)
return nullptr;
char* hex = winpr_BinToHexString(buffer, sizeof(buffer), FALSE);
if (hex)
path = GetKnownSubPath(KNOWN_PATH_TEMP, hex);
free(hex);
return path;
}
static SmartcardCertInfo* smartcardCertInfo_New(const char* privKeyPEM, const char* certPEM)
{
size_t size = 0;
WINPR_ASSERT(privKeyPEM);
WINPR_ASSERT(certPEM);
SmartcardCertInfo* cert = calloc(1, sizeof(SmartcardCertInfo));
if (!cert)
goto fail;
{
SmartcardKeyInfo* info = cert->key_info = calloc(1, sizeof(SmartcardKeyInfo));
if (!info)
goto fail;
cert->certificate = freerdp_certificate_new_from_pem(certPEM);
if (!cert->certificate)
{
WLog_ERR(TAG, "unable to read smartcard certificate");
goto fail;
}
if (!treat_sc_cert(cert))
{
WLog_ERR(TAG, "unable to treat smartcard certificate");
goto fail;
}
{
char* str = nullptr;
size_t len = 0;
(void)winpr_asprintf(&str, &len, "%s Emulator", freerdp_getApplicationDetailsString());
if (str)
cert->reader = ConvertUtf8NToWCharAlloc(str, len, nullptr);
free(str);
}
if (!cert->reader)
goto fail;
cert->containerName = ConvertUtf8ToWCharAlloc("Private Key 00", nullptr);
if (!cert->containerName)
goto fail;
/* compute PKINIT args FILE:<cert file>,<key file>
*
* We need files for PKINIT to read, so write the certificate to some
* temporary location and use that.
*/
info->keyPath = create_temporary_file();
WLog_DBG(TAG, "writing PKINIT key to %s", info->keyPath);
if (!crypto_write_pem(info->keyPath, privKeyPEM, strlen(privKeyPEM)))
goto fail;
info->certPath = create_temporary_file();
WLog_DBG(TAG, "writing PKINIT cert to %s", info->certPath);
if (!crypto_write_pem(info->certPath, certPEM, strlen(certPEM)))
goto fail;
{
const int res = winpr_asprintf(&cert->pkinitArgs, &size, "FILE:%s,%s", info->certPath,
info->keyPath);
if (res <= 0)
goto fail;
}
}
return cert;
fail:
smartcardCertInfo_Free(cert);
return nullptr;
}
static BOOL smartcard_sw_enumerateCerts(const rdpSettings* settings, SmartcardCertInfo*** scCerts,
size_t* retCount)
{
BOOL rc = FALSE;
SmartcardCertInfo** cert_list = nullptr;
WINPR_ASSERT(settings);
WINPR_ASSERT(scCerts);
WINPR_ASSERT(retCount);
const char* privKeyPEM = freerdp_settings_get_string(settings, FreeRDP_SmartcardPrivateKey);
const char* certPEM = freerdp_settings_get_string(settings, FreeRDP_SmartcardCertificate);
if (!privKeyPEM)
{
WLog_ERR(TAG, "Invalid smartcard private key PEM, aborting");
goto out_error;
}
if (!certPEM)
{
WLog_ERR(TAG, "Invalid smartcard certificate PEM, aborting");
goto out_error;
}
cert_list = (SmartcardCertInfo**)calloc(1, sizeof(SmartcardCertInfo*));
if (!cert_list)
goto out_error;
{
SmartcardCertInfo* cert = smartcardCertInfo_New(privKeyPEM, certPEM);
if (!cert)
goto out_error;
cert_list[0] = cert;
}
rc = TRUE;
*scCerts = cert_list;
*retCount = 1;
out_error:
if (!rc)
smartcardCertList_Free(cert_list, 1);
return rc;
}
BOOL smartcard_enumerateCerts(const rdpSettings* settings, SmartcardCertInfo*** scCerts,
size_t* retCount, BOOL gateway)
{
BOOL ret = 0;
LPWSTR csp = nullptr;
const char* ReaderName = freerdp_settings_get_string(settings, FreeRDP_ReaderName);
const char* CspName = freerdp_settings_get_string(settings, FreeRDP_CspName);
const char* Username = nullptr;
const char* Domain = nullptr;
if (gateway)
{
Username = freerdp_settings_get_string(settings, FreeRDP_GatewayUsername);
Domain = freerdp_settings_get_string(settings, FreeRDP_GatewayDomain);
}
else
{
Username = freerdp_settings_get_string(settings, FreeRDP_Username);
Domain = freerdp_settings_get_string(settings, FreeRDP_Domain);
}
WINPR_ASSERT(settings);
WINPR_ASSERT(scCerts);
WINPR_ASSERT(retCount);
if (Domain && !strlen(Domain))
Domain = nullptr;
if (freerdp_settings_get_bool(settings, FreeRDP_SmartcardEmulation))
return smartcard_sw_enumerateCerts(settings, scCerts, retCount);
if (CspName && (!(csp = ConvertUtf8ToWCharAlloc(CspName, nullptr))))
{
WLog_ERR(TAG, "error while converting CSP to WCHAR");
return FALSE;
}
ret =
smartcard_hw_enumerateCerts(settings, csp, ReaderName, Username, Domain, scCerts, retCount);
free(csp);
return ret;
}
static BOOL set_settings_from_smartcard(rdpSettings* settings, FreeRDP_Settings_Keys_String id,
const char* value)
{
WINPR_ASSERT(settings);
if (!freerdp_settings_get_string(settings, id) && value)
if (!freerdp_settings_set_string(settings, id, value))
return FALSE;
return TRUE;
}
BOOL smartcard_getCert(const rdpContext* context, SmartcardCertInfo** cert, BOOL gateway)
{
WINPR_ASSERT(context);
const freerdp* instance = context->instance;
rdpSettings* settings = context->settings;
SmartcardCertInfo** cert_list = nullptr;
size_t count = 0;
WINPR_ASSERT(instance);
WINPR_ASSERT(settings);
if (!smartcard_enumerateCerts(settings, &cert_list, &count, gateway))
return FALSE;
if (count < 1)
{
WLog_ERR(TAG, "no suitable smartcard certificates were found");
return FALSE;
}
if (count > UINT32_MAX)
{
WLog_ERR(TAG, "smartcard certificate count %" PRIuz " exceeds UINT32_MAX", count);
return FALSE;
}
if (count > 1)
{
DWORD index = 0;
if (!instance->ChooseSmartcard ||
!instance->ChooseSmartcard(context->instance, cert_list, (UINT32)count, &index,
gateway))
{
WLog_ERR(TAG, "more than one suitable smartcard certificate was found");
smartcardCertList_Free(cert_list, count);
return FALSE;
}
*cert = cert_list[index];
for (DWORD i = 0; i < index; i++)
smartcardCertInfo_Free(cert_list[i]);
for (DWORD i = index + 1; i < count; i++)
smartcardCertInfo_Free(cert_list[i]);
}
else
*cert = cert_list[0];
FreeRDP_Settings_Keys_String username_setting =
gateway ? FreeRDP_GatewayUsername : FreeRDP_Username;
FreeRDP_Settings_Keys_String domain_setting = gateway ? FreeRDP_GatewayDomain : FreeRDP_Domain;
free((void*)cert_list);
if (!set_settings_from_smartcard(settings, username_setting, (*cert)->userHint) ||
!set_settings_from_smartcard(settings, domain_setting, (*cert)->domainHint))
{
WLog_ERR(TAG, "unable to set settings from smartcard!");
smartcardCertInfo_Free(*cert);
return FALSE;
}
return TRUE;
}

Some files were not shown because too many files have changed in this diff Show More