summaryrefslogtreecommitdiffstats
path: root/libfreerdp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:25:12 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:25:12 +0000
commit827a4c3faa27e0c186452585b15094eee1119085 (patch)
treee6a08b0c767863d66f7d4a9de80db5edc7db29be /libfreerdp
parentReleasing progress-linux version 3.3.0+dfsg1-1~progress7.99u1. (diff)
downloadfreerdp3-827a4c3faa27e0c186452585b15094eee1119085.tar.xz
freerdp3-827a4c3faa27e0c186452585b15094eee1119085.zip
Merging upstream version 3.5.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libfreerdp')
-rw-r--r--libfreerdp/CMakeLists.txt66
-rw-r--r--libfreerdp/FreeRDPConfig.cmake.in6
-rw-r--r--libfreerdp/codec/clear.c2
-rw-r--r--libfreerdp/codec/interleaved.c2
-rw-r--r--libfreerdp/codec/ncrush.c55
-rw-r--r--libfreerdp/codec/nsc.c4
-rw-r--r--libfreerdp/codec/planar.c54
-rw-r--r--libfreerdp/codec/rfx.c2
-rw-r--r--libfreerdp/codec/rfx_rlgr.c42
-rw-r--r--libfreerdp/codec/test/CMakeLists.txt6
-rw-r--r--libfreerdp/codec/test/TestFuzzCodecs.c480
-rw-r--r--libfreerdp/codec/zgfx.c14
-rw-r--r--libfreerdp/common/settings.c38
-rw-r--r--libfreerdp/common/settings_getters.c14
-rw-r--r--libfreerdp/common/settings_str.h4
-rw-r--r--libfreerdp/common/test/CMakeLists.txt15
-rw-r--r--libfreerdp/core/aad.c4
-rw-r--r--libfreerdp/core/capabilities.c7
-rw-r--r--libfreerdp/core/childsession.c268
-rw-r--r--libfreerdp/core/client.c9
-rw-r--r--libfreerdp/core/connection.c13
-rw-r--r--libfreerdp/core/credssp_auth.c1
-rw-r--r--libfreerdp/core/freerdp.c20
-rw-r--r--libfreerdp/core/gateway/arm.c9
-rw-r--r--libfreerdp/core/gateway/http.c20
-rw-r--r--libfreerdp/core/gateway/rdg.c221
-rw-r--r--libfreerdp/core/gateway/tsg.c120
-rw-r--r--libfreerdp/core/gateway/tsg.h2
-rw-r--r--libfreerdp/core/gateway/wst.c2
-rw-r--r--libfreerdp/core/gcc.c6
-rw-r--r--libfreerdp/core/info.c8
-rw-r--r--libfreerdp/core/input.h2
-rw-r--r--libfreerdp/core/license.c25
-rw-r--r--libfreerdp/core/listener.c14
-rw-r--r--libfreerdp/core/nla.c7
-rw-r--r--libfreerdp/core/peer.c4
-rw-r--r--libfreerdp/core/proxy.c8
-rw-r--r--libfreerdp/core/rdp.c4
-rw-r--r--libfreerdp/core/security.c1
-rw-r--r--libfreerdp/core/smartcardlogon.c11
-rw-r--r--libfreerdp/core/test/CMakeLists.txt17
-rw-r--r--libfreerdp/core/test/settings_property_lists.h2
-rw-r--r--libfreerdp/core/transport.c14
-rw-r--r--libfreerdp/core/transport.h15
-rw-r--r--libfreerdp/core/update.c8
-rw-r--r--libfreerdp/core/utils.c181
-rw-r--r--libfreerdp/core/utils.h14
-rw-r--r--libfreerdp/crypto/cert_common.c12
-rw-r--r--libfreerdp/crypto/certificate.c35
-rw-r--r--libfreerdp/crypto/certificate_data.c42
-rw-r--r--libfreerdp/crypto/privatekey.c6
-rw-r--r--libfreerdp/crypto/tls.c3
-rw-r--r--libfreerdp/emu/scard/smartcard_emulate.c19
-rw-r--r--libfreerdp/emu/scard/smartcard_virtual_gids.c6
-rw-r--r--libfreerdp/freerdp.pc.in4
-rw-r--r--libfreerdp/locale/keyboard_xkbfile.c564
-rw-r--r--libfreerdp/primitives/prim_YUV_neon.c18
-rw-r--r--libfreerdp/primitives/prim_alphaComp.c1
-rw-r--r--libfreerdp/primitives/prim_copy.c21
-rw-r--r--libfreerdp/primitives/test/measure.h59
-rw-r--r--libfreerdp/primitives/test/prim_test.c26
-rw-r--r--libfreerdp/utils/CMakeLists.txt4
-rw-r--r--libfreerdp/utils/encoded_types.c214
-rw-r--r--libfreerdp/utils/http.c6
-rw-r--r--libfreerdp/utils/pcap.c30
-rw-r--r--libfreerdp/utils/stopwatch.c28
-rw-r--r--libfreerdp/utils/test/CMakeLists.txt6
-rw-r--r--libfreerdp/utils/test/TestEncodedTypes.c212
68 files changed, 2345 insertions, 812 deletions
diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt
index 5b47d98..54c9cd1 100644
--- a/libfreerdp/CMakeLists.txt
+++ b/libfreerdp/CMakeLists.txt
@@ -21,15 +21,6 @@ set(MODULE_PREFIX "FREERDP")
# CMake modules includes
include(FindCairo)
-# Create imported targets for Intel IPP libraries
-
-if(IPP_FOUND)
- foreach(ipp_lib ${IPP_LIBRARIES})
- add_library("${ipp_lib}_imported" STATIC IMPORTED)
- set_property(TARGET "${ipp_lib}_imported" PROPERTY IMPORTED_LOCATION "${IPP_LIBRARY_DIRS}/${ipp_lib}")
- endforeach()
-endif()
-
set(LIBFREERDP_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(LIBFREERDP_SRCS "")
set(LIBFREERDP_LIBS "")
@@ -376,15 +367,6 @@ set(PRIMITIVES_OPT_SRCS
${PRIMITIVES_SSSE3_SRCS}
${PRIMITIVES_OPENCL_SRCS})
-### IPP Variable debugging
-if(WITH_IPP)
- if(CMAKE_COMPILER_IS_GNUCC OR ${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
- foreach(INCLDIR ${IPP_INCLUDE_DIRS})
- set(OPTIMIZATION "${OPTIMIZATION} -I${INCLDIR}")
- endforeach(INCLDIR)
- endif()
-endif()
-
if(WITH_SSE2)
if(CMAKE_COMPILER_IS_GNUCC OR ${CMAKE_C_COMPILER_ID} STREQUAL "Clang")
set_source_files_properties(${PRIMITIVES_SSE2_SRCS}
@@ -413,13 +395,6 @@ set(PRIMITIVES_SRCS ${PRIMITIVES_SRCS} ${PRIMITIVES_OPT_SRCS})
freerdp_module_add(${PRIMITIVES_SRCS})
-if(IPP_FOUND)
- freerdp_include_directory_add(${IPP_INCLUDE_DIRS})
- foreach(ipp_lib ${IPP_LIBRARIES})
- freerdp_library_add("${ipp_lib}_imported")
- endforeach()
-endif()
-
if(BUILD_TESTING AND NOT WIN32 AND NOT APPLE)
add_subdirectory(primitives/test)
endif()
@@ -430,37 +405,13 @@ endif()
list(APPEND LIBFREERDP_PUB_LIBS winpr)
list(REMOVE_DUPLICATES LIBFREERDP_DEFINITIONS)
-list(REMOVE_DUPLICATES LIBFREERDP_LIBS)
-list(REMOVE_DUPLICATES LIBFREERDP_PUB_LIBS)
list(REMOVE_DUPLICATES LIBFREERDP_INCLUDES)
include_directories(${LIBFREERDP_INCLUDES})
-# On windows create dll version information.
-# Vendor, product and year are already set in top level CMakeLists.txt
-if (WIN32)
- set (RC_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
- set (RC_VERSION_MINOR ${FREERDP_VERSION_MINOR})
- set (RC_VERSION_BUILD ${FREERDP_VERSION_REVISION})
- set (RC_VERSION_FILE "${CMAKE_SHARED_LIBRARY_PREFIX}${MODULE_NAME}${FREERDP_API_VERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}" )
+AddTargetWithResourceFile(${MODULE_NAME} FALSE "${FREERDP_VERSION}" LIBFREERDP_SRCS)
- configure_file(
- ${PROJECT_SOURCE_DIR}/cmake/WindowsDLLVersion.rc.in
- ${CMAKE_CURRENT_BINARY_DIR}/version.rc
- @ONLY)
-
- set (LIBFREERDP_SRCS ${LIBFREERDP_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
-endif()
-
-add_library(${MODULE_NAME} ${LIBFREERDP_SRCS})
add_definitions(${LIBFREERDP_DEFINITIONS})
-set_target_properties(${MODULE_NAME} PROPERTIES LINKER_LANGUAGE C)
-set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME ${MODULE_NAME}${FREERDP_VERSION_MAJOR})
-
-if (WITH_LIBRARY_VERSIONING)
- set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${FREERDP_VERSION} SOVERSION ${FREERDP_API_VERSION})
-endif()
-
target_include_directories(${MODULE_NAME} INTERFACE $<INSTALL_INTERFACE:include>)
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBFREERDP_LIBS})
target_link_libraries(${MODULE_NAME} PUBLIC ${LIBFREERDP_PUB_LIBS})
@@ -469,14 +420,19 @@ install(TARGETS ${MODULE_NAME} COMPONENT libraries EXPORT FreeRDPTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
-if (WITH_DEBUG_SYMBOLS AND MSVC AND BUILD_SHARED_LIBS)
- get_target_property(OUTPUT_FILENAME ${MODULE_NAME} OUTPUT_NAME)
- install(FILES ${CMAKE_PDB_BINARY_DIR}/${OUTPUT_FILENAME}.pdb DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT symbols)
-endif()
-
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/libfreerdp")
include(pkg-config-install-prefix)
+set(FREERDP_REQUIRES_PRIVATE "")
+if(cJSON_FOUND)
+ string(APPEND FREERDP_REQUIRES_PRIVATE " libcjson")
+ list(APPEND FREERDP_PC_PRIVATE_LIBS "-lcjson")
+endif()
+if(WITH_SMARTCARD_EMULATE)
+ string(APPEND FREERDP_REQUIRES_PRIVATE " zlib")
+ list(APPEND FREERDP_PC_PRIVATE_LIBS "-lz")
+endif()
+list(JOIN FREERDP_PC_PRIVATE_LIBS " " FREERDP_PC_PRIVATE_LIBS)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp${FREERDP_VERSION_MAJOR}.pc @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp${FREERDP_VERSION_MAJOR}.pc DESTINATION ${PKG_CONFIG_PC_INSTALL_DIR})
diff --git a/libfreerdp/FreeRDPConfig.cmake.in b/libfreerdp/FreeRDPConfig.cmake.in
index 21ecd59..0052c3d 100644
--- a/libfreerdp/FreeRDPConfig.cmake.in
+++ b/libfreerdp/FreeRDPConfig.cmake.in
@@ -1,5 +1,11 @@
include(CMakeFindDependencyMacro)
find_dependency(WinPR @FREERDP_VERSION@)
+if("@cJSON_FOUND@" AND NOT "@BUILD_SHARED_LIBS@")
+ find_dependency(cJSON)
+endif()
+if("@WITH_SMARTCARD_EMULATE@" AND NOT "@BUILD_SHARED_LIBS@")
+ find_dependency(ZLIB)
+endif()
@PACKAGE_INIT@
diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c
index 5c009d8..512aeae 100644
--- a/libfreerdp/codec/clear.c
+++ b/libfreerdp/codec/clear.c
@@ -409,7 +409,7 @@ static BOOL clear_decompress_residual_data(CLEAR_CONTEXT* clear, wStream* s,
}
}
- if ((pixelIndex + runLengthFactor) > pixelCount)
+ if ((pixelIndex >= pixelCount) || (runLengthFactor > (pixelCount - pixelIndex)))
{
WLog_ERR(TAG,
"pixelIndex %" PRIu32 " + runLengthFactor %" PRIu32 " > pixelCount %" PRIu32
diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
index 75b2e27..df148b6 100644
--- a/libfreerdp/codec/interleaved.c
+++ b/libfreerdp/codec/interleaved.c
@@ -237,7 +237,7 @@ static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd,
runLength = *pbOrderHdr & g_MaskLiteRunLength;
if (runLength == 0)
{
- if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
+ if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
{
*advance = 0;
return 0;
diff --git a/libfreerdp/codec/ncrush.c b/libfreerdp/codec/ncrush.c
index 4a7162c..28b98d9 100644
--- a/libfreerdp/codec/ncrush.c
+++ b/libfreerdp/codec/ncrush.c
@@ -2068,6 +2068,12 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
return 1;
}
+ if (SrcSize < 4)
+ {
+ WLog_ERR(TAG, "Input size short: SrcSize %" PRIu32 " < 4", SrcSize);
+ return -1;
+ }
+
const BYTE* SrcEnd = &pSrcData[SrcSize];
const BYTE* SrcPtr = pSrcData + 4;
@@ -2119,7 +2125,7 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSi
CopyOffset = ncrush->OffsetCache[OffsetCacheIndex];
const UINT16 Mask = get_word(&HuffTableMask[21]);
const UINT32 MaskedBits = bits & Mask;
- if (MaskedBits > ARRAYSIZE(HuffTableLOM))
+ if (MaskedBits >= ARRAYSIZE(HuffTableLOM))
return -1;
LengthOfMatch = HuffTableLOM[MaskedBits] & 0xFFF;
BitLength = HuffTableLOM[MaskedBits] >> 12;
@@ -2480,50 +2486,39 @@ static int ncrush_find_best_match(NCRUSH_CONTEXT* ncrush, UINT16 HistoryOffset,
static int ncrush_move_encoder_windows(NCRUSH_CONTEXT* ncrush, BYTE* HistoryPtr)
{
- int NewHash = 0;
- int NewMatch = 0;
- UINT32 HistoryOffset = 0;
-
WINPR_ASSERT(ncrush);
WINPR_ASSERT(HistoryPtr);
- if (HistoryPtr < &ncrush->HistoryBuffer[32768])
+ const size_t history_half = ARRAYSIZE(ncrush->HistoryBuffer) / 2;
+ if (HistoryPtr < &ncrush->HistoryBuffer[history_half])
return -1;
- if (HistoryPtr > &ncrush->HistoryBuffer[65536])
+ if (HistoryPtr > &ncrush->HistoryBuffer[ARRAYSIZE(ncrush->HistoryBuffer)])
return -1;
- MoveMemory(ncrush->HistoryBuffer, HistoryPtr - 32768, 32768);
- const intptr_t hsize = HistoryPtr - 32768 - ncrush->HistoryBuffer;
- WINPR_ASSERT(hsize <= UINT32_MAX);
+ MoveMemory(ncrush->HistoryBuffer, HistoryPtr - history_half, history_half * sizeof(BYTE));
+ const intptr_t hsize = HistoryPtr - history_half - ncrush->HistoryBuffer;
+ WINPR_ASSERT(hsize <= UINT16_MAX);
WINPR_ASSERT(hsize >= 0);
- HistoryOffset = (UINT32)hsize;
+ INT32 HistoryOffset = (INT32)hsize;
- for (int i = 0; i < 65536; i += 4)
+ for (size_t i = 0; i < ARRAYSIZE(ncrush->HashTable); i++)
{
- NewHash = ncrush->HashTable[i + 0] - HistoryOffset;
- ncrush->HashTable[i + 0] = (NewHash <= 0) ? 0 : NewHash;
- NewHash = ncrush->HashTable[i + 1] - HistoryOffset;
- ncrush->HashTable[i + 1] = (NewHash <= 0) ? 0 : NewHash;
- NewHash = ncrush->HashTable[i + 2] - HistoryOffset;
- ncrush->HashTable[i + 2] = (NewHash <= 0) ? 0 : NewHash;
- NewHash = ncrush->HashTable[i + 3] - HistoryOffset;
- ncrush->HashTable[i + 3] = (NewHash <= 0) ? 0 : NewHash;
+ INT32 NewHash = ncrush->HashTable[i] - HistoryOffset;
+ ncrush->HashTable[i] = (NewHash <= 0) ? 0 : NewHash;
}
- for (int j = 0; j < 32768; j += 4)
+ const size_t match_half = ARRAYSIZE(ncrush->MatchTable) / 2;
+ for (size_t j = 0; j < match_half; j++)
{
- NewMatch = ncrush->MatchTable[HistoryOffset + j + 0] - HistoryOffset;
- ncrush->MatchTable[j + 0] = (NewMatch <= 0) ? 0 : NewMatch;
- NewMatch = ncrush->MatchTable[HistoryOffset + j + 1] - HistoryOffset;
- ncrush->MatchTable[j + 1] = (NewMatch <= 0) ? 0 : NewMatch;
- NewMatch = ncrush->MatchTable[HistoryOffset + j + 2] - HistoryOffset;
- ncrush->MatchTable[j + 2] = (NewMatch <= 0) ? 0 : NewMatch;
- NewMatch = ncrush->MatchTable[HistoryOffset + j + 3] - HistoryOffset;
- ncrush->MatchTable[j + 3] = (NewMatch <= 0) ? 0 : NewMatch;
+ if (HistoryOffset + j >= ARRAYSIZE(ncrush->MatchTable))
+ continue;
+
+ INT32 NewMatch = ncrush->MatchTable[HistoryOffset + j] - HistoryOffset;
+ ncrush->MatchTable[j] = (NewMatch <= 0) ? 0 : NewMatch;
}
- ZeroMemory(&ncrush->MatchTable[32768], 65536);
+ ZeroMemory(&ncrush->MatchTable[match_half], match_half * sizeof(UINT16));
return 1;
}
diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c
index 049b541..74f4e28 100644
--- a/libfreerdp/codec/nsc.c
+++ b/libfreerdp/codec/nsc.c
@@ -160,7 +160,7 @@ static BOOL nsc_rle_decode(const BYTE* in, size_t inSize, BYTE* out, UINT32 outS
len |= ((UINT32)(*in++)) << 24U;
}
- if (outSize < len)
+ if ((outSize < len) || (left < len))
return FALSE;
outSize -= len;
@@ -262,7 +262,7 @@ static BOOL nsc_context_initialize(NSC_CONTEXT* context, wStream* s)
if (!nsc_stream_initialize(context, s))
return FALSE;
- const size_t blength = context->width * context->height * 4ull;
+ const size_t blength = 4ull * context->width * context->height;
if (!context->BitmapData || (blength > context->BitmapDataLength))
{
diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c
index 0ec0862..4b51a02 100644
--- a/libfreerdp/codec/planar.c
+++ b/libfreerdp/codec/planar.c
@@ -788,18 +788,26 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT
rawHeights[3] = nSrcHeight;
}
+ const size_t diff = srcp - pSrcData;
+ if (SrcSize < diff)
+ {
+ WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff);
+ return FALSE;
+ }
+
if (!rle) /* RAW */
{
+
UINT32 base = planeSize * 3;
if (cs)
base = planeSize + planeSize / 2;
if (alpha)
{
- if ((SrcSize - (srcp - pSrcData)) < (planeSize + base))
+ if ((SrcSize - diff) < (planeSize + base))
{
- WLog_ERR(TAG, "Alpha plane size mismatch %" PRIu32 " < %" PRIu32,
- SrcSize - (srcp - pSrcData), (planeSize + base));
+ WLog_ERR(TAG, "Alpha plane size mismatch %" PRIuz " < %" PRIu32, SrcSize - diff,
+ (planeSize + base));
return FALSE;
}
@@ -817,10 +825,9 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT
}
else
{
- if ((SrcSize - (srcp - pSrcData)) < base)
+ if ((SrcSize - diff) < base)
{
- WLog_ERR(TAG, "plane size mismatch %" PRIu32 " < %" PRIu32,
- SrcSize - (srcp - pSrcData), base);
+ WLog_ERR(TAG, "plane size mismatch %" PRIu32 " < %" PRIu32, SrcSize - diff, base);
return FALSE;
}
@@ -841,8 +848,8 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT
if (alpha)
{
planes[3] = srcp;
- rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - (planes[3] - pSrcData),
- rawWidths[3], rawHeights[3]); /* AlphaPlane */
+ rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - diff, rawWidths[3],
+ rawHeights[3]); /* AlphaPlane */
if (rleSizes[3] < 0)
return FALSE;
@@ -852,22 +859,41 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT
else
planes[0] = srcp;
- rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - (planes[0] - pSrcData),
- rawWidths[0], rawHeights[0]); /* RedPlane */
+ const size_t diff0 = (planes[0] - pSrcData);
+ if (SrcSize < diff0)
+ {
+ WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff0);
+ return FALSE;
+ }
+ rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - diff0, rawWidths[0],
+ rawHeights[0]); /* RedPlane */
if (rleSizes[0] < 0)
return FALSE;
planes[1] = planes[0] + rleSizes[0];
- rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - (planes[1] - pSrcData),
- rawWidths[1], rawHeights[1]); /* GreenPlane */
+
+ const size_t diff1 = (planes[1] - pSrcData);
+ if (SrcSize < diff1)
+ {
+ WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff1);
+ return FALSE;
+ }
+ rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - diff1, rawWidths[1],
+ rawHeights[1]); /* GreenPlane */
if (rleSizes[1] < 1)
return FALSE;
planes[2] = planes[1] + rleSizes[1];
- rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - (planes[2] - pSrcData),
- rawWidths[2], rawHeights[2]); /* BluePlane */
+ const size_t diff2 = (planes[2] - pSrcData);
+ if (SrcSize < diff2)
+ {
+ WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff);
+ return FALSE;
+ }
+ rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - diff2, rawWidths[2],
+ rawHeights[2]); /* BluePlane */
if (rleSizes[2] < 1)
return FALSE;
diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c
index c83cfd5..66ed1e0 100644
--- a/libfreerdp/codec/rfx.c
+++ b/libfreerdp/codec/rfx.c
@@ -1368,7 +1368,7 @@ const RFX_TILE** rfx_message_get_tiles(const RFX_MESSAGE* message, UINT16* numTi
WINPR_ASSERT(message);
if (numTiles)
*numTiles = message->numTiles;
- return message->tiles;
+ return (const RFX_TILE**)message->tiles;
}
UINT16 rfx_message_get_tile_count(const RFX_MESSAGE* message)
diff --git a/libfreerdp/codec/rfx_rlgr.c b/libfreerdp/codec/rfx_rlgr.c
index da1b63f..6ecbfbe 100644
--- a/libfreerdp/codec/rfx_rlgr.c
+++ b/libfreerdp/codec/rfx_rlgr.c
@@ -50,12 +50,12 @@
#define GetMinBits(_val, _nbits) \
do \
{ \
- UINT32 _v = _val; \
- _nbits = 0; \
+ UINT32 _v = (_val); \
+ (_nbits) = 0; \
while (_v) \
{ \
_v >>= 1; \
- _nbits++; \
+ (_nbits)++; \
} \
} while (0)
@@ -66,12 +66,12 @@
#define UpdateParam(_param, _deltaP, _k) \
do \
{ \
- _param += _deltaP; \
- if (_param > KPMAX) \
- _param = KPMAX; \
- if (_param < 0) \
- _param = 0; \
- _k = (_param >> LSGR); \
+ (_param) += (_deltaP); \
+ if ((_param) > KPMAX) \
+ (_param) = KPMAX; \
+ if ((_param) < 0) \
+ (_param) = 0; \
+ (_k) = ((_param) >> LSGR); \
} while (0)
static BOOL g_LZCNT = FALSE;
@@ -568,18 +568,18 @@ int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* WINPR_RESTRICT pSrcData, UINT32
}
/* Returns the next coefficient (a signed int) to encode, from the input stream */
-#define GetNextInput(_n) \
- do \
- { \
- if (data_size > 0) \
- { \
- _n = *data++; \
- data_size--; \
- } \
- else \
- { \
- _n = 0; \
- } \
+#define GetNextInput(_n) \
+ do \
+ { \
+ if (data_size > 0) \
+ { \
+ (_n) = *data++; \
+ data_size--; \
+ } \
+ else \
+ { \
+ (_n) = 0; \
+ } \
} while (0)
/* Emit bitPattern to the output bitstream */
diff --git a/libfreerdp/codec/test/CMakeLists.txt b/libfreerdp/codec/test/CMakeLists.txt
index 4258b50..ebc7b8e 100644
--- a/libfreerdp/codec/test/CMakeLists.txt
+++ b/libfreerdp/codec/test/CMakeLists.txt
@@ -35,3 +35,9 @@ endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Test")
+set(FUZZERS
+ TestFuzzCodecs.c
+)
+
+include (AddFuzzerTest)
+add_fuzzer_test("${FUZZERS}" "freerdp winpr")
diff --git a/libfreerdp/codec/test/TestFuzzCodecs.c b/libfreerdp/codec/test/TestFuzzCodecs.c
new file mode 100644
index 0000000..d83d8d4
--- /dev/null
+++ b/libfreerdp/codec/test/TestFuzzCodecs.c
@@ -0,0 +1,480 @@
+/* https://github.com/ergnoorr/fuzzrdp
+ *
+ * MIT License
+ *
+ * Copyright (c) 2024 ergnoorr
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <freerdp/assistance.h>
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+#include <winpr/platform.h>
+#include <freerdp/codec/interleaved.h>
+#include <freerdp/codec/planar.h>
+#include <freerdp/codec/bulk.h>
+#include <freerdp/codec/clear.h>
+#include <freerdp/codec/zgfx.h>
+#include <freerdp/log.h>
+#include <winpr/bitstream.h>
+#include <freerdp/codec/rfx.h>
+#include <freerdp/codec/progressive.h>
+
+#include <freerdp/freerdp.h>
+#include <freerdp/gdi/gdi.h>
+
+#include "../progressive.h"
+#include "../mppc.h"
+#include "../xcrush.h"
+#include "../ncrush.h"
+
+static BOOL test_ClearDecompressExample(UINT32 nr, UINT32 width, UINT32 height,
+ const BYTE* pSrcData, const UINT32 SrcSize)
+{
+ BOOL rc = FALSE;
+ int status = 0;
+ BYTE* pDstData = calloc(1ull * width * height, 4);
+ CLEAR_CONTEXT* clear = clear_context_new(FALSE);
+
+ WINPR_UNUSED(nr);
+ if (!clear || !pDstData)
+ goto fail;
+
+ status = clear_decompress(clear, pSrcData, SrcSize, width, height, pDstData,
+ PIXEL_FORMAT_XRGB32, 0, 0, 0, width, height, NULL);
+ // printf("clear_decompress example %" PRIu32 " status: %d\n", nr, status);
+ // fflush(stdout);
+ rc = (status == 0);
+fail:
+ clear_context_free(clear);
+ free(pDstData);
+ return rc;
+}
+
+static int TestFreeRDPCodecClear(const uint8_t* Data, size_t Size)
+{
+ if (Size > UINT32_MAX)
+ return -1;
+ test_ClearDecompressExample(2, 78, 17, Data, (UINT32)Size);
+ test_ClearDecompressExample(3, 64, 24, Data, (UINT32)Size);
+ test_ClearDecompressExample(4, 7, 15, Data, (UINT32)Size);
+ return 0;
+}
+
+static int TestFreeRDPCodecXCrush(const uint8_t* Data, size_t Size)
+{
+ if (Size > UINT32_MAX)
+ return -1;
+
+ const BYTE* OutputBuffer = NULL;
+ UINT32 DstSize = 0;
+ XCRUSH_CONTEXT* xcrush = xcrush_context_new(TRUE);
+ if (!xcrush)
+ return 0;
+ xcrush_decompress(xcrush, Data, (UINT32)Size, &OutputBuffer, &DstSize, 0);
+ xcrush_context_free(xcrush);
+ return 0;
+}
+
+static int test_ZGfxDecompressFoxSingle(const uint8_t* Data, size_t Size)
+{
+ if (Size > UINT32_MAX)
+ return -1;
+ int rc = -1;
+ int status = 0;
+ UINT32 Flags = 0;
+ const BYTE* pSrcData = (const BYTE*)Data;
+ UINT32 SrcSize = (UINT32)Size;
+ UINT32 DstSize = 0;
+ BYTE* pDstData = NULL;
+ ZGFX_CONTEXT* zgfx = zgfx_context_new(TRUE);
+
+ if (!zgfx)
+ return -1;
+
+ status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
+ if (status < 0)
+ goto fail;
+
+ rc = 0;
+fail:
+ free(pDstData);
+ zgfx_context_free(zgfx);
+ return rc;
+}
+
+static int TestFreeRDPCodecZGfx(const uint8_t* Data, size_t Size)
+{
+ test_ZGfxDecompressFoxSingle(Data, Size);
+ return 0;
+}
+
+static BOOL test_NCrushDecompressBells(const uint8_t* Data, size_t Size)
+{
+ if (Size > UINT32_MAX)
+ return FALSE;
+
+ BOOL rc = FALSE;
+ int status = 0;
+ UINT32 Flags = PACKET_COMPRESSED | 2;
+ const BYTE* pSrcData = (const BYTE*)Data;
+ UINT32 SrcSize = (UINT32)Size;
+ UINT32 DstSize = 0;
+ const BYTE* pDstData = NULL;
+ NCRUSH_CONTEXT* ncrush = ncrush_context_new(FALSE);
+
+ if (!ncrush)
+ return rc;
+
+ status = ncrush_decompress(ncrush, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
+ if (status < 0)
+ goto fail;
+
+ rc = TRUE;
+fail:
+ ncrush_context_free(ncrush);
+ return rc;
+}
+
+static int TestFreeRDPCodecNCrush(const uint8_t* Data, size_t Size)
+{
+ test_NCrushDecompressBells(Data, Size);
+ return 0;
+}
+
+static const size_t IMG_WIDTH = 64;
+static const size_t IMG_HEIGHT = 64;
+static const size_t FORMAT_SIZE = 4;
+static const UINT32 FORMAT = PIXEL_FORMAT_XRGB32;
+
+static int TestFreeRDPCodecRemoteFX(const uint8_t* Data, size_t Size)
+{
+ int rc = -1;
+ REGION16 region = { 0 };
+ RFX_CONTEXT* context = rfx_context_new(FALSE);
+ BYTE* dest = calloc(IMG_WIDTH * IMG_HEIGHT, FORMAT_SIZE);
+ size_t stride = FORMAT_SIZE * IMG_WIDTH;
+ if (!context)
+ goto fail;
+ if (Size > UINT32_MAX)
+ goto fail;
+ if (stride > UINT32_MAX)
+ goto fail;
+ if (!dest)
+ goto fail;
+
+ region16_init(&region);
+ if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride,
+ IMG_HEIGHT, &region))
+ goto fail;
+
+ region16_clear(&region);
+ if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride,
+ IMG_HEIGHT, &region))
+ goto fail;
+ region16_print(&region);
+
+ rc = 0;
+fail:
+ region16_uninit(&region);
+ rfx_context_free(context);
+ free(dest);
+ return rc;
+}
+
+static int test_MppcDecompressBellsRdp5(const uint8_t* Data, size_t Size)
+{
+ int rc = -1;
+ int status = 0;
+ UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1;
+ const BYTE* pSrcData = Data;
+ UINT32 SrcSize = (UINT32)Size;
+ UINT32 DstSize = 0;
+ const BYTE* pDstData = NULL;
+ MPPC_CONTEXT* mppc = mppc_context_new(1, FALSE);
+
+ if (!mppc)
+ return -1;
+
+ status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
+
+ if (status < 0)
+ goto fail;
+
+ rc = 0;
+
+fail:
+ mppc_context_free(mppc);
+ return rc;
+}
+
+static int test_MppcDecompressBellsRdp4(const uint8_t* Data, size_t Size)
+{
+ if (Size > UINT32_MAX)
+ return -1;
+ int rc = -1;
+ int status = 0;
+ UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0;
+ const BYTE* pSrcData = (const BYTE*)Data;
+ UINT32 SrcSize = (UINT32)Size;
+ UINT32 DstSize = 0;
+ const BYTE* pDstData = NULL;
+ MPPC_CONTEXT* mppc = mppc_context_new(0, FALSE);
+
+ if (!mppc)
+ return -1;
+
+ status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
+
+ if (status < 0)
+ goto fail;
+
+ rc = 0;
+fail:
+ mppc_context_free(mppc);
+ return rc;
+}
+
+static int test_MppcDecompressBufferRdp5(const uint8_t* Data, size_t Size)
+{
+ if (Size > UINT32_MAX)
+ return -1;
+ int rc = -1;
+ int status = 0;
+ UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1;
+ const BYTE* pSrcData = (const BYTE*)Data;
+ UINT32 SrcSize = (UINT32)Size;
+ UINT32 DstSize = 0;
+ const BYTE* pDstData = NULL;
+ MPPC_CONTEXT* mppc = mppc_context_new(1, FALSE);
+
+ if (!mppc)
+ return -1;
+
+ status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
+
+ if (status < 0)
+ goto fail;
+
+ rc = 0;
+fail:
+ mppc_context_free(mppc);
+ return rc;
+}
+
+static int TestFreeRDPCodecMppc(const uint8_t* Data, size_t Size)
+{
+ test_MppcDecompressBellsRdp5(Data, Size);
+ test_MppcDecompressBellsRdp4(Data, Size);
+ test_MppcDecompressBufferRdp5(Data, Size);
+ return 0;
+}
+
+static BOOL progressive_decode(const uint8_t* Data, size_t Size)
+{
+ BOOL res = FALSE;
+ int rc = 0;
+ BYTE* resultData = NULL;
+ UINT32 ColorFormat = PIXEL_FORMAT_BGRX32;
+ REGION16 invalidRegion = { 0 };
+ UINT32 scanline = 4240;
+ UINT32 width = 1060;
+ UINT32 height = 827;
+ if (Size > UINT32_MAX)
+ return FALSE;
+
+ PROGRESSIVE_CONTEXT* progressiveDec = progressive_context_new(FALSE);
+
+ region16_init(&invalidRegion);
+ if (!progressiveDec)
+ goto fail;
+
+ resultData = calloc(scanline, height);
+ if (!resultData)
+ goto fail;
+
+ rc = progressive_create_surface_context(progressiveDec, 0, width, height);
+ if (rc <= 0)
+ goto fail;
+
+ rc = progressive_decompress(progressiveDec, Data, (UINT32)Size, resultData, ColorFormat,
+ scanline, 0, 0, &invalidRegion, 0, 0);
+ if (rc < 0)
+ goto fail;
+
+ res = TRUE;
+fail:
+ region16_uninit(&invalidRegion);
+ progressive_context_free(progressiveDec);
+ free(resultData);
+ return res;
+}
+
+static int TestFreeRDPCodecProgressive(const uint8_t* Data, size_t Size)
+{
+ progressive_decode(Data, Size);
+ return 0;
+}
+
+static BOOL i_run_encode_decode(UINT16 bpp, BITMAP_INTERLEAVED_CONTEXT* encoder,
+ BITMAP_INTERLEAVED_CONTEXT* decoder, const uint8_t* Data,
+ size_t Size)
+{
+ BOOL rc2 = FALSE;
+ BOOL rc = 0;
+ const UINT32 w = 64;
+ const UINT32 h = 64;
+ const UINT32 x = 0;
+ const UINT32 y = 0;
+ const UINT32 format = PIXEL_FORMAT_RGBX32;
+ const size_t step = (w + 13ull) * 4ull;
+ const size_t SrcSize = step * h;
+ BYTE* pSrcData = calloc(1, SrcSize);
+ BYTE* pDstData = calloc(1, SrcSize);
+ BYTE* tmp = calloc(1, SrcSize);
+
+ WINPR_UNUSED(encoder);
+ if (!pSrcData || !pDstData || !tmp)
+ goto fail;
+
+ if (Size > UINT32_MAX)
+ goto fail;
+
+ winpr_RAND(pSrcData, SrcSize);
+
+ if (!bitmap_interleaved_context_reset(decoder))
+ goto fail;
+
+ rc = interleaved_decompress(decoder, Data, (UINT32)Size, w, h, bpp, pDstData, format, step, x,
+ y, w, h, NULL);
+
+ if (!rc)
+ goto fail;
+
+ rc2 = TRUE;
+fail:
+ free(pSrcData);
+ free(pDstData);
+ free(tmp);
+ return rc2;
+}
+
+static int TestFreeRDPCodecInterleaved(const uint8_t* Data, size_t Size)
+{
+ int rc = -1;
+ BITMAP_INTERLEAVED_CONTEXT* decoder = bitmap_interleaved_context_new(FALSE);
+
+ if (!decoder)
+ goto fail;
+
+ i_run_encode_decode(24, NULL, decoder, Data, Size);
+ i_run_encode_decode(16, NULL, decoder, Data, Size);
+ i_run_encode_decode(15, NULL, decoder, Data, Size);
+ rc = 0;
+fail:
+ bitmap_interleaved_context_free(decoder);
+ return rc;
+}
+
+static BOOL RunTestPlanar(BITMAP_PLANAR_CONTEXT* planar, const BYTE* srcBitmap,
+ const UINT32 srcFormat, const UINT32 dstFormat, const UINT32 width,
+ const UINT32 height, const uint8_t* Data, size_t Size)
+{
+ BOOL rc = FALSE;
+ WINPR_UNUSED(srcBitmap);
+ WINPR_UNUSED(srcFormat);
+ if (Size > UINT32_MAX)
+ return FALSE;
+ UINT32 dstSize = (UINT32)Size;
+ const BYTE* compressedBitmap = Data;
+ BYTE* decompressedBitmap =
+ (BYTE*)calloc(height, 1ull * width * FreeRDPGetBytesPerPixel(dstFormat));
+ rc = TRUE;
+
+ if (!decompressedBitmap)
+ goto fail;
+
+ if (!planar_decompress(planar, compressedBitmap, dstSize, width, height, decompressedBitmap,
+ dstFormat, 0, 0, 0, width, height, FALSE))
+ {
+ goto fail;
+ }
+
+ rc = TRUE;
+fail:
+ free(decompressedBitmap);
+ return rc;
+}
+
+static BOOL TestPlanar(const UINT32 format, const uint8_t* Data, size_t Size)
+{
+ BOOL rc = FALSE;
+ const DWORD planarFlags = PLANAR_FORMAT_HEADER_NA | PLANAR_FORMAT_HEADER_RLE;
+ BITMAP_PLANAR_CONTEXT* planar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
+
+ if (!planar)
+ goto fail;
+
+ RunTestPlanar(planar, NULL, PIXEL_FORMAT_RGBX32, format, 64, 64, Data, Size);
+
+ RunTestPlanar(planar, NULL, PIXEL_FORMAT_RGB16, format, 32, 32, Data, Size);
+
+ rc = TRUE;
+fail:
+ freerdp_bitmap_planar_context_free(planar);
+ return rc;
+}
+
+static int TestFreeRDPCodecPlanar(const uint8_t* Data, size_t Size)
+{
+ TestPlanar(0, Data, Size);
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
+{
+ if (Size < 4)
+ return 0;
+
+ int i = 0;
+ winpr_RAND(&i, sizeof(i));
+ i = i % 18;
+
+ if (i < 2)
+ TestFreeRDPCodecClear(Data, Size);
+ else if (i < 4)
+ TestFreeRDPCodecXCrush(Data, Size);
+ else if (i < 6)
+ TestFreeRDPCodecZGfx(Data, Size);
+ else if (i < 8)
+ TestFreeRDPCodecNCrush(Data, Size);
+ else if (i < 10)
+ TestFreeRDPCodecRemoteFX(Data, Size);
+ else if (i < 12)
+ TestFreeRDPCodecMppc(Data, Size);
+ else if (i < 14)
+ TestFreeRDPCodecProgressive(Data, Size);
+ else if (i < 16)
+ TestFreeRDPCodecInterleaved(Data, Size);
+ else if (i < 18)
+ TestFreeRDPCodecPlanar(Data, Size);
+
+ return 0;
+}
diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c
index 881823a..b7ee275 100644
--- a/libfreerdp/codec/zgfx.c
+++ b/libfreerdp/codec/zgfx.c
@@ -227,7 +227,10 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t
BYTE* pbSegment = NULL;
size_t cbSegment = 0;
- if (!zgfx || !stream || (segmentSize < 2))
+ WINPR_ASSERT(zgfx);
+ WINPR_ASSERT(stream);
+
+ if (segmentSize < 2)
return FALSE;
cbSegment = segmentSize - 1;
@@ -346,8 +349,9 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t
if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
return FALSE;
-
- if (count > zgfx->cBitsRemaining / 8)
+ else if (count > zgfx->cBitsRemaining / 8)
+ return FALSE;
+ else if (zgfx->pbInputCurrent + count > zgfx->pbInputEnd)
return FALSE;
CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent,
@@ -386,8 +390,8 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY
wStream sbuffer = { 0 };
wStream* stream = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);
- if (!stream)
- return -1;
+ WINPR_ASSERT(zgfx);
+ WINPR_ASSERT(stream);
if (!Stream_CheckAndLogRequiredLength(TAG, stream, 1))
goto fail;
diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c
index 34712c8..3beba43 100644
--- a/libfreerdp/common/settings.c
+++ b/libfreerdp/common/settings.c
@@ -237,6 +237,33 @@ BOOL freerdp_device_collection_add(rdpSettings* settings, RDPDR_DEVICE* device)
return TRUE;
}
+BOOL freerdp_device_collection_del(rdpSettings* settings, const RDPDR_DEVICE* device)
+{
+ WINPR_ASSERT(settings);
+
+ if (!device)
+ return FALSE;
+
+ const UINT32 count = settings->DeviceCount;
+ for (size_t x = 0; x < count; x++)
+ {
+ const RDPDR_DEVICE* cur = settings->DeviceArray[x];
+ if (cur == device)
+ {
+ for (size_t y = x + 1; y < count; y++)
+ {
+ RDPDR_DEVICE* next = settings->DeviceArray[y];
+ settings->DeviceArray[y - 1] = next;
+ }
+ settings->DeviceArray[count - 1] = NULL;
+ settings->DeviceCount--;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
RDPDR_DEVICE* freerdp_device_collection_find(rdpSettings* settings, const char* name)
{
RDPDR_DEVICE* device = NULL;
@@ -392,6 +419,9 @@ fail:
void freerdp_device_free(RDPDR_DEVICE* device)
{
+ if (!device)
+ return;
+
union
{
RDPDR_DEVICE* dev;
@@ -403,8 +433,6 @@ void freerdp_device_free(RDPDR_DEVICE* device)
} cnv;
cnv.dev = device;
- if (!cnv.dev)
- return;
switch (device->Type)
{
@@ -1166,8 +1194,10 @@ BOOL freerdp_settings_set_value_for_name(rdpSettings* settings, const char* name
case RDP_SETTINGS_TYPE_BOOL:
{
- BOOL val = _strnicmp(value, "TRUE", 5) == 0;
- if (!val && _strnicmp(value, "FALSE", 6) != 0)
+ const BOOL val = (_strnicmp(value, "TRUE", 5) == 0) || (_strnicmp(value, "ON", 5) == 0);
+ const BOOL nval =
+ (_strnicmp(value, "FALSE", 6) == 0) || (_strnicmp(value, "OFF", 6) == 0);
+ if (!val && !nval)
return parsing_fail(name, "BOOL", value);
return freerdp_settings_set_bool(settings, (FreeRDP_Settings_Keys_Bool)index, val);
}
diff --git a/libfreerdp/common/settings_getters.c b/libfreerdp/common/settings_getters.c
index ecec044..88f1fcb 100644
--- a/libfreerdp/common/settings_getters.c
+++ b/libfreerdp/common/settings_getters.c
@@ -105,6 +105,9 @@ BOOL freerdp_settings_get_bool(const rdpSettings* settings, FreeRDP_Settings_Key
case FreeRDP_AutoReconnectionEnabled:
return settings->AutoReconnectionEnabled;
+ case FreeRDP_AutoReconnectionPacketSupported:
+ return settings->AutoReconnectionPacketSupported;
+
case FreeRDP_BitmapCacheEnabled:
return settings->BitmapCacheEnabled;
@@ -252,6 +255,9 @@ BOOL freerdp_settings_get_bool(const rdpSettings* settings, FreeRDP_Settings_Key
case FreeRDP_GatewayHttpUseWebsockets:
return settings->GatewayHttpUseWebsockets;
+ case FreeRDP_GatewayIgnoreRedirectionPolicy:
+ return settings->GatewayIgnoreRedirectionPolicy;
+
case FreeRDP_GatewayRpcTransport:
return settings->GatewayRpcTransport;
@@ -712,6 +718,10 @@ BOOL freerdp_settings_set_bool(rdpSettings* settings, FreeRDP_Settings_Keys_Bool
settings->AutoReconnectionEnabled = cnv.c;
break;
+ case FreeRDP_AutoReconnectionPacketSupported:
+ settings->AutoReconnectionPacketSupported = cnv.c;
+ break;
+
case FreeRDP_BitmapCacheEnabled:
settings->BitmapCacheEnabled = cnv.c;
break;
@@ -908,6 +918,10 @@ BOOL freerdp_settings_set_bool(rdpSettings* settings, FreeRDP_Settings_Keys_Bool
settings->GatewayHttpUseWebsockets = cnv.c;
break;
+ case FreeRDP_GatewayIgnoreRedirectionPolicy:
+ settings->GatewayIgnoreRedirectionPolicy = cnv.c;
+ break;
+
case FreeRDP_GatewayRpcTransport:
settings->GatewayRpcTransport = cnv.c;
break;
diff --git a/libfreerdp/common/settings_str.h b/libfreerdp/common/settings_str.h
index a3c71fb..27939bd 100644
--- a/libfreerdp/common/settings_str.h
+++ b/libfreerdp/common/settings_str.h
@@ -50,6 +50,8 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_AutoLogonEnabled, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_AutoLogonEnabled" },
{ FreeRDP_AutoReconnectionEnabled, FREERDP_SETTINGS_TYPE_BOOL,
"FreeRDP_AutoReconnectionEnabled" },
+ { FreeRDP_AutoReconnectionPacketSupported, FREERDP_SETTINGS_TYPE_BOOL,
+ "FreeRDP_AutoReconnectionPacketSupported" },
{ FreeRDP_BitmapCacheEnabled, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_BitmapCacheEnabled" },
{ FreeRDP_BitmapCachePersistEnabled, FREERDP_SETTINGS_TYPE_BOOL,
"FreeRDP_BitmapCachePersistEnabled" },
@@ -114,6 +116,8 @@ static const struct settings_str_entry settings_map[] = {
{ FreeRDP_GatewayHttpTransport, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_GatewayHttpTransport" },
{ FreeRDP_GatewayHttpUseWebsockets, FREERDP_SETTINGS_TYPE_BOOL,
"FreeRDP_GatewayHttpUseWebsockets" },
+ { FreeRDP_GatewayIgnoreRedirectionPolicy, FREERDP_SETTINGS_TYPE_BOOL,
+ "FreeRDP_GatewayIgnoreRedirectionPolicy" },
{ FreeRDP_GatewayRpcTransport, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_GatewayRpcTransport" },
{ FreeRDP_GatewayUdpTransport, FREERDP_SETTINGS_TYPE_BOOL, "FreeRDP_GatewayUdpTransport" },
{ FreeRDP_GatewayUseSameCredentials, FREERDP_SETTINGS_TYPE_BOOL,
diff --git a/libfreerdp/common/test/CMakeLists.txt b/libfreerdp/common/test/CMakeLists.txt
index c1f871b..da832a8 100644
--- a/libfreerdp/common/test/CMakeLists.txt
+++ b/libfreerdp/common/test/CMakeLists.txt
@@ -8,7 +8,7 @@ set(${MODULE_PREFIX}_TESTS
TestAddinArgv.c
TestCommonAssistance.c)
-set(${MODULE_PREFIX}_FUZZERS
+set(FUZZERS
TestFuzzCommonAssistanceParseFileBuffer.c
TestFuzzCommonAssistanceBinToHexString.c
TestFuzzCommonAssistanceHexStringToBin.c)
@@ -21,17 +21,8 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} freerdp winpr)
-if (BUILD_FUZZERS)
- foreach(test ${${MODULE_PREFIX}_FUZZERS})
- get_filename_component(TestName ${test} NAME_WE)
- add_executable(${TestName} ${test})
- # Use PUBLIC to force 'fuzzer_config' for all dependent targets.
- target_link_libraries(${TestName} PUBLIC freerdp winpr fuzzer_config)
- add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
- set_target_properties(${TestName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
- add_dependencies(fuzzers ${TestName})
- endforeach()
-endif (BUILD_FUZZERS)
+include (AddFuzzerTest)
+add_fuzzer_test("${FUZZERS}" "freerdp winpr")
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
diff --git a/libfreerdp/core/aad.c b/libfreerdp/core/aad.c
index 72204d7..15eabed 100644
--- a/libfreerdp/core/aad.c
+++ b/libfreerdp/core/aad.c
@@ -210,8 +210,8 @@ cJSON* cJSON_ParseWithLength(const char* value, size_t buffer_length)
static INLINE const char* aad_auth_result_to_string(DWORD code)
{
-#define ERROR_CASE(cd, x) \
- if (cd == (DWORD)(x)) \
+#define ERROR_CASE(cd, x) \
+ if ((cd) == (DWORD)(x)) \
return #x;
ERROR_CASE(code, S_OK)
diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c
index 427e434..e8df920 100644
--- a/libfreerdp/core/capabilities.c
+++ b/libfreerdp/core/capabilities.c
@@ -168,7 +168,7 @@ static BOOL rdp_apply_general_capability_set(rdpSettings* settings, const rdpSet
settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
settings->LongCredentialsSupported = src->LongCredentialsSupported;
- settings->AutoReconnectionEnabled = src->AutoReconnectionEnabled;
+ settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
if (!src->FastPathOutput)
settings->FastPathOutput = FALSE;
@@ -223,7 +223,8 @@ static BOOL rdp_read_general_capability_set(wStream* s, rdpSettings* settings)
settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE;
settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) ? TRUE : FALSE;
- settings->AutoReconnectionEnabled = (extraFlags & AUTORECONNECT_SUPPORTED) ? TRUE : FALSE;
+ settings->AutoReconnectionPacketSupported =
+ (extraFlags & AUTORECONNECT_SUPPORTED) ? TRUE : FALSE;
settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) ? TRUE : FALSE;
settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) ? TRUE : FALSE;
settings->RefreshRect = refreshRectSupport;
@@ -252,7 +253,7 @@ static BOOL rdp_write_general_capability_set(wStream* s, const rdpSettings* sett
if (settings->NoBitmapCompressionHeader)
extraFlags |= NO_BITMAP_COMPRESSION_HDR;
- if (settings->AutoReconnectionEnabled)
+ if (settings->AutoReconnectionPacketSupported)
extraFlags |= AUTORECONNECT_SUPPORTED;
if (settings->FastPathOutput)
diff --git a/libfreerdp/core/childsession.c b/libfreerdp/core/childsession.c
index 3bed262..f9d5b2c 100644
--- a/libfreerdp/core/childsession.c
+++ b/libfreerdp/core/childsession.c
@@ -2,7 +2,7 @@
* FreeRDP: A Remote Desktop Protocol Implementation
* Named pipe transport
*
- * Copyright 2023 David Fort <contact@hardening-consulting.com>
+ * 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.
@@ -18,15 +18,29 @@
*/
#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);
@@ -44,47 +58,192 @@ static int transport_bio_named_write(BIO* bio, const char* buf, int size)
BIO_clear_flags(bio, BIO_FLAGS_WRITE);
DWORD written = 0;
+ UINT64 start = GetTickCount64();
BOOL ret = WriteFile(ptr->hFile, buf, size, &written, NULL);
- WLog_VRB(TAG, "transport_bio_named_write(%d)=%d written=%d", size, ret, written);
+ // winpr_HexDump(TAG, WLOG_DEBUG, buf, size);
if (!ret)
- return -1;
+ {
+ WLog_VRB(TAG, "error or deferred");
+ return 0;
+ }
+
+ WLog_VRB(TAG, "(%d)=%d written=%d duration=%d", size, ret, written, GetTickCount64() - start);
if (written == 0)
- return -1;
+ {
+ WLog_VRB(TAG, "closed on write");
+ return 0;
+ }
return 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;
+
+ 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_READ);
+ BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ);
- DWORD readBytes = 0;
- BOOL ret = ReadFile(ptr->hFile, buf, size, &readBytes, NULL);
- WLog_VRB(TAG, "transport_bio_named_read(%d)=%d read=%d", size, ret, readBytes);
- if (!ret)
+ if (ptr->blocking)
{
- if (GetLastError() == ERROR_NO_DATA)
- BIO_set_flags(bio, (BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ));
- return -1;
+ 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;
+ 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;
+ 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;
+ }
+ }
}
- if (readBytes == 0)
+ int ret = MIN(size, ringbuffer_used(&ptr->readBuffer));
+ if (ret)
{
- BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY));
- return 0;
+ DataChunk chunks[2];
+ int nchunks = ringbuffer_peek(&ptr->readBuffer, chunks, 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, ret);
+
+ WLog_VRB(TAG, "(%d)=%d nchunks=%d", size, ret, nchunks);
+ }
+ else
+ {
+ ret = -1;
+ }
+
+ if (!ringbuffer_used(&ptr->readBuffer))
+ {
+ if (!ptr->opInProgress && !doReadOp(ptr))
+ {
+ WLog_ERR(TAG, "error rearming read");
+ return -1;
+ }
}
- return readBytes;
+ if (ret <= 0)
+ BIO_set_flags(bio, (BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ));
+
+ return ret;
}
static int transport_bio_named_puts(BIO* bio, const char* str)
@@ -100,7 +259,7 @@ static int transport_bio_named_gets(BIO* bio, char* str, int size)
WINPR_ASSERT(bio);
WINPR_ASSERT(str);
- return transport_bio_named_write(bio, str, size);
+ return transport_bio_named_read(bio, str, size);
}
static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
@@ -119,7 +278,7 @@ static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
if (!BIO_get_init(bio) || !arg2)
return 0;
- *((HANDLE*)arg2) = ptr->hFile;
+ *((HANDLE*)arg2) = ptr->readEvent;
return 1;
case BIO_C_SET_HANDLE:
BIO_set_init(bio, 1);
@@ -127,18 +286,25 @@ static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* 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;
}
@@ -173,17 +339,34 @@ static long transport_bio_named_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
return status;
}
-static int transport_bio_named_uninit(BIO* bio)
+static void BIO_NAMED_free(WINPR_BIO_NAMED* ptr)
{
- WINPR_ASSERT(bio);
- WINPR_BIO_NAMED* ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
+ if (!ptr)
+ return;
- if (ptr && ptr->hFile)
+ if (ptr->hFile)
{
CloseHandle(ptr->hFile);
ptr->hFile = NULL;
}
+ if (ptr->readEvent)
+ {
+ CloseHandle(ptr->readEvent);
+ ptr->readEvent = NULL;
+ }
+
+ 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;
@@ -192,15 +375,27 @@ static int transport_bio_named_uninit(BIO* bio)
static int transport_bio_named_new(BIO* bio)
{
WINPR_ASSERT(bio);
- BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
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(NULL, TRUE, FALSE, NULL);
+ 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)
@@ -211,13 +406,10 @@ static int transport_bio_named_free(BIO* bio)
return 0;
transport_bio_named_uninit(bio);
- ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
+ ptr = (WINPR_BIO_NAMED*)BIO_get_data(bio);
if (ptr)
- {
BIO_set_data(bio, NULL);
- free(ptr);
- }
return 1;
}
@@ -292,10 +484,28 @@ static BOOL createChildSessionTransport(HANDLE* pFile)
goto out;
}
+ const BYTE startOfPath[] = { '\\', 0, '\\', 0, '.', 0, '\\', 0 };
+ if (_wcsncmp(pipePath, (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);
+ }
+
ConvertWCharNToUtf8(pipePath, 0x80, pipePathA, sizeof(pipePathA));
WLog_DBG(TAG, "child session is at '%s'", pipePathA);
- HANDLE f = CreateFileW(pipePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+ HANDLE f = CreateFileW(pipePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL);
if (f == INVALID_HANDLE_VALUE)
{
WLog_ERR(TAG, "error when connecting to local named pipe");
diff --git a/libfreerdp/core/client.c b/libfreerdp/core/client.c
index 1bfc617..7898a9d 100644
--- a/libfreerdp/core/client.c
+++ b/libfreerdp/core/client.c
@@ -661,6 +661,8 @@ static int freerdp_channels_process_sync(rdpChannels* channels, freerdp* instanc
int status = TRUE;
wMessage message = { 0 };
+ WINPR_ASSERT(channels);
+
while (MessageQueue_Peek(channels->queue, &message, TRUE))
{
freerdp_channels_process_message(instance, &message);
@@ -728,6 +730,8 @@ int freerdp_channels_process_pending_messages(freerdp* instance)
*/
BOOL freerdp_channels_check_fds(rdpChannels* channels, freerdp* instance)
{
+ WINPR_ASSERT(channels);
+
if (WaitForSingleObject(MessageQueue_Event(channels->queue), 0) == WAIT_OBJECT_0)
{
freerdp_channels_process_sync(channels, instance);
@@ -742,6 +746,8 @@ UINT freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance)
CHANNEL_OPEN_DATA* pChannelOpenData = NULL;
CHANNEL_CLIENT_DATA* pChannelClientData = NULL;
+ WINPR_ASSERT(channels);
+
if (!channels->connected)
return 0;
@@ -808,8 +814,6 @@ void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
}
}
- channels->clientDataCount = 0;
-
for (int index = 0; index < channels->openDataCount; index++)
{
pChannelOpenData = &channels->openDataList[index];
@@ -818,6 +822,7 @@ void freerdp_channels_close(rdpChannels* channels, freerdp* instance)
channels->openDataCount = 0;
channels->initDataCount = 0;
+ channels->clientDataCount = 0;
WINPR_ASSERT(instance->context);
WINPR_ASSERT(instance->context->settings);
diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c
index 3abfa93..240a29f 100644
--- a/libfreerdp/core/connection.c
+++ b/libfreerdp/core/connection.c
@@ -622,11 +622,10 @@ BOOL rdp_client_redirect(rdpRdp* rdp)
if (!rdp_client_disconnect_and_clear(rdp))
return FALSE;
+ /* Only disconnect & close the channels here.
+ * they will be discarded and recreated after the new settings have been applied. */
freerdp_channels_disconnect(rdp->context->channels, rdp->context->instance);
freerdp_channels_close(rdp->context->channels, rdp->context->instance);
- freerdp_channels_free(rdp->context->channels);
- rdp->context->channels = freerdp_channels_new(rdp->context->instance);
- WINPR_ASSERT(rdp->context->channels);
if (rdp_redirection_apply_settings(rdp) != 0)
return FALSE;
@@ -684,14 +683,10 @@ BOOL rdp_client_redirect(rdpRdp* rdp)
if (!IFCALLRESULT(TRUE, rdp->context->instance->Redirect, rdp->context->instance))
return FALSE;
- BOOL ok = IFCALLRESULT(TRUE, rdp->context->instance->LoadChannels, rdp->context->instance);
+ BOOL ok = utils_reload_channels(rdp->context);
if (!ok)
return FALSE;
- if (CHANNEL_RC_OK !=
- freerdp_channels_pre_connect(rdp->context->channels, rdp->context->instance))
- return FALSE;
-
status = rdp_client_connect(rdp);
if (status)
@@ -782,7 +777,6 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
Stream_Zero(s, 8);
Stream_SealLength(s);
status = transport_write(rdp->mcs->transport, s);
- Stream_Free(s, TRUE);
if (status < 0)
goto end;
@@ -829,6 +823,7 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp)
ret = TRUE;
end:
+ Stream_Free(s, TRUE);
free(crypt_client_random);
if (!ret)
diff --git a/libfreerdp/core/credssp_auth.c b/libfreerdp/core/credssp_auth.c
index c14dbe1..8b4c0cb 100644
--- a/libfreerdp/core/credssp_auth.c
+++ b/libfreerdp/core/credssp_auth.c
@@ -808,6 +808,7 @@ static SecurityFunctionTable* auth_resolve_sspi_table(const rdpSettings* setting
if (!hSSPI)
{
WLog_ERR(TAG, "Failed to load SSPI module: %s", module_name);
+ free(sspi_module);
return FALSE;
}
diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c
index 29d907a..3660e24 100644
--- a/libfreerdp/core/freerdp.c
+++ b/libfreerdp/core/freerdp.c
@@ -84,7 +84,6 @@ static void sig_abort_connect(int signum, const char* signame, void* ctx)
static int freerdp_connect_begin(freerdp* instance)
{
BOOL rc = 0;
- UINT status2 = CHANNEL_RC_OK;
rdpRdp* rdp = NULL;
BOOL status = TRUE;
rdpSettings* settings = NULL;
@@ -121,16 +120,9 @@ static int freerdp_connect_begin(freerdp* instance)
freerdp_settings_print_warnings(settings);
if (status)
- {
- if (!rdp_set_backup_settings(rdp))
- return 0;
-
- WINPR_ASSERT(instance->LoadChannels);
- if (!instance->LoadChannels(instance))
- return 0;
-
- status2 = freerdp_channels_pre_connect(instance->context->channels, instance);
- }
+ status = rdp_set_backup_settings(rdp);
+ if (status)
+ status = utils_reload_channels(instance->context);
KeyboardLayout = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout);
switch (KeyboardLayout)
@@ -151,7 +143,7 @@ static int freerdp_connect_begin(freerdp* instance)
break;
}
- if (!status || (status2 != CHANNEL_RC_OK))
+ if (!status)
{
rdpContext* context = instance->context;
WINPR_ASSERT(context);
@@ -413,8 +405,8 @@ static BOOL freerdp_prevent_session_lock(rdpContext* context)
if (now - in->lastInputTimestamp > FakeMouseMotionInterval)
{
WLog_Print(context->log, WLOG_DEBUG,
- "fake mouse move: x=%d y=%d lastInputTimestamp=%d "
- "FakeMouseMotionInterval=%d",
+ "fake mouse move: x=%d y=%d lastInputTimestamp=%" PRIu64 " "
+ "FakeMouseMotionInterval=%" PRIu32,
in->lastX, in->lastY, in->lastInputTimestamp, FakeMouseMotionInterval);
BOOL status = freerdp_input_send_mouse_event(context->input, PTR_FLAGS_MOVE, in->lastX,
diff --git a/libfreerdp/core/gateway/arm.c b/libfreerdp/core/gateway/arm.c
index 9848c48..d506c75 100644
--- a/libfreerdp/core/gateway/arm.c
+++ b/libfreerdp/core/gateway/arm.c
@@ -549,6 +549,7 @@ static BOOL arm_pick_base64Utf16Field(const cJSON* json, const char* name, BYTE*
if (!output1 || !len1)
{
WLog_ERR(TAG, "error when first unbase64 for %s", name);
+ free(output1);
return FALSE;
}
@@ -558,6 +559,7 @@ static BOOL arm_pick_base64Utf16Field(const cJSON* json, const char* name, BYTE*
if (!output2 || !len2)
{
WLog_ERR(TAG, "error when decode('utf-16') for %s", name);
+ free(output2);
return FALSE;
}
@@ -567,6 +569,7 @@ static BOOL arm_pick_base64Utf16Field(const cJSON* json, const char* name, BYTE*
if (!output || !*plen)
{
WLog_ERR(TAG, "error when second unbase64 for %s", name);
+ free(output);
return FALSE;
}
@@ -842,7 +845,11 @@ static BOOL arm_handle_bad_request(rdpArm* arm, const HttpResponse* response, BO
0)
{
*retry = TRUE;
- WLog_DBG(TAG, "Starting your VM. It may take up to 5 minutes");
+ const cJSON* message = cJSON_GetObjectItemCaseSensitive(json, "Message");
+ if (!cJSON_IsString(message) || !message->valuestring)
+ WLog_WARN(TAG, "Starting your VM. It may take up to 5 minutes");
+ else
+ WLog_WARN(TAG, "%s", message->valuestring);
}
else
{
diff --git a/libfreerdp/core/gateway/http.c b/libfreerdp/core/gateway/http.c
index cf70b3b..a7cdaab 100644
--- a/libfreerdp/core/gateway/http.c
+++ b/libfreerdp/core/gateway/http.c
@@ -322,8 +322,9 @@ static BOOL list_append(HttpContext* context, WINPR_FORMAT_ARG const char* str,
}
else
sstr = Pragma;
- free(context->Pragma);
+ Pragma = NULL;
+ free(context->Pragma);
context->Pragma = sstr;
rc = TRUE;
@@ -830,7 +831,10 @@ static BOOL http_response_parse_header_field(HttpResponse* response, const char*
const char* value)
{
BOOL status = TRUE;
- if (!response || !name)
+
+ WINPR_ASSERT(response);
+
+ if (!name)
return FALSE;
if (_stricmp(name, "Content-Length") == 0)
@@ -924,6 +928,10 @@ static BOOL http_response_parse_header_field(HttpResponse* response, const char*
*separator = '\0';
CookieName = value;
CookieValue = separator + 1;
+
+ if (!CookieName || !CookieValue)
+ return FALSE;
+
if (*CookieValue == '"')
{
char* p = CookieValue;
@@ -944,9 +952,6 @@ static BOOL http_response_parse_header_field(HttpResponse* response, const char*
}
*p = '\0';
}
-
- if (!CookieName || !CookieValue)
- return FALSE;
}
else
{
@@ -1053,12 +1058,13 @@ static void http_response_print(wLog* log, DWORD level, const HttpResponse* resp
freerdp_http_status_string_format(status, buffer, ARRAYSIZE(buffer)));
for (size_t i = 0; i < response->count; i++)
- WLog_Print(log, level, "[%" PRIuz "] %s", i, response->lines[i]);
+ WLog_Print(log, WLOG_DEBUG, "[%" PRIuz "] %s", i, response->lines[i]);
if (response->ReasonPhrase)
WLog_Print(log, level, "[reason] %s", response->ReasonPhrase);
- WLog_Print(log, level, "[body][%" PRIuz "] %s", response->BodyLength, response->BodyContent);
+ WLog_Print(log, WLOG_TRACE, "[body][%" PRIuz "] %s", response->BodyLength,
+ response->BodyContent);
}
static BOOL http_use_content_length(const char* cur)
diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c
index c6d952b..484b599 100644
--- a/libfreerdp/core/gateway/rdg.c
+++ b/libfreerdp/core/gateway/rdg.c
@@ -89,15 +89,6 @@
#define HTTP_TUNNEL_PACKET_FIELD_PAA_COOKIE 0x1
#define HTTP_TUNNEL_PACKET_FIELD_REAUTH 0x2
-/* HTTP tunnel redir flags. */
-#define HTTP_TUNNEL_REDIR_ENABLE_ALL 0x80000000
-#define HTTP_TUNNEL_REDIR_DISABLE_ALL 0x40000000
-#define HTTP_TUNNEL_REDIR_DISABLE_DRIVE 0x1
-#define HTTP_TUNNEL_REDIR_DISABLE_PRINTER 0x2
-#define HTTP_TUNNEL_REDIR_DISABLE_PORT 0x4
-#define HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD 0x8
-#define HTTP_TUNNEL_REDIR_DISABLE_PNP 0x10
-
/* HTTP tunnel response fields present flags. */
#define HTTP_TUNNEL_RESPONSE_FIELD_TUNNEL_ID 0x1
#define HTTP_TUNNEL_RESPONSE_FIELD_CAPS 0x2
@@ -146,6 +137,7 @@ struct rdp_rdg
rdg_http_encoding_context transferEncoding;
SmartcardCertInfo* smartcard;
+ wLog* log;
};
enum
@@ -261,15 +253,17 @@ static const char* capabilities_enum_to_string(UINT32 capabilities)
return flags_to_string(capabilities, capabilities_enum, ARRAYSIZE(capabilities_enum));
}
-static BOOL rdg_read_http_unicode_string(wStream* s, const WCHAR** string, UINT16* lengthInBytes)
+static BOOL rdg_read_http_unicode_string(wLog* log, wStream* s, const WCHAR** string,
+ UINT16* lengthInBytes)
{
UINT16 strLenBytes = 0;
size_t rem = Stream_GetRemainingLength(s);
/* Read length of the string */
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
{
- WLog_ERR(TAG, "Could not read stream length, only have %" PRIuz " bytes", rem);
+ WLog_Print(log, WLOG_ERROR, "Could not read stream length, only have %" PRIuz " bytes",
+ rem);
return FALSE;
}
Stream_Read_UINT16(s, strLenBytes);
@@ -280,8 +274,9 @@ static BOOL rdg_read_http_unicode_string(wStream* s, const WCHAR** string, UINT1
/* seek past the string - if this fails something is wrong */
if (!Stream_SafeSeek(s, strLenBytes))
{
- WLog_ERR(TAG, "Could not read stream data, only have %" PRIuz " bytes, expected %" PRIu16,
- rem - 4, strLenBytes);
+ WLog_Print(log, WLOG_ERROR,
+ "Could not read stream data, only have %" PRIuz " bytes, expected %" PRIu16,
+ rem - 4, strLenBytes);
return FALSE;
}
@@ -362,7 +357,13 @@ static int rdg_socket_read(BIO* bio, BYTE* pBuffer, size_t size,
}
}
-static BOOL rdg_read_all(rdpTls* tls, BYTE* buffer, size_t size,
+static BOOL rdg_shall_abort(rdpRdg* rdg)
+{
+ WINPR_ASSERT(rdg);
+ return freerdp_shall_disconnect_context(rdg->context);
+}
+
+static BOOL rdg_read_all(rdpContext* context, rdpTls* tls, BYTE* buffer, size_t size,
rdg_http_encoding_context* transferEncoding)
{
size_t readCount = 0;
@@ -370,6 +371,9 @@ static BOOL rdg_read_all(rdpTls* tls, BYTE* buffer, size_t size,
while (readCount < size)
{
+ if (freerdp_shall_disconnect_context(context))
+ return FALSE;
+
int status = rdg_socket_read(tls->bio, pBuffer, size - readCount, transferEncoding);
if (status <= 0)
{
@@ -396,7 +400,7 @@ static wStream* rdg_receive_packet(rdpRdg* rdg)
if (!s)
return NULL;
- if (!rdg_read_all(rdg->tlsOut, Stream_Buffer(s), header, &rdg->transferEncoding))
+ if (!rdg_read_all(rdg->context, rdg->tlsOut, Stream_Buffer(s), header, &rdg->transferEncoding))
{
Stream_Free(s, TRUE);
return NULL;
@@ -412,8 +416,8 @@ static wStream* rdg_receive_packet(rdpRdg* rdg)
return NULL;
}
- if (!rdg_read_all(rdg->tlsOut, Stream_Buffer(s) + header, (int)packetLength - (int)header,
- &rdg->transferEncoding))
+ if (!rdg_read_all(rdg->context, rdg->tlsOut, Stream_Buffer(s) + header,
+ (int)packetLength - (int)header, &rdg->transferEncoding))
{
Stream_Free(s, TRUE);
return NULL;
@@ -699,7 +703,7 @@ out:
return s;
}
-static BOOL rdg_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
+static BOOL rdg_recv_auth_token(wLog* log, rdpCredsspAuth* auth, HttpResponse* response)
{
size_t len = 0;
const char* token64 = NULL;
@@ -719,7 +723,7 @@ static BOOL rdg_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
case HTTP_STATUS_OK:
break;
default:
- http_response_log_error_status(WLog_Get(TAG), WLOG_WARN, response);
+ http_response_log_error_status(log, WLOG_WARN, response);
return FALSE;
}
@@ -738,6 +742,8 @@ static BOOL rdg_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
authToken.cbBuffer = authTokenLength;
credssp_auth_take_input_buffer(auth, &authToken);
}
+ else
+ free(authTokenData);
rc = credssp_auth_authenticate(auth);
if (rc < 0)
@@ -746,7 +752,7 @@ static BOOL rdg_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
return TRUE;
}
-static BOOL rdg_skip_seed_payload(rdpTls* tls, SSIZE_T lastResponseLength,
+static BOOL rdg_skip_seed_payload(rdpContext* context, rdpTls* tls, size_t lastResponseLength,
rdg_http_encoding_context* transferEncoding)
{
BYTE seed_payload[10] = { 0 };
@@ -755,9 +761,9 @@ static BOOL rdg_skip_seed_payload(rdpTls* tls, SSIZE_T lastResponseLength,
/* Per [MS-TSGU] 3.3.5.1 step 4, after final OK response RDG server sends
* random "seed" payload of limited size. In practice it's 10 bytes.
*/
- if (lastResponseLength < (SSIZE_T)size)
+ if (lastResponseLength < size)
{
- if (!rdg_read_all(tls, seed_payload, size - lastResponseLength, transferEncoding))
+ if (!rdg_read_all(context, tls, seed_payload, size - lastResponseLength, transferEncoding))
{
return FALSE;
}
@@ -774,14 +780,14 @@ static BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
BYTE verMajor = 0;
BYTE verMinor = 0;
const char* error = NULL;
- WLog_DBG(TAG, "Handshake response received");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Handshake response received");
if (rdg->state != RDG_CLIENT_STATE_HANDSHAKE)
{
return FALSE;
}
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 10))
return FALSE;
Stream_Read_UINT32(s, errorCode);
@@ -790,14 +796,14 @@ static BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
Stream_Read_UINT16(s, serverVersion);
Stream_Read_UINT16(s, extendedAuth);
error = rpc_error_to_string(errorCode);
- WLog_DBG(TAG,
- "errorCode=%s, verMajor=%" PRId8 ", verMinor=%" PRId8 ", serverVersion=%" PRId16
- ", extendedAuth=%s",
- error, verMajor, verMinor, serverVersion, extended_auth_to_string(extendedAuth));
+ WLog_Print(rdg->log, WLOG_DEBUG,
+ "errorCode=%s, verMajor=%" PRId8 ", verMinor=%" PRId8 ", serverVersion=%" PRId16
+ ", extendedAuth=%s",
+ error, verMajor, verMinor, serverVersion, extended_auth_to_string(extendedAuth));
if (FAILED((HRESULT)errorCode))
{
- WLog_ERR(TAG, "Handshake error %s", error);
+ WLog_Print(rdg->log, WLOG_ERROR, "Handshake error %s", error);
freerdp_set_last_error_log(rdg->context, errorCode);
return FALSE;
}
@@ -815,8 +821,8 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
/* Seek over tunnelId (4 bytes) */
if (!Stream_SafeSeek(s, 4))
{
- WLog_ERR(TAG, "Short tunnelId, got %" PRIuz ", expected 4",
- Stream_GetRemainingLength(s));
+ WLog_Print(rdg->log, WLOG_ERROR, "Short tunnelId, got %" PRIuz ", expected 4",
+ Stream_GetRemainingLength(s));
return FALSE;
}
}
@@ -824,11 +830,11 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
if (fieldsPresent & HTTP_TUNNEL_RESPONSE_FIELD_CAPS)
{
UINT32 caps = 0;
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 4))
return FALSE;
Stream_Read_UINT32(s, caps);
- WLog_DBG(TAG, "capabilities=%s", capabilities_enum_to_string(caps));
+ WLog_Print(rdg->log, WLOG_DEBUG, "capabilities=%s", capabilities_enum_to_string(caps));
}
if (fieldsPresent & HTTP_TUNNEL_RESPONSE_FIELD_SOH_REQ)
@@ -836,14 +842,15 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
/* Seek over nonce (20 bytes) */
if (!Stream_SafeSeek(s, 20))
{
- WLog_ERR(TAG, "Short nonce, got %" PRIuz ", expected 20", Stream_GetRemainingLength(s));
+ WLog_Print(rdg->log, WLOG_ERROR, "Short nonce, got %" PRIuz ", expected 20",
+ Stream_GetRemainingLength(s));
return FALSE;
}
/* Read serverCert */
- if (!rdg_read_http_unicode_string(s, NULL, NULL))
+ if (!rdg_read_http_unicode_string(rdg->log, s, NULL, NULL))
{
- WLog_ERR(TAG, "Failed to read server certificate");
+ WLog_Print(rdg->log, WLOG_ERROR, "Failed to read server certificate");
return FALSE;
}
}
@@ -858,9 +865,9 @@ static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16
WINPR_ASSERT(context->instance);
/* Read message string and invoke callback */
- if (!rdg_read_http_unicode_string(s, &msg, &msgLenBytes))
+ if (!rdg_read_http_unicode_string(rdg->log, s, &msg, &msgLenBytes))
{
- WLog_ERR(TAG, "Failed to read consent message");
+ WLog_Print(rdg->log, WLOG_ERROR, "Failed to read consent message");
return FALSE;
}
@@ -877,14 +884,14 @@ static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
UINT16 fieldsPresent = 0;
UINT32 errorCode = 0;
const char* error = NULL;
- WLog_DBG(TAG, "Tunnel response received");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Tunnel response received");
if (rdg->state != RDG_CLIENT_STATE_TUNNEL_CREATE)
{
return FALSE;
}
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 10))
return FALSE;
Stream_Read_UINT16(s, serverVersion);
@@ -892,12 +899,12 @@ static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
Stream_Read_UINT16(s, fieldsPresent);
Stream_Seek_UINT16(s); /* reserved */
error = rpc_error_to_string(errorCode);
- WLog_DBG(TAG, "serverVersion=%" PRId16 ", errorCode=%s, fieldsPresent=%s", serverVersion, error,
- tunnel_response_fields_present_to_string(fieldsPresent));
+ WLog_Print(rdg->log, WLOG_DEBUG, "serverVersion=%" PRId16 ", errorCode=%s, fieldsPresent=%s",
+ serverVersion, error, tunnel_response_fields_present_to_string(fieldsPresent));
if (FAILED((HRESULT)errorCode))
{
- WLog_ERR(TAG, "Tunnel creation error %s", error);
+ WLog_Print(rdg->log, WLOG_ERROR, "Tunnel creation error %s", error);
freerdp_set_last_error_log(rdg->context, errorCode);
return FALSE;
}
@@ -913,31 +920,66 @@ static BOOL rdg_process_tunnel_authorization_response(rdpRdg* rdg, wStream* s)
UINT32 errorCode = 0;
UINT16 fieldsPresent = 0;
const char* error = NULL;
- WLog_DBG(TAG, "Tunnel authorization received");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Tunnel authorization received");
if (rdg->state != RDG_CLIENT_STATE_TUNNEL_AUTHORIZE)
{
return FALSE;
}
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 8))
return FALSE;
Stream_Read_UINT32(s, errorCode);
Stream_Read_UINT16(s, fieldsPresent);
Stream_Seek_UINT16(s); /* reserved */
error = rpc_error_to_string(errorCode);
- WLog_DBG(TAG, "errorCode=%s, fieldsPresent=%s", error,
- tunnel_authorization_response_fields_present_to_string(fieldsPresent));
+ WLog_Print(rdg->log, WLOG_DEBUG, "errorCode=%s, fieldsPresent=%s", error,
+ tunnel_authorization_response_fields_present_to_string(fieldsPresent));
/* [MS-TSGU] 3.7.5.2.7 */
if (errorCode != S_OK && errorCode != E_PROXY_QUARANTINE_ACCESSDENIED)
{
- WLog_ERR(TAG, "Tunnel authorization error %s", error);
+ WLog_Print(rdg->log, WLOG_ERROR, "Tunnel authorization error %s", error);
freerdp_set_last_error_log(rdg->context, errorCode);
return FALSE;
}
+ if (fieldsPresent & HTTP_TUNNEL_AUTH_RESPONSE_FIELD_REDIR_FLAGS)
+ {
+ UINT32 redirFlags = 0;
+ if (!Stream_CheckAndLogRequiredCapacityWLog(rdg->log, s, 4))
+ return FALSE;
+ Stream_Read_UINT32(s, redirFlags);
+
+ rdpContext* context = rdg->context;
+ if (!utils_apply_gateway_policy(rdg->log, context, redirFlags, "RDG"))
+ return FALSE;
+ }
+
+ if (fieldsPresent & HTTP_TUNNEL_AUTH_RESPONSE_FIELD_IDLE_TIMEOUT)
+ {
+ UINT32 idleTimeout = 0;
+ if (!Stream_CheckAndLogRequiredCapacityWLog(rdg->log, s, 4))
+ return FALSE;
+ Stream_Read_UINT32(s, idleTimeout);
+ WLog_Print(rdg->log, WLOG_DEBUG, "[IDLE_TIMEOUT] idleTimeout=%" PRIu32 ": TODO: unused",
+ idleTimeout);
+ }
+
+ if (fieldsPresent & HTTP_TUNNEL_AUTH_RESPONSE_FIELD_SOH_RESPONSE)
+ {
+ UINT16 cbLen = 0;
+ if (!Stream_CheckAndLogRequiredCapacityWLog(rdg->log, s, 2))
+ return FALSE;
+ Stream_Read_UINT16(s, cbLen);
+
+ WLog_Print(rdg->log, WLOG_DEBUG, "[SOH_RESPONSE] cbLen=%" PRIu16 ": TODO: unused", cbLen);
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, cbLen))
+ return FALSE;
+ Stream_Seek(s, cbLen);
+ }
+
return rdg_send_channel_create(rdg);
}
@@ -955,8 +997,8 @@ static BOOL rdg_process_extauth_sspi(rdpRdg* rdg, wStream* s)
if (errorCode != ERROR_SUCCESS)
{
- WLog_ERR(TAG, "EXTAUTH_SSPI_NTLM failed with error %s [0x%08X]",
- GetSecurityStatusString(errorCode), errorCode);
+ WLog_Print(rdg->log, WLOG_ERROR, "EXTAUTH_SSPI_NTLM failed with error %s [0x%08X]",
+ GetSecurityStatusString(errorCode), errorCode);
return FALSE;
}
@@ -972,6 +1014,8 @@ static BOOL rdg_process_extauth_sspi(rdpRdg* rdg, wStream* s)
}
authTokenData = malloc(authBlobLen);
+ if (authTokenData == NULL)
+ return FALSE;
Stream_Read(s, authTokenData, authBlobLen);
authToken.pvBuffer = authTokenData;
@@ -993,27 +1037,27 @@ static BOOL rdg_process_channel_response(rdpRdg* rdg, wStream* s)
UINT16 fieldsPresent = 0;
UINT32 errorCode = 0;
const char* error = NULL;
- WLog_DBG(TAG, "Channel response received");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Channel response received");
if (rdg->state != RDG_CLIENT_STATE_CHANNEL_CREATE)
{
return FALSE;
}
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 8))
return FALSE;
Stream_Read_UINT32(s, errorCode);
Stream_Read_UINT16(s, fieldsPresent);
Stream_Seek_UINT16(s); /* reserved */
error = rpc_error_to_string(errorCode);
- WLog_DBG(TAG, "channel response errorCode=%s, fieldsPresent=%s", error,
- channel_response_fields_present_to_string(fieldsPresent));
+ WLog_Print(rdg->log, WLOG_DEBUG, "channel response errorCode=%s, fieldsPresent=%s", error,
+ channel_response_fields_present_to_string(fieldsPresent));
if (FAILED((HRESULT)errorCode))
{
- WLog_ERR(TAG, "channel response errorCode=%s, fieldsPresent=%s", error,
- channel_response_fields_present_to_string(fieldsPresent));
+ WLog_Print(rdg->log, WLOG_ERROR, "channel response errorCode=%s, fieldsPresent=%s", error,
+ channel_response_fields_present_to_string(fieldsPresent));
freerdp_set_last_error_log(rdg->context, errorCode);
return FALSE;
}
@@ -1029,7 +1073,7 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
UINT32 packetLength = 0;
Stream_SetPosition(s, 0);
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 8))
return FALSE;
Stream_Read_UINT16(s, type);
@@ -1038,7 +1082,8 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
if (Stream_Length(s) < packetLength)
{
- WLog_ERR(TAG, "Short packet %" PRIuz ", expected %" PRIuz, Stream_Length(s), packetLength);
+ WLog_Print(rdg->log, WLOG_ERROR, "Short packet %" PRIuz ", expected %" PRIuz,
+ Stream_Length(s), packetLength);
return FALSE;
}
@@ -1061,7 +1106,7 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
break;
case PKT_TYPE_DATA:
- WLog_ERR(TAG, "Unexpected packet type DATA");
+ WLog_Print(rdg->log, WLOG_ERROR, "Unexpected packet type DATA");
return FALSE;
case PKT_TYPE_EXTENDED_AUTH_MSG:
@@ -1069,7 +1114,7 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
break;
default:
- WLog_ERR(TAG, "PKG TYPE 0x%x not implemented", type);
+ WLog_Print(rdg->log, WLOG_ERROR, "PKG TYPE 0x%x not implemented", type);
return FALSE;
}
@@ -1325,7 +1370,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
* sending an answer if it is not happy with the http request */
if (!response)
{
- WLog_INFO(TAG, "RD Gateway HTTP transport broken.");
+ WLog_Print(rdg->log, WLOG_INFO, "RD Gateway HTTP transport broken.");
*rpcFallback = TRUE;
return FALSE;
}
@@ -1336,7 +1381,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
{
case HTTP_STATUS_NOT_FOUND:
{
- WLog_INFO(TAG, "RD Gateway does not support HTTP transport.");
+ WLog_Print(rdg->log, WLOG_INFO, "RD Gateway does not support HTTP transport.");
*rpcFallback = TRUE;
http_response_free(response);
@@ -1345,13 +1390,13 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
case HTTP_STATUS_OK:
break;
default:
- http_response_log_error_status(WLog_Get(TAG), WLOG_WARN, response);
+ http_response_log_error_status(rdg->log, WLOG_WARN, response);
break;
}
while (!credssp_auth_is_complete(rdg->auth))
{
- if (!rdg_recv_auth_token(rdg->auth, response))
+ if (!rdg_recv_auth_token(rdg->log, rdg->auth, response))
{
http_response_free(response);
return FALSE;
@@ -1367,7 +1412,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
response = http_response_recv(tls, TRUE);
if (!response)
{
- WLog_INFO(TAG, "RD Gateway HTTP transport broken.");
+ WLog_Print(rdg->log, WLOG_INFO, "RD Gateway HTTP transport broken.");
*rpcFallback = TRUE;
return FALSE;
}
@@ -1388,7 +1433,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
if (!response)
{
- WLog_INFO(TAG, "RD Gateway HTTP transport broken.");
+ WLog_Print(rdg->log, WLOG_INFO, "RD Gateway HTTP transport broken.");
*rpcFallback = TRUE;
return FALSE;
}
@@ -1398,9 +1443,9 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
const size_t bodyLength = http_response_get_body_length(response);
const TRANSFER_ENCODING encoding = http_response_get_transfer_encoding(response);
const BOOL isWebsocket = http_response_is_websocket(rdg->http, response);
- http_response_free(response);
- WLog_DBG(TAG, "%s authorization result: %s", method,
- freerdp_http_status_string_format(statusCode, buffer, ARRAYSIZE(buffer)));
+
+ WLog_Print(rdg->log, WLOG_DEBUG, "%s authorization result: %s", method,
+ freerdp_http_status_string_format(statusCode, buffer, ARRAYSIZE(buffer)));
switch (statusCode)
{
@@ -1408,11 +1453,14 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
/* old rdg endpoint without websocket support, don't request websocket for RDG_IN_DATA
*/
http_context_enable_websocket_upgrade(rdg->http, FALSE);
+ http_response_free(response);
break;
case HTTP_STATUS_DENIED:
freerdp_set_last_error_log(rdg->context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
+ http_response_free(response);
return FALSE;
case HTTP_STATUS_SWITCH_PROTOCOLS:
+ http_response_free(response);
if (!isWebsocket)
{
/*
@@ -1442,7 +1490,8 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
}
return TRUE;
default:
- http_response_log_error_status(WLog_Get(TAG), WLOG_WARN, response);
+ http_response_log_error_status(rdg->log, WLOG_WARN, response);
+ http_response_free(response);
return FALSE;
}
@@ -1455,7 +1504,7 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char*
rdg->transferEncoding.context.chunked.headerFooterPos = 0;
rdg->transferEncoding.context.chunked.state = ChunkStateLenghHeader;
}
- if (!rdg_skip_seed_payload(tls, bodyLength, &rdg->transferEncoding))
+ if (!rdg_skip_seed_payload(rdg->context, tls, bodyLength, &rdg->transferEncoding))
{
return FALSE;
}
@@ -1522,7 +1571,7 @@ BOOL rdg_connect(rdpRdg* rdg, DWORD timeout, BOOL* rpcFallback)
{
if (rdg->transferEncoding.isWebsocketTransport)
{
- WLog_DBG(TAG, "Upgraded to websocket. RDG_IN_DATA not required");
+ WLog_Print(rdg->log, WLOG_DEBUG, "Upgraded to websocket. RDG_IN_DATA not required");
}
else
{
@@ -1717,7 +1766,7 @@ static BOOL rdg_process_close_packet(rdpRdg* rdg, wStream* s)
UINT32 packetSize = 12;
/* Read error code */
- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
+ if (!Stream_CheckAndLogRequiredLengthWLog(rdg->log, s, 4))
return FALSE;
Stream_Read_UINT32(s, errorCode);
@@ -1769,9 +1818,9 @@ static BOOL rdg_process_service_message(rdpRdg* rdg, wStream* s)
WINPR_ASSERT(context->instance);
/* Read message string */
- if (!rdg_read_http_unicode_string(s, &msg, &msgLenBytes))
+ if (!rdg_read_http_unicode_string(rdg->log, s, &msg, &msgLenBytes))
{
- WLog_ERR(TAG, "Failed to read string");
+ WLog_Print(rdg->log, WLOG_ERROR, "Failed to read string");
return FALSE;
}
@@ -1783,7 +1832,7 @@ static BOOL rdg_process_unknown_packet(rdpRdg* rdg, int type)
{
WINPR_UNUSED(rdg);
WINPR_UNUSED(type);
- WLog_WARN(TAG, "Unknown Control Packet received: %X", type);
+ WLog_Print(rdg->log, WLOG_WARN, "Unknown Control Packet received: %X", type);
return TRUE;
}
@@ -1808,6 +1857,11 @@ static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLengt
while (readCount < payloadSize)
{
+ if (rdg_shall_abort(rdg))
+ {
+ Stream_Free(s, TRUE);
+ return FALSE;
+ }
status = rdg_socket_read(rdg->tlsOut->bio, Stream_Pointer(s), payloadSize - readCount,
&rdg->transferEncoding);
@@ -1852,7 +1906,8 @@ static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLengt
case PKT_TYPE_SERVICE_MESSAGE:
if (!s)
{
- WLog_ERR(TAG, "PKT_TYPE_SERVICE_MESSAGE requires payload but none was sent");
+ WLog_Print(rdg->log, WLOG_ERROR,
+ "PKT_TYPE_SERVICE_MESSAGE requires payload but none was sent");
return FALSE;
}
status = rdg_process_service_message(rdg, s);
@@ -1880,6 +1935,9 @@ static int rdg_read_data_packet(rdpRdg* rdg, BYTE* buffer, int size)
while (readCount < sizeof(RdgPacketHeader))
{
+ if (rdg_shall_abort(rdg))
+ return -1;
+
status = rdg_socket_read(rdg->tlsOut->bio, (BYTE*)(&header) + readCount,
(int)sizeof(RdgPacketHeader) - (int)readCount,
&rdg->transferEncoding);
@@ -1916,6 +1974,8 @@ static int rdg_read_data_packet(rdpRdg* rdg, BYTE* buffer, int size)
while (readCount < 2)
{
+ if (rdg_shall_abort(rdg))
+ return -1;
status =
rdg_socket_read(rdg->tlsOut->bio, (BYTE*)(&rdg->packetRemainingCount) + readCount,
2 - (int)readCount, &rdg->transferEncoding);
@@ -2153,6 +2213,7 @@ rdpRdg* rdg_new(rdpContext* context)
if (rdg)
{
+ rdg->log = WLog_Get(TAG);
rdg->state = RDG_CLIENT_STATE_INITIAL;
rdg->context = context;
rdg->settings = rdg->context->settings;
@@ -2212,8 +2273,8 @@ rdpRdg* rdg_new(rdpContext* context)
break;
default:
- WLog_DBG(TAG, "RDG extended authentication method %d not supported",
- rdg->extAuth);
+ WLog_Print(rdg->log, WLOG_DEBUG,
+ "RDG extended authentication method %d not supported", rdg->extAuth);
}
}
diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c
index 3ab833a..8101e53 100644
--- a/libfreerdp/core/gateway/tsg.c
+++ b/libfreerdp/core/gateway/tsg.c
@@ -35,6 +35,7 @@
#include "rpc_bind.h"
#include "rpc_client.h"
#include "tsg.h"
+#include "../utils.h"
#include "../../crypto/opensslcompat.h"
#define TAG FREERDP_TAG("core.gateway.tsg")
@@ -1590,7 +1591,7 @@ fail:
return FALSE;
}
-static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu,
+static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu,
CONTEXT_HANDLE* tunnelContext, UINT32* tunnelId)
{
BOOL rc = FALSE;
@@ -1728,7 +1729,41 @@ fail:
return FALSE;
}
-static BOOL TsProxyAuthorizeTunnelReadResponse(wLog* log, RPC_PDU* pdu)
+static UINT32 tsg_redir_to_flags(const TSG_REDIRECTION_FLAGS* redirect)
+{
+ UINT32 flags = 0;
+ if (redirect->enableAllRedirections)
+ flags |= HTTP_TUNNEL_REDIR_ENABLE_ALL;
+ if (redirect->disableAllRedirections)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_ALL;
+
+ if (redirect->driveRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_DRIVE;
+ if (redirect->printerRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_PRINTER;
+ if (redirect->portRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_PORT;
+ if (redirect->clipboardRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD;
+ if (redirect->pnpRedirectionDisabled)
+ flags |= HTTP_TUNNEL_REDIR_DISABLE_PNP;
+ return flags;
+}
+
+static BOOL tsg_redirect_apply(rdpTsg* tsg, const TSG_REDIRECTION_FLAGS* redirect)
+{
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(redirect);
+
+ rdpTransport* transport = tsg->transport;
+ WINPR_ASSERT(transport);
+
+ rdpContext* context = transport_get_context(transport);
+ UINT32 redirFlags = tsg_redir_to_flags(redirect);
+ return utils_apply_gateway_policy(tsg->log, context, redirFlags, "TSG");
+}
+
+static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
{
BOOL rc = FALSE;
UINT32 SwitchValue = 0;
@@ -1736,8 +1771,12 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(wLog* log, RPC_PDU* pdu)
TSG_PACKET packet = { 0 };
UINT32 PacketPtr = 0;
UINT32 PacketResponsePtr = 0;
- if (!pdu)
- return FALSE;
+
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(pdu);
+
+ wLog* log = tsg->log;
+ WINPR_ASSERT(log);
if (!tsg_ndr_pointer_read(log, pdu->s, &index, &PacketPtr, TRUE))
goto fail;
@@ -1773,6 +1812,9 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(wLog* log, RPC_PDU* pdu)
goto fail;
rc = TRUE;
+
+ if (packet.tsgPacket.packetResponse.flags & TSG_PACKET_TYPE_QUARREQUEST)
+ rc = tsg_redirect_apply(tsg, &packet.tsgPacket.packetResponse.redirectionFlags);
fail:
return rc;
}
@@ -1846,7 +1888,7 @@ static BOOL TsProxyReadPacketSTringMessage(rdpTsg* tsg, wStream* s, TSG_PACKET_S
return tsg_ndr_read_string(tsg->log, s, &msg->msgBuffer, msg->msgBytes);
}
-static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
+static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
{
BOOL rc = FALSE;
UINT32 index = 0;
@@ -1991,20 +2033,20 @@ fail:
static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext)
{
- size_t count = 0;
- wStream* s = NULL;
- rdpRpc* rpc = NULL;
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(tunnelContext);
+
WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCreateChannelWriteRequest");
- if (!tsg || !tsg->rpc || !tunnelContext || !tsg->Hostname)
+ if (!tsg->rpc || !tsg->Hostname)
return FALSE;
- rpc = tsg->rpc;
- count = _wcslen(tsg->Hostname) + 1;
+ rdpRpc* rpc = tsg->rpc;
+ const size_t count = _wcslen(tsg->Hostname) + 1;
if (count > UINT32_MAX)
return FALSE;
- s = Stream_New(NULL, 60 + count * 2);
+ wStream* s = Stream_New(NULL, 60 + count * 2);
if (!s)
return FALSE;
@@ -2036,14 +2078,16 @@ fail:
return FALSE;
}
-static BOOL TsProxyCreateChannelReadResponse(wLog* log, RPC_PDU* pdu,
+static BOOL TsProxyCreateChannelReadResponse(wLog* log, const RPC_PDU* pdu,
CONTEXT_HANDLE* channelContext, UINT32* channelId)
{
BOOL rc = FALSE;
- WLog_Print(log, WLOG_DEBUG, "TsProxyCreateChannelReadResponse");
- if (!pdu)
- return FALSE;
+ WINPR_ASSERT(log);
+ WINPR_ASSERT(pdu);
+ WINPR_ASSERT(channelId);
+
+ WLog_Print(log, WLOG_DEBUG, "TsProxyCreateChannelReadResponse");
if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 28))
goto fail;
@@ -2068,15 +2112,15 @@ fail:
static BOOL TsProxyCloseChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context)
{
- wStream* s = NULL;
- rdpRpc* rpc = NULL;
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(context);
+
WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCloseChannelWriteRequest");
- if (!tsg || !tsg->rpc || !context)
- return FALSE;
+ rdpRpc* rpc = tsg->rpc;
+ WINPR_ASSERT(rpc);
- rpc = tsg->rpc;
- s = Stream_New(NULL, 20);
+ wStream* s = Stream_New(NULL, 20);
if (!s)
return FALSE;
@@ -2090,7 +2134,7 @@ fail:
return FALSE;
}
-static BOOL TsProxyCloseChannelReadResponse(wLog* log, RPC_PDU* pdu, CONTEXT_HANDLE* context)
+static BOOL TsProxyCloseChannelReadResponse(wLog* log, const RPC_PDU* pdu, CONTEXT_HANDLE* context)
{
BOOL rc = FALSE;
WLog_Print(log, WLOG_DEBUG, "TsProxyCloseChannelReadResponse");
@@ -2124,15 +2168,15 @@ fail:
static BOOL TsProxyCloseTunnelWriteRequest(rdpTsg* tsg, const CONTEXT_HANDLE* context)
{
- wStream* s = NULL;
- rdpRpc* rpc = NULL;
+ WINPR_ASSERT(tsg);
+ WINPR_ASSERT(context);
+
WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyCloseTunnelWriteRequest");
- if (!tsg || !tsg->rpc || !context)
- return FALSE;
+ rdpRpc* rpc = tsg->rpc;
+ WINPR_ASSERT(rpc);
- rpc = tsg->rpc;
- s = Stream_New(NULL, 20);
+ wStream* s = Stream_New(NULL, 20);
if (!s)
return FALSE;
@@ -2146,13 +2190,15 @@ fail:
return FALSE;
}
-static BOOL TsProxyCloseTunnelReadResponse(wLog* log, RPC_PDU* pdu, CONTEXT_HANDLE* context)
+static BOOL TsProxyCloseTunnelReadResponse(wLog* log, const RPC_PDU* pdu, CONTEXT_HANDLE* context)
{
BOOL rc = FALSE;
- WLog_Print(log, WLOG_DEBUG, "TsProxyCloseTunnelReadResponse");
- if (!pdu || !context)
- return FALSE;
+ WINPR_ASSERT(log);
+ WINPR_ASSERT(pdu);
+ WINPR_ASSERT(context);
+
+ WLog_Print(log, WLOG_DEBUG, "TsProxyCloseTunnelReadResponse");
if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 24))
goto fail;
@@ -2294,7 +2340,7 @@ static BOOL tsg_proxy_reauth(rdpTsg* tsg)
return tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
}
-BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
+BOOL tsg_recv_pdu(rdpTsg* tsg, const RPC_PDU* pdu)
{
BOOL rc = FALSE;
RpcClientCall* call = NULL;
@@ -2342,10 +2388,10 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu)
case TSG_STATE_CONNECTED:
{
- CONTEXT_HANDLE* TunnelContext = NULL;
- TunnelContext = (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
+ CONTEXT_HANDLE* TunnelContext =
+ (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext;
- if (!TsProxyAuthorizeTunnelReadResponse(tsg->log, pdu))
+ if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu))
{
WLog_Print(tsg->log, WLOG_ERROR, "TsProxyAuthorizeTunnelReadResponse failure");
return FALSE;
diff --git a/libfreerdp/core/gateway/tsg.h b/libfreerdp/core/gateway/tsg.h
index 626a7ac..81b50a7 100644
--- a/libfreerdp/core/gateway/tsg.h
+++ b/libfreerdp/core/gateway/tsg.h
@@ -109,7 +109,7 @@ FREERDP_LOCAL BOOL tsg_proxy_begin(rdpTsg* tsg);
FREERDP_LOCAL BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout);
FREERDP_LOCAL BOOL tsg_disconnect(rdpTsg* tsg);
-FREERDP_LOCAL BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu);
+FREERDP_LOCAL BOOL tsg_recv_pdu(rdpTsg* tsg, const RPC_PDU* pdu);
FREERDP_LOCAL BOOL tsg_check_event_handles(rdpTsg* tsg);
FREERDP_LOCAL DWORD tsg_get_event_handles(rdpTsg* tsg, HANDLE* events, DWORD count);
diff --git a/libfreerdp/core/gateway/wst.c b/libfreerdp/core/gateway/wst.c
index 00581d3..87194da 100644
--- a/libfreerdp/core/gateway/wst.c
+++ b/libfreerdp/core/gateway/wst.c
@@ -199,6 +199,8 @@ static BOOL wst_recv_auth_token(rdpCredsspAuth* auth, HttpResponse* response)
authToken.cbBuffer = authTokenLength;
credssp_auth_take_input_buffer(auth, &authToken);
}
+ else
+ free(authTokenData);
rc = credssp_auth_authenticate(auth);
if (rc < 0)
diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c
index d99ee86..733a763 100644
--- a/libfreerdp/core/gcc.c
+++ b/libfreerdp/core/gcc.c
@@ -1704,7 +1704,13 @@ BOOL gcc_read_server_security_data(wStream* s, rdpMcs* mcs)
Stream_Read_UINT32(s, settings->ServerCertificateLength); /* serverCertLen */
if ((settings->ServerRandomLength == 0) || (settings->ServerCertificateLength == 0))
+ {
+ WLog_ERR(TAG,
+ "Invalid ServerRandom (length=%" PRIu32 ") or ServerCertificate (length=%" PRIu32
+ ")",
+ settings->ServerRandomLength, settings->ServerCertificateLength);
return FALSE;
+ }
if (!Stream_CheckAndLogRequiredLength(TAG, s, settings->ServerRandomLength))
return FALSE;
diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c
index 0d8e90e..7d6eec1 100644
--- a/libfreerdp/core/info.c
+++ b/libfreerdp/core/info.c
@@ -469,8 +469,12 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s)
rdpSettings* settings = rdp->settings;
WINPR_ASSERT(settings);
- const UINT16 clientAddressFamily =
- settings->IPv6Enabled ? ADDRESS_FAMILY_INET6 : ADDRESS_FAMILY_INET;
+ UINT16 clientAddressFamily = ADDRESS_FAMILY_INET;
+ if (settings->ConnectChildSession)
+ clientAddressFamily = 0x0000;
+ else if (settings->IPv6Enabled)
+ clientAddressFamily = ADDRESS_FAMILY_INET6;
+
WCHAR* clientAddress = ConvertUtf8ToWCharAlloc(settings->ClientAddress, &cbClientAddress);
if (cbClientAddress > (UINT16_MAX / sizeof(WCHAR)))
diff --git a/libfreerdp/core/input.h b/libfreerdp/core/input.h
index c67153b..9a1585d 100644
--- a/libfreerdp/core/input.h
+++ b/libfreerdp/core/input.h
@@ -38,7 +38,7 @@ typedef struct
rdpInputProxy* proxy;
wMessageQueue* queue;
- UINT32 lastInputTimestamp;
+ UINT64 lastInputTimestamp;
UINT16 lastX;
UINT16 lastY;
} rdp_input_internal;
diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c
index 99d4fa2..aeb7bb2 100644
--- a/libfreerdp/core/license.c
+++ b/libfreerdp/core/license.c
@@ -1114,10 +1114,9 @@ BOOL license_generate_hwid(rdpLicense* license)
const char* hostname = license->rdp->settings->ClientHostname;
wStream* s = Stream_StaticInit(&buffer, license->HardwareId, 4);
Stream_Write_UINT32(s, license->PlatformId);
- Stream_Free(s, TRUE);
hashTarget = (const BYTE*)hostname;
- targetLen = strlen(hostname);
+ targetLen = hostname ? strlen(hostname) : 0;
}
/* Allow FIPS override for use of MD5 here, really this does not have to be MD5 as we are just
@@ -1723,14 +1722,15 @@ void license_free_scope_list(SCOPE_LIST* scopeList)
BOOL license_send_license_info(rdpLicense* license, const LICENSE_BLOB* calBlob,
const BYTE* signature, size_t signature_length)
{
- wStream* s = license_send_stream_init(license);
-
WINPR_ASSERT(calBlob);
WINPR_ASSERT(signature);
WINPR_ASSERT(license->certificate);
const rdpCertInfo* info = freerdp_certificate_get_info(license->certificate);
+ if (!info)
+ return FALSE;
+ wStream* s = license_send_stream_init(license);
if (!s)
return FALSE;
@@ -2802,18 +2802,25 @@ BOOL license_server_send_request(rdpLicense* license)
return license_set_state(license, LICENSE_STATE_REQUEST);
}
-static BOOL license_set_string(const char* what, const char* value, WCHAR** dst, UINT32* dstLen)
+static BOOL license_set_string(const char* what, const char* value, BYTE** bdst, UINT32* dstLen)
{
WINPR_ASSERT(what);
WINPR_ASSERT(value);
- WINPR_ASSERT(dst);
+ WINPR_ASSERT(bdst);
WINPR_ASSERT(dstLen);
+ union
+ {
+ WCHAR** w;
+ BYTE** b;
+ } cnv;
+ cnv.b = bdst;
+
size_t len = 0;
- *dst = (BYTE*)ConvertUtf8ToWCharAlloc(value, &len);
- if (!*dst || (len > UINT32_MAX / sizeof(WCHAR)))
+ *cnv.w = ConvertUtf8ToWCharAlloc(value, &len);
+ if (!*cnv.w || (len > UINT32_MAX / sizeof(WCHAR)))
{
- WLog_ERR(TAG, "license->ProductInfo: %s == %p || %" PRIu32 " > UINT32_MAX", what, *dst,
+ WLog_ERR(TAG, "license->ProductInfo: %s == %p || %" PRIu32 " > UINT32_MAX", what, *cnv.w,
len);
return FALSE;
}
diff --git a/libfreerdp/core/listener.c b/libfreerdp/core/listener.c
index 5a9c1e2..a7592da 100644
--- a/libfreerdp/core/listener.c
+++ b/libfreerdp/core/listener.c
@@ -188,10 +188,11 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value,
sizeof(option_value)) == -1)
- WLog_ERR(TAG, "setsockopt");
+ WLog_ERR(TAG, "setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR)");
#ifndef _WIN32
- fcntl(sockfd, F_SETFL, O_NONBLOCK);
+ if (fcntl(sockfd, F_SETFL, O_NONBLOCK) != 0)
+ WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
#else
arg = 1;
ioctlsocket(sockfd, FIONBIO, &arg);
@@ -256,7 +257,14 @@ static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char*
return FALSE;
}
- fcntl(sockfd, F_SETFL, O_NONBLOCK);
+ 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);
diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c
index ddee306..577e0b4 100644
--- a/libfreerdp/core/nla.c
+++ b/libfreerdp/core/nla.c
@@ -1148,6 +1148,11 @@ static BOOL nla_read_TSCspDataDetail(WinPrAsn1Decoder* dec, rdpSettings* setting
static BOOL nla_read_KERB_TICKET_LOGON(rdpNla* nla, wStream* s, KERB_TICKET_LOGON* ticket)
{
+ WINPR_ASSERT(nla);
+
+ if (!ticket)
+ return FALSE;
+
/* mysterious extra 16 bytes before TGS/TGT content */
if (!Stream_CheckAndLogRequiredLength(TAG, s, 16 + 16))
return FALSE;
@@ -1244,7 +1249,7 @@ static BOOL nla_read_ts_credentials(rdpNla* nla, SecBuffer* data)
WinPrAsn1_OctetString credentials = { 0 };
BOOL error = FALSE;
WinPrAsn1_INTEGER credType = -1;
- BOOL ret = true;
+ BOOL ret = TRUE;
WINPR_ASSERT(nla);
WINPR_ASSERT(data);
diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c
index 9d00c66..42c4c21 100644
--- a/libfreerdp/core/peer.c
+++ b/libfreerdp/core/peer.c
@@ -1495,7 +1495,8 @@ void freerdp_peer_free(freerdp_peer* client)
return;
sspi_FreeAuthIdentity(&client->identity);
- closesocket((SOCKET)client->sockfd);
+ if (client->sockfd >= 0)
+ closesocket((SOCKET)client->sockfd);
free(client);
}
@@ -1511,6 +1512,7 @@ static BOOL freerdp_peer_transport_setup(freerdp_peer* client)
if (!transport_attach(rdp->transport, client->sockfd))
return FALSE;
+ client->sockfd = -1;
if (!transport_set_recv_callbacks(rdp->transport, peer_recv_callback, client))
return FALSE;
diff --git a/libfreerdp/core/proxy.c b/libfreerdp/core/proxy.c
index 9312c22..ecb9b34 100644
--- a/libfreerdp/core/proxy.c
+++ b/libfreerdp/core/proxy.c
@@ -284,14 +284,12 @@ static BOOL check_no_proxy(rdpSettings* settings, const char* no_proxy)
void proxy_read_environment(rdpSettings* settings, char* envname)
{
- DWORD envlen = 0;
- char* env = NULL;
- envlen = GetEnvironmentVariableA(envname, NULL, 0);
+ const DWORD envlen = GetEnvironmentVariableA(envname, NULL, 0);
- if (!envlen)
+ if (!envlen || (envlen <= 1))
return;
- env = calloc(1, envlen);
+ char* env = calloc(1, envlen);
if (!env)
{
diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c
index c1f6d3a..466a9a7 100644
--- a/libfreerdp/core/rdp.c
+++ b/libfreerdp/core/rdp.c
@@ -261,7 +261,7 @@ BOOL rdp_read_share_control_header(rdpRdp* rdp, wStream* s, UINT16* tpktLength,
WLog_Print(rdp->log, WLOG_DEBUG,
"[Flow control PDU] type=%s, tpktLength=%" PRIuz ", remainingLength=%" PRIuz,
pdu_type_to_str(*type, buffer, sizeof(buffer)), tpktLength ? *tpktLength : 0,
- *remainingLength);
+ remainingLength ? *remainingLength : 0);
return TRUE;
}
@@ -2259,7 +2259,7 @@ rdpRdp* rdp_new(rdpContext* context)
/* Keep a backup copy of settings for later comparisons */
if (!rdp_set_backup_settings(rdp))
- return FALSE;
+ goto fail;
rdp->settings->instance = context->instance;
diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c
index 653bf0a..96cf00b 100644
--- a/libfreerdp/core/security.c
+++ b/libfreerdp/core/security.c
@@ -592,6 +592,7 @@ static void fips_expand_key_bits(const BYTE* in, size_t in_len, BYTE* out, size_
}
else
{
+ WINPR_ASSERT(p + 1 < sizeof(buf));
/* c is accumulator */
BYTE c = (BYTE)(buf[p] << r) & 0xFF;
c |= buf[p + 1] >> (8 - r);
diff --git a/libfreerdp/core/smartcardlogon.c b/libfreerdp/core/smartcardlogon.c
index d5907cf..f3f5581 100644
--- a/libfreerdp/core/smartcardlogon.c
+++ b/libfreerdp/core/smartcardlogon.c
@@ -222,11 +222,14 @@ static BOOL set_info_certificate(SmartcardCertInfo* cert, BYTE* certBytes, DWORD
return FALSE;
}
- if (userFilter && cert->userHint && strcmp(cert->userHint, userFilter) != 0)
+ if (userFilter && (!cert->upn || (strcmp(cert->upn, userFilter) != 0)))
{
- WLog_DBG(TAG, "discarding non matching cert by user %s@%s", cert->userHint,
- cert->domainHint);
- return FALSE;
+ 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)
diff --git a/libfreerdp/core/test/CMakeLists.txt b/libfreerdp/core/test/CMakeLists.txt
index 3e0a652..ebd8fef 100644
--- a/libfreerdp/core/test/CMakeLists.txt
+++ b/libfreerdp/core/test/CMakeLists.txt
@@ -9,8 +9,9 @@ set(${MODULE_PREFIX}_TESTS
TestStreamDump.c
TestSettings.c)
-set(${MODULE_PREFIX}_FUZZERS
- TestFuzzCryptoCertificateDataSetPEM.c)
+set(FUZZERS
+ TestFuzzCryptoCertificateDataSetPEM.c
+)
if(WITH_SAMPLE AND WITH_SERVER AND NOT WIN32)
add_definitions(-DCMAKE_EXECUTABLE_SUFFIX="${CMAKE_EXECUTABLE_SUFFIX}")
@@ -32,16 +33,8 @@ add_definitions(-DTESTING_SRC_DIRECTORY="${PROJECT_SOURCE_DIR}")
target_link_libraries(${MODULE_NAME} freerdp winpr freerdp-client)
-if (BUILD_FUZZERS)
- foreach(test ${${MODULE_PREFIX}_FUZZERS})
- get_filename_component(TestName ${test} NAME_WE)
- add_executable(${TestName} ${test})
- target_link_libraries(${TestName} freerdp winpr freerdp-client fuzzer_config)
- add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
- set_target_properties(${TestName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
- add_dependencies(fuzzers ${TestName})
- endforeach()
-endif (BUILD_FUZZERS)
+include (AddFuzzerTest)
+add_fuzzer_test("${FUZZERS}" "freerdp winpr")
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h
index fb280e6..d966242 100644
--- a/libfreerdp/core/test/settings_property_lists.h
+++ b/libfreerdp/core/test/settings_property_lists.h
@@ -19,6 +19,7 @@ static const size_t bool_list_indices[] = {
FreeRDP_AutoDenyCertificate,
FreeRDP_AutoLogonEnabled,
FreeRDP_AutoReconnectionEnabled,
+ FreeRDP_AutoReconnectionPacketSupported,
FreeRDP_BitmapCacheEnabled,
FreeRDP_BitmapCachePersistEnabled,
FreeRDP_BitmapCacheV3Enabled,
@@ -68,6 +69,7 @@ static const size_t bool_list_indices[] = {
FreeRDP_GatewayHttpExtAuthSspiNtlm,
FreeRDP_GatewayHttpTransport,
FreeRDP_GatewayHttpUseWebsockets,
+ FreeRDP_GatewayIgnoreRedirectionPolicy,
FreeRDP_GatewayRpcTransport,
FreeRDP_GatewayUdpTransport,
FreeRDP_GatewayUseSameCredentials,
diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c
index e4cc570..a2a899b 100644
--- a/libfreerdp/core/transport.c
+++ b/libfreerdp/core/transport.c
@@ -197,8 +197,6 @@ static BOOL transport_default_attach(rdpTransport* transport, int sockfd)
if (!socketBio)
goto fail;
-
- BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
}
bufferedBio = BIO_new(BIO_s_buffered_socket());
@@ -206,8 +204,18 @@ static BOOL transport_default_attach(rdpTransport* transport, int sockfd)
goto fail;
if (socketBio)
+ {
bufferedBio = BIO_push(bufferedBio, socketBio);
- WINPR_ASSERT(bufferedBio);
+ if (!bufferedBio)
+ goto fail;
+
+ /* Attach the socket only when this function can no longer fail.
+ * This ensures solid ownership:
+ * - if this function fails, the caller is responsible to clean up
+ * - if this function is successful, the caller MUST NOT close the socket any more.
+ */
+ BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
+ }
transport->frontBio = bufferedBio;
return TRUE;
fail:
diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h
index 8b5c5c6..912fffd 100644
--- a/libfreerdp/core/transport.h
+++ b/libfreerdp/core/transport.h
@@ -58,6 +58,21 @@ FREERDP_LOCAL wStream* transport_send_stream_init(rdpTransport* transport, size_
FREERDP_LOCAL BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port,
DWORD timeout);
FREERDP_LOCAL BOOL transport_connect_childsession(rdpTransport* transport);
+
+/**! \brief Attach a socket to the transport layer
+ *
+ * The ownership of the socket provided by \b sockfd is taken if and only if the function is
+ * successful. In such a case the caller must no longer close or otherwise use the socket. If the
+ * function fails it is up to the caller to close the socket.
+ *
+ * The implementation can be overridden by
+ * transport_set_io_callbacks(rdpTransportIo::TransportAttach)
+ *
+ * \param transport The transport instance to attach the socket to
+ * \param sockfd The socket to attach to the transport
+ *
+ * \return \b TRUE in case of success, \b FALSE otherwise.
+ */
FREERDP_LOCAL BOOL transport_attach(rdpTransport* transport, int sockfd);
FREERDP_LOCAL BOOL transport_disconnect(rdpTransport* transport);
FREERDP_LOCAL BOOL transport_connect_rdp(rdpTransport* transport);
diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c
index db8ddef..cfc0abc 100644
--- a/libfreerdp/core/update.c
+++ b/libfreerdp/core/update.c
@@ -3322,6 +3322,10 @@ BOOL update_begin_paint(rdpUpdate* update)
WINPR_ASSERT(update->context);
+ BOOL rc = IFCALLRESULT(TRUE, update->BeginPaint, update->context);
+ if (!rc)
+ WLog_WARN(TAG, "BeginPaint call failed");
+
/* Reset the invalid regions, we start a new frame here. */
rdpGdi* gdi = update->context->gdi;
WINPR_ASSERT(gdi);
@@ -3335,10 +3339,6 @@ BOOL update_begin_paint(rdpUpdate* update)
hwnd->ninvalid = 0;
}
- BOOL rc = IFCALLRESULT(TRUE, update->BeginPaint, update->context);
- if (!rc)
- WLog_WARN(TAG, "BeginPaint call failed");
-
return rc;
}
diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c
index 1bcb090..f414611 100644
--- a/libfreerdp/core/utils.c
+++ b/libfreerdp/core/utils.c
@@ -25,6 +25,8 @@
#include <winpr/assert.h>
#include <freerdp/freerdp.h>
+#include <freerdp/channels/cliprdr.h>
+#include <freerdp/channels/rdpdr.h>
#include <freerdp/log.h>
#define TAG FREERDP_TAG("core.gateway.utils")
@@ -299,3 +301,182 @@ const char* utils_is_vsock(const char* hostname)
return &hostname[sizeof(vsock)];
return NULL;
}
+
+static BOOL remove_rdpdr_type(rdpSettings* settings, UINT32 type)
+{
+ RDPDR_DEVICE* printer = NULL;
+ do
+ {
+ printer = freerdp_device_collection_find_type(settings, type);
+ freerdp_device_collection_del(settings, printer);
+ freerdp_device_free(printer);
+ } while (printer);
+ return TRUE;
+}
+
+static BOOL disable_clipboard(rdpSettings* settings)
+{
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, FALSE))
+ return FALSE;
+ freerdp_static_channel_collection_del(settings, CLIPRDR_SVC_CHANNEL_NAME);
+ return TRUE;
+}
+
+static BOOL disable_drive(rdpSettings* settings)
+{
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectDrives, FALSE))
+ return FALSE;
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectHomeDrive, FALSE))
+ return FALSE;
+
+ return remove_rdpdr_type(settings, RDPDR_DTYP_FILESYSTEM);
+}
+
+static BOOL disable_printers(rdpSettings* settings)
+{
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectPrinters, FALSE))
+ return FALSE;
+
+ return remove_rdpdr_type(settings, RDPDR_DTYP_PRINT);
+}
+
+static BOOL disable_port(rdpSettings* settings)
+{
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectParallelPorts, FALSE))
+ return FALSE;
+ if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSerialPorts, FALSE))
+ return FALSE;
+ if (!remove_rdpdr_type(settings, RDPDR_DTYP_SERIAL))
+ return FALSE;
+ return remove_rdpdr_type(settings, RDPDR_DTYP_PARALLEL);
+}
+
+static BOOL disable_pnp(rdpSettings* settings)
+{
+ // TODO(akallabeth): [MS-RDPEPNP] related stuff is disabled.
+ return TRUE;
+}
+
+static BOOL apply_gw_policy(rdpContext* context)
+{
+ WINPR_ASSERT(context);
+ return utils_reload_channels(context);
+}
+
+BOOL utils_apply_gateway_policy(wLog* log, rdpContext* context, UINT32 flags, const char* module)
+{
+ WINPR_ASSERT(log);
+ WINPR_ASSERT(context);
+
+ rdpSettings* settings = context->settings;
+ WINPR_ASSERT(settings);
+
+ if (flags & HTTP_TUNNEL_REDIR_ENABLE_ALL)
+ {
+ WLog_Print(log, WLOG_DEBUG, "[%s] policy allows all redirections", module);
+ }
+ else if (freerdp_settings_get_bool(settings, FreeRDP_GatewayIgnoreRedirectionPolicy))
+ {
+ char buffer[128] = { 0 };
+ WLog_Print(log, WLOG_INFO, "[%s] policy ignored on user request %s", module,
+ utils_redir_flags_to_string(flags, buffer, sizeof(buffer)));
+ }
+ else if (flags & HTTP_TUNNEL_REDIR_DISABLE_ALL)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies all redirections", module);
+ if (!disable_drive(settings))
+ return FALSE;
+ if (!disable_printers(settings))
+ return FALSE;
+ if (!disable_clipboard(settings))
+ return FALSE;
+ if (!disable_port(settings))
+ return FALSE;
+ if (!disable_pnp(settings))
+ return FALSE;
+ if (!apply_gw_policy(context))
+ return FALSE;
+ }
+ else
+ {
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_DRIVE)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies drive redirections", module);
+ if (!disable_drive(settings))
+ return FALSE;
+ }
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PRINTER)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies printer redirections", module);
+ if (!disable_printers(settings))
+ return FALSE;
+ }
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PORT)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies port redirections", module);
+ if (!disable_port(settings))
+ return FALSE;
+ }
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies clipboard redirections", module);
+ if (!disable_clipboard(settings))
+ return FALSE;
+ }
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PNP)
+ {
+ WLog_Print(log, WLOG_INFO, "[%s] policy denies PNP redirections", module);
+ if (!disable_pnp(settings))
+ return FALSE;
+ }
+ if (flags != 0)
+ {
+ if (!apply_gw_policy(context))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+char* utils_redir_flags_to_string(UINT32 flags, char* buffer, size_t size)
+{
+ winpr_str_append("{", buffer, size, "");
+ if (flags & HTTP_TUNNEL_REDIR_ENABLE_ALL)
+ winpr_str_append("ENABLE_ALL", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_ALL)
+ winpr_str_append("DISABLE_ALL", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_DRIVE)
+ winpr_str_append("DISABLE_DRIVE", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PRINTER)
+ winpr_str_append("DISABLE_PRINTER", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PORT)
+ winpr_str_append("DISABLE_PORT", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD)
+ winpr_str_append("DISABLE_CLIPBOARD", buffer, size, "|");
+ if (flags & HTTP_TUNNEL_REDIR_DISABLE_PNP)
+ winpr_str_append("DISABLE_PNP", buffer, size, "|");
+
+ char fbuffer[16] = { 0 };
+ _snprintf(fbuffer, sizeof(fbuffer), "[0x%08" PRIx32 "]", flags);
+
+ winpr_str_append(fbuffer, buffer, size, " ");
+ winpr_str_append("{", buffer, size, "}");
+ return buffer;
+}
+
+BOOL utils_reload_channels(rdpContext* context)
+{
+ WINPR_ASSERT(context);
+
+ freerdp_channels_disconnect(context->channels, context->instance);
+ freerdp_channels_close(context->channels, context->instance);
+ freerdp_channels_free(context->channels);
+ context->channels = freerdp_channels_new(context->instance);
+ WINPR_ASSERT(context->channels);
+
+ BOOL rc = TRUE;
+ IFCALLRET(context->instance->LoadChannels, rc, context->instance);
+ if (rc)
+ return freerdp_channels_pre_connect(context->channels, context->instance) == CHANNEL_RC_OK;
+ return rc;
+}
diff --git a/libfreerdp/core/utils.h b/libfreerdp/core/utils.h
index 87fa272..54a7856 100644
--- a/libfreerdp/core/utils.h
+++ b/libfreerdp/core/utils.h
@@ -24,6 +24,15 @@
#include <winpr/winpr.h>
#include <freerdp/freerdp.h>
+/* HTTP tunnel redir flags. */
+#define HTTP_TUNNEL_REDIR_ENABLE_ALL 0x80000000
+#define HTTP_TUNNEL_REDIR_DISABLE_ALL 0x40000000
+#define HTTP_TUNNEL_REDIR_DISABLE_DRIVE 0x1
+#define HTTP_TUNNEL_REDIR_DISABLE_PRINTER 0x2
+#define HTTP_TUNNEL_REDIR_DISABLE_PORT 0x4
+#define HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD 0x8
+#define HTTP_TUNNEL_REDIR_DISABLE_PNP 0x10
+
typedef enum
{
AUTH_SUCCESS,
@@ -47,4 +56,9 @@ BOOL utils_str_copy(const char* value, char** dst);
const char* utils_is_vsock(const char* hostname);
+BOOL utils_apply_gateway_policy(wLog* log, rdpContext* context, UINT32 flags, const char* module);
+char* utils_redir_flags_to_string(UINT32 flags, char* buffer, size_t size);
+
+BOOL utils_reload_channels(rdpContext* context);
+
#endif /* FREERDP_LIB_CORE_UTILS_H */
diff --git a/libfreerdp/crypto/cert_common.c b/libfreerdp/crypto/cert_common.c
index 60ef60f..bd0abad 100644
--- a/libfreerdp/crypto/cert_common.c
+++ b/libfreerdp/crypto/cert_common.c
@@ -144,7 +144,10 @@ BOOL cert_info_allocate(rdpCertInfo* info, size_t size)
info->Modulus = (BYTE*)malloc(size);
if (!info->Modulus && (size > 0))
+ {
+ WLog_ERR(TAG, "Failed to allocate info->Modulus of size %" PRIuz, size);
return FALSE;
+ }
info->ModulusLength = (UINT32)size;
return TRUE;
}
@@ -154,7 +157,10 @@ BOOL cert_info_read_modulus(rdpCertInfo* info, size_t size, wStream* s)
if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
return FALSE;
if (size > UINT32_MAX)
+ {
+ WLog_ERR(TAG, "modulus size %" PRIuz " exceeds limit of %" PRIu32, size, UINT32_MAX);
return FALSE;
+ }
if (!cert_info_allocate(info, size))
return FALSE;
Stream_Read(s, info->Modulus, info->ModulusLength);
@@ -166,9 +172,15 @@ BOOL cert_info_read_exponent(rdpCertInfo* info, size_t size, wStream* s)
if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
return FALSE;
if (size > 4)
+ {
+ WLog_ERR(TAG, "exponent size %" PRIuz " exceeds limit of %" PRIu32, size, 4);
return FALSE;
+ }
if (!info->Modulus || (info->ModulusLength == 0))
+ {
+ WLog_ERR(TAG, "invalid modulus=%p [%" PRIu32 "]", info->Modulus, info->ModulusLength);
return FALSE;
+ }
Stream_Read(s, &info->exponent[4 - size], size);
crypto_reverse(info->Modulus, info->ModulusLength);
crypto_reverse(info->exponent, 4);
diff --git a/libfreerdp/crypto/certificate.c b/libfreerdp/crypto/certificate.c
index ddfe776..896b605 100644
--- a/libfreerdp/crypto/certificate.c
+++ b/libfreerdp/crypto/certificate.c
@@ -301,8 +301,8 @@ static BOOL certificate_read_x509_certificate(const rdpCertBlob* cert, rdpCertIn
size_t exponent_length = 0;
int error = 0;
- if (!cert || !info)
- return FALSE;
+ WINPR_ASSERT(cert);
+ WINPR_ASSERT(info);
cert_info_free(info);
@@ -571,6 +571,9 @@ fail2:
rc = TRUE;
fail:
+ if (!rc)
+ WLog_ERR(TAG, "failed to update x509 from rdpCertInfo");
+
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
if (rsa)
RSA_free(rsa);
@@ -600,7 +603,7 @@ static BOOL certificate_process_server_public_key(rdpCertificate* cert, wStream*
if (memcmp(magic, rsa_magic, sizeof(magic)) != 0)
{
- WLog_ERR(TAG, "magic error");
+ WLog_ERR(TAG, "invalid RSA magic bytes");
return FALSE;
}
@@ -612,14 +615,33 @@ static BOOL certificate_process_server_public_key(rdpCertificate* cert, wStream*
Stream_Read_UINT32(s, datalen);
Stream_Read(s, info->exponent, 4);
- if ((keylen <= 8) || (!Stream_CheckAndLogRequiredLength(TAG, s, keylen)))
+ if (keylen <= 8)
+ {
+ WLog_ERR(TAG, "Invalid RSA keylen=%" PRIu32 " <= 8", keylen);
return FALSE;
-
+ }
+ if (!Stream_CheckAndLogRequiredLength(TAG, s, keylen))
+ return FALSE;
+ if (keylen != (bitlen / 8ull) + 8ull)
+ {
+ WLog_ERR(TAG, "Invalid RSA key bitlen %" PRIu32 ", expected %" PRIu32, bitlen,
+ (keylen - 8) * 8);
+ return FALSE;
+ }
+ if (datalen != (bitlen / 8ull) - 1ull)
+ {
+ WLog_ERR(TAG, "Invalid RSA key datalen %" PRIu32 ", expected %" PRIu32, datalen,
+ (bitlen / 8ull) - 1ull);
+ return FALSE;
+ }
info->ModulusLength = keylen - 8;
BYTE* tmp = realloc(info->Modulus, info->ModulusLength);
if (!tmp)
+ {
+ WLog_ERR(TAG, "Failed to reallocate modulus of length %" PRIu32, info->ModulusLength);
return FALSE;
+ }
info->Modulus = tmp;
Stream_Read(s, info->Modulus, info->ModulusLength);
@@ -957,6 +979,7 @@ static BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* cert,
if (!res)
{
+ WLog_ERR(TAG, "Failed to read x509 certificate");
return FALSE;
}
@@ -1592,6 +1615,8 @@ BOOL freerdp_certificate_publickey_encrypt(const rdpCertificate* cert, const BYT
size_t outputSize = EVP_PKEY_size(pkey);
output = malloc(outputSize);
+ if (output == NULL)
+ goto out;
*pcbOutput = outputSize;
if (EVP_PKEY_encrypt_init(ctx) != 1 ||
diff --git a/libfreerdp/crypto/certificate_data.c b/libfreerdp/crypto/certificate_data.c
index a48beb4..04b5432 100644
--- a/libfreerdp/crypto/certificate_data.c
+++ b/libfreerdp/crypto/certificate_data.c
@@ -50,11 +50,21 @@ struct rdp_certificate_data
char* cached_pem;
};
+/* ensure our hostnames (and therefore filenames) always use the same capitalization.
+ * the user might have input random case, but we always need to have a sane
+ * baseline to compare against. */
+static char* ensure_lowercase(char* str, size_t length)
+{
+ const size_t len = strnlen(str, length);
+ for (size_t x = 0; x < len; x++)
+ str[x] = tolower(str[x]);
+ return str;
+}
static const char* freerdp_certificate_data_hash_(const char* hostname, UINT16 port, char* name,
size_t length)
{
_snprintf(name, length, "%s_%" PRIu16 ".pem", hostname, port);
- return name;
+ return ensure_lowercase(name, length);
}
static BOOL freerdp_certificate_data_load_cache(rdpCertificateData* data)
@@ -107,8 +117,7 @@ static rdpCertificateData* freerdp_certificate_data_new_nocopy(const char* hostn
certdata->hostname = _strdup(hostname);
if (!certdata->hostname)
goto fail;
- for (size_t i = 0; i < strlen(hostname); i++)
- certdata->hostname[i] = tolower(certdata->hostname[i]);
+ ensure_lowercase(certdata->hostname, strlen(certdata->hostname));
certdata->cert = xcert;
if (!freerdp_certificate_data_load_cache(certdata))
@@ -176,43 +185,44 @@ void freerdp_certificate_data_free(rdpCertificateData* data)
const char* freerdp_certificate_data_get_host(const rdpCertificateData* cert)
{
- WINPR_ASSERT(cert);
+ if (!cert)
+ return NULL;
return cert->hostname;
}
UINT16 freerdp_certificate_data_get_port(const rdpCertificateData* cert)
{
- WINPR_ASSERT(cert);
+ if (!cert)
+ return 0;
return cert->port;
}
const char* freerdp_certificate_data_get_pem(const rdpCertificateData* cert)
{
- WINPR_ASSERT(cert);
- WINPR_ASSERT(cert->cached_pem);
-
+ if (!cert)
+ return NULL;
return cert->cached_pem;
}
const char* freerdp_certificate_data_get_subject(const rdpCertificateData* cert)
{
- WINPR_ASSERT(cert);
- WINPR_ASSERT(cert->cached_subject);
+ if (!cert)
+ return NULL;
return cert->cached_subject;
}
const char* freerdp_certificate_data_get_issuer(const rdpCertificateData* cert)
{
- WINPR_ASSERT(cert);
- WINPR_ASSERT(cert->cached_issuer);
+ if (!cert)
+ return NULL;
return cert->cached_issuer;
}
const char* freerdp_certificate_data_get_fingerprint(const rdpCertificateData* cert)
{
- WINPR_ASSERT(cert);
- WINPR_ASSERT(cert->cached_fingerprint);
+ if (!cert)
+ return NULL;
return cert->cached_fingerprint;
}
@@ -241,8 +251,8 @@ BOOL freerdp_certificate_data_equal(const rdpCertificateData* a, const rdpCertif
const char* freerdp_certificate_data_get_hash(const rdpCertificateData* cert)
{
- WINPR_ASSERT(cert);
- WINPR_ASSERT(cert->cached_hash);
+ if (!cert)
+ return NULL;
return cert->cached_hash;
}
diff --git a/libfreerdp/crypto/privatekey.c b/libfreerdp/crypto/privatekey.c
index 159157c..55379d4 100644
--- a/libfreerdp/crypto/privatekey.c
+++ b/libfreerdp/crypto/privatekey.c
@@ -482,13 +482,19 @@ char* freerdp_key_get_param(const rdpPrivateKey* key, enum FREERDP_KEY_PARAM par
switch (param)
{
case FREERDP_KEY_PARAM_RSA_D:
+#if OPENSSL_VERSION_NUMBER >= 0x10101007L
cbn = RSA_get0_d(rsa);
+#endif
break;
case FREERDP_KEY_PARAM_RSA_E:
+#if OPENSSL_VERSION_NUMBER >= 0x10101007L
cbn = RSA_get0_e(rsa);
+#endif
break;
case FREERDP_KEY_PARAM_RSA_N:
+#if OPENSSL_VERSION_NUMBER >= 0x10101007L
cbn = RSA_get0_n(rsa);
+#endif
break;
default:
return NULL;
diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c
index 371b81b..2d40038 100644
--- a/libfreerdp/crypto/tls.c
+++ b/libfreerdp/crypto/tls.c
@@ -985,6 +985,7 @@ static int pollAndHandshake(rdpTls* tls)
case WAIT_OBJECT_0:
break;
case WAIT_TIMEOUT:
+ case WAIT_IO_COMPLETION:
continue;
default:
WLog_ERR(TAG, "error during WaitForSingleObject(): 0x%08" PRIX32 "", status);
@@ -1107,7 +1108,7 @@ TlsHandshakeResult freerdp_tls_accept_ex(rdpTls* tls, BIO* underlying, rdpSettin
* Disable SSL client site renegotiation.
*/
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && (OPENSSL_VERSION_NUMBER < 0x30000000L) && \
+#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) && (OPENSSL_VERSION_NUMBER < 0x30000000L) && \
!defined(LIBRESSL_VERSION_NUMBER)
options |= SSL_OP_NO_RENEGOTIATION;
#endif
diff --git a/libfreerdp/emu/scard/smartcard_emulate.c b/libfreerdp/emu/scard/smartcard_emulate.c
index b2809c3..d517bd6 100644
--- a/libfreerdp/emu/scard/smartcard_emulate.c
+++ b/libfreerdp/emu/scard/smartcard_emulate.c
@@ -19,6 +19,7 @@
*/
#include <freerdp/config.h>
+#include <freerdp/freerdp.h>
#include <winpr/crt.h>
#include <winpr/wlog.h>
@@ -1362,6 +1363,10 @@ LONG WINAPI Emulate_SCardGetStatusChangeA(SmartcardEmulationContext* smartcard,
SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
+ freerdp* inst =
+ freerdp_settings_get_pointer_writable(smartcard->settings, FreeRDP_instance);
+ WINPR_ASSERT(inst);
+
status = SCARD_E_TIMEOUT;
do
{
@@ -1410,6 +1415,11 @@ LONG WINAPI Emulate_SCardGetStatusChangeA(SmartcardEmulationContext* smartcard,
Sleep(diff);
if (dwTimeout != INFINITE)
dwTimeout -= MIN(dwTimeout, diff);
+ if (freerdp_shall_disconnect_context(inst->context))
+ {
+ status = SCARD_E_CANCELLED;
+ break;
+ }
} while (dwTimeout > 0);
}
@@ -1436,6 +1446,10 @@ LONG WINAPI Emulate_SCardGetStatusChangeW(SmartcardEmulationContext* smartcard,
SCardContext* value = HashTable_GetItemValue(smartcard->contexts, (const void*)hContext);
WINPR_ASSERT(value); /* Must be valid after Emulate_SCardIsValidContext */
+ freerdp* inst =
+ freerdp_settings_get_pointer_writable(smartcard->settings, FreeRDP_instance);
+ WINPR_ASSERT(inst);
+
status = SCARD_E_TIMEOUT;
do
{
@@ -1483,6 +1497,11 @@ LONG WINAPI Emulate_SCardGetStatusChangeW(SmartcardEmulationContext* smartcard,
Sleep(diff);
if (dwTimeout != INFINITE)
dwTimeout -= MIN(dwTimeout, diff);
+ if (freerdp_shall_disconnect_context(inst->context))
+ {
+ status = SCARD_E_CANCELLED;
+ break;
+ }
} while (dwTimeout > 0);
}
diff --git a/libfreerdp/emu/scard/smartcard_virtual_gids.c b/libfreerdp/emu/scard/smartcard_virtual_gids.c
index 3d4dda3..4f29c25 100644
--- a/libfreerdp/emu/scard/smartcard_virtual_gids.c
+++ b/libfreerdp/emu/scard/smartcard_virtual_gids.c
@@ -842,14 +842,14 @@ static BOOL vgids_get_public_key(vgidsContext* context, UINT16 doTag)
/* set response data */
Stream_SetPosition(response, 0);
context->responseData = response;
+ response = NULL;
rc = TRUE;
handle_error:
free(n);
free(e);
Stream_Free(pubKey, TRUE);
- if (!rc)
- Stream_Free(response, TRUE);
+ Stream_Free(response, TRUE);
return rc;
}
@@ -1047,8 +1047,10 @@ static BOOL vgids_perform_digital_signature(vgidsContext* context)
{ g_PKCS1_SHA256, sizeof(g_PKCS1_SHA256), EVP_sha256() },
{ g_PKCS1_SHA384, sizeof(g_PKCS1_SHA384), EVP_sha384() },
{ g_PKCS1_SHA512, sizeof(g_PKCS1_SHA512), EVP_sha512() },
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L
{ g_PKCS1_SHA512_224, sizeof(g_PKCS1_SHA512_224), EVP_sha512_224() },
{ g_PKCS1_SHA512_256, sizeof(g_PKCS1_SHA512_256), EVP_sha512_256() }
+#endif
};
if (!pk)
diff --git a/libfreerdp/freerdp.pc.in b/libfreerdp/freerdp.pc.in
index 7555957..185ec98 100644
--- a/libfreerdp/freerdp.pc.in
+++ b/libfreerdp/freerdp.pc.in
@@ -14,7 +14,7 @@ Description: FreeRDP: A Remote Desktop Protocol Implementation
URL: http://www.freerdp.com/
Version: @FREERDP_VERSION@
Requires:
-Requires.private: winpr@FREERDP_API_VERSION@
+Requires.private: winpr@FREERDP_API_VERSION@ @FREERDP_REQUIRES_PRIVATE@
Libs: -L${libdir} ${libs}
-Libs.private: -ldl -lpthread
+Libs.private: -ldl -lpthread @FREERDP_PC_PRIVATE_LIBS@
Cflags: -I${includedir}
diff --git a/libfreerdp/locale/keyboard_xkbfile.c b/libfreerdp/locale/keyboard_xkbfile.c
index a64cac9..2b80aa4 100644
--- a/libfreerdp/locale/keyboard_xkbfile.c
+++ b/libfreerdp/locale/keyboard_xkbfile.c
@@ -47,265 +47,254 @@ typedef struct
} XKB_KEY_NAME_SCANCODE;
static const XKB_KEY_NAME_SCANCODE XKB_KEY_NAME_SCANCODE_TABLE[] = {
- { "AB00", RDP_SCANCODE_LSHIFT },
- { "AB01", RDP_SCANCODE_KEY_Z }, // evdev 52
- { "AB02", RDP_SCANCODE_KEY_X }, // evdev 53
- { "AB03", RDP_SCANCODE_KEY_C }, // evdev 54
- { "AB04", RDP_SCANCODE_KEY_V }, // evdev 55
- { "AB05", RDP_SCANCODE_KEY_B }, // evdev 56
- { "AB06", RDP_SCANCODE_KEY_N }, // evdev 57
- { "AB07", RDP_SCANCODE_KEY_M }, // evdev 58
- { "AB08", RDP_SCANCODE_OEM_COMMA }, // evdev 59
- { "AB09", RDP_SCANCODE_OEM_PERIOD }, // evdev 60
- { "AB10", RDP_SCANCODE_OEM_2 }, // evdev 61. Not KP, not RDP_SCANCODE_DIVIDE
- { "AB11", RDP_SCANCODE_ABNT_C1 }, // evdev 97. Brazil backslash/underscore.
- { "AC01", RDP_SCANCODE_KEY_A }, // evdev 38
- { "AC02", RDP_SCANCODE_KEY_S }, // evdev 39
- { "AC03", RDP_SCANCODE_KEY_D }, // evdev 40
- { "AC04", RDP_SCANCODE_KEY_F }, // evdev 41
- { "AC05", RDP_SCANCODE_KEY_G }, // evdev 42
- { "AC06", RDP_SCANCODE_KEY_H }, // evdev 43
- { "AC07", RDP_SCANCODE_KEY_J }, // evdev 44
- { "AC08", RDP_SCANCODE_KEY_K }, // evdev 45
- { "AC09", RDP_SCANCODE_KEY_L }, // evdev 46
- { "AC10", RDP_SCANCODE_OEM_1 }, // evdev 47
- { "AC11", RDP_SCANCODE_OEM_7 }, // evdev 48
- { "AC12", RDP_SCANCODE_OEM_5 }, // alias of evdev 51 backslash
- { "AD01", RDP_SCANCODE_KEY_Q }, // evdev 24
- { "AD02", RDP_SCANCODE_KEY_W }, // evdev 25
- { "AD03", RDP_SCANCODE_KEY_E }, // evdev 26
- { "AD04", RDP_SCANCODE_KEY_R }, // evdev 27
- { "AD05", RDP_SCANCODE_KEY_T }, // evdev 28
- { "AD06", RDP_SCANCODE_KEY_Y }, // evdev 29
- { "AD07", RDP_SCANCODE_KEY_U }, // evdev 30
- { "AD08", RDP_SCANCODE_KEY_I }, // evdev 31
- { "AD09", RDP_SCANCODE_KEY_O }, // evdev 32
- { "AD10", RDP_SCANCODE_KEY_P }, // evdev 33
- { "AD11", RDP_SCANCODE_OEM_4 }, // evdev 34
- { "AD12", RDP_SCANCODE_OEM_6 }, // evdev 35
- { "AE00", RDP_SCANCODE_OEM_3 },
- { "AE01", RDP_SCANCODE_KEY_1 }, // evdev 10
- { "AE02", RDP_SCANCODE_KEY_2 }, // evdev 11
- { "AE03", RDP_SCANCODE_KEY_3 }, // evdev 12
- { "AE04", RDP_SCANCODE_KEY_4 }, // evdev 13
- { "AE05", RDP_SCANCODE_KEY_5 }, // evdev 14
- { "AE06", RDP_SCANCODE_KEY_6 }, // evdev 15
- { "AE07", RDP_SCANCODE_KEY_7 }, // evdev 16
- { "AE08", RDP_SCANCODE_KEY_8 }, // evdev 17
- { "AE09", RDP_SCANCODE_KEY_9 }, // evdev 18
- { "AE10", RDP_SCANCODE_KEY_0 }, // evdev 19
- { "AE11", RDP_SCANCODE_OEM_MINUS }, // evdev 20
- { "AE12", RDP_SCANCODE_OEM_PLUS }, // evdev 21
- { "AE13", RDP_SCANCODE_BACKSLASH_JP }, // JP 132 Yen next to backspace
- // { "AGAI", RDP_SCANCODE_ }, // evdev 137
- { "ALGR", RDP_SCANCODE_RMENU }, // alias of evdev 108 RALT
- { "ALT", RDP_SCANCODE_LMENU }, // evdev 204, fake keycode for virtual key
- { "BKSL", RDP_SCANCODE_OEM_5 }, // evdev 51
- { "BKSP", RDP_SCANCODE_BACKSPACE }, // evdev 22
- // { "BRK", RDP_SCANCODE_ }, // evdev 419
- { "CAPS", RDP_SCANCODE_CAPSLOCK }, // evdev 66
- { "COMP", RDP_SCANCODE_APPS }, // evdev 135
- // { "COPY", RDP_SCANCODE_ }, // evdev 141
- // { "CUT", RDP_SCANCODE_ }, // evdev 145
- { "DELE", RDP_SCANCODE_DELETE }, // evdev 119
- { "DOWN", RDP_SCANCODE_DOWN }, // evdev 116
- { "END", RDP_SCANCODE_END }, // evdev 115
- { "ESC", RDP_SCANCODE_ESCAPE }, // evdev 9
- // { "FIND", RDP_SCANCODE_ }, // evdev 144
- { "FK01", RDP_SCANCODE_F1 }, // evdev 67
- { "FK02", RDP_SCANCODE_F2 }, // evdev 68
- { "FK03", RDP_SCANCODE_F3 }, // evdev 69
- { "FK04", RDP_SCANCODE_F4 }, // evdev 70
- { "FK05", RDP_SCANCODE_F5 }, // evdev 71
- { "FK06", RDP_SCANCODE_F6 }, // evdev 72
- { "FK07", RDP_SCANCODE_F7 }, // evdev 73
- { "FK08", RDP_SCANCODE_F8 }, // evdev 74
- { "FK09", RDP_SCANCODE_F9 }, // evdev 75
- { "FK10", RDP_SCANCODE_F10 }, // evdev 76
- { "FK11", RDP_SCANCODE_F11 }, // evdev 95
- { "FK12", RDP_SCANCODE_F12 }, // evdev 96
- { "FK13", RDP_SCANCODE_F13 }, // evdev 191
- { "FK14", RDP_SCANCODE_F14 }, // evdev 192
- { "FK15", RDP_SCANCODE_F15 }, // evdev 193
- { "FK16", RDP_SCANCODE_F16 }, // evdev 194
- { "FK17", RDP_SCANCODE_F17 }, // evdev 195
- { "FK18", RDP_SCANCODE_F18 }, // evdev 196
- { "FK19", RDP_SCANCODE_F19 }, // evdev 197
- { "FK20", RDP_SCANCODE_F20 }, // evdev 198
- { "FK21", RDP_SCANCODE_F21 }, // evdev 199
- { "FK22", RDP_SCANCODE_F22 }, // evdev 200
- { "FK23", RDP_SCANCODE_F23 }, // evdev 201
- { "FK24", RDP_SCANCODE_F24 }, // evdev 202
- // { "FRNT", RDP_SCANCODE_ }, // evdev 140
- { "HANJ", RDP_SCANCODE_HANJA },
- { "HELP", RDP_SCANCODE_HELP }, // evdev 146
- { "HENK", RDP_SCANCODE_CONVERT_JP }, // JP evdev 100 Henkan
- { "HIRA", RDP_SCANCODE_HIRAGANA }, // JP evdev 99 Hiragana
- { "HJCV", RDP_SCANCODE_HANJA }, // KR evdev 131 Hangul->Hanja
- { "HKTG", RDP_SCANCODE_HIRAGANA }, // JP evdev 101 Hiragana/Katakana toggle
- { "HNGL", RDP_SCANCODE_HANGUL }, // KR evdev 130 Hangul/Latin toggle
- { "HOME", RDP_SCANCODE_HOME }, // evdev 110
- { "HYPR", RDP_SCANCODE_LWIN }, // evdev 207, fake keycode for virtual key
- { "HZTG", RDP_SCANCODE_OEM_3 }, // JP alias of evdev 49
- // { "I120", RDP_SCANCODE_ }, // evdev 120 KEY_MACRO
- // { "I126", RDP_SCANCODE_ }, // evdev 126 KEY_KPPLUSMINUS
- // { "I128", RDP_SCANCODE_ }, // evdev 128 KEY_SCALE
- { "I129", RDP_SCANCODE_ABNT_C2 }, // evdev 129 KEY_KPCOMMA Brazil
- // { "I147", RDP_SCANCODE_ }, // evdev 147 KEY_MENU
- // { "I148", RDP_SCANCODE_ }, // evdev 148 KEY_CALC
- // { "I149", RDP_SCANCODE_ }, // evdev 149 KEY_SETUP
- { "I150", RDP_SCANCODE_SLEEP }, // evdev 150 KEY_SLEEP
- // { "I151", RDP_SCANCODE_ }, // evdev 151 KEY_WAKEUP
- // { "I152", RDP_SCANCODE_ }, // evdev 152 KEY_FILE
- // { "I153", RDP_SCANCODE_ }, // evdev 153 KEY_SENDFILE
- // { "I154", RDP_SCANCODE_ }, // evdev 154 KEY_DELETEFILE
- // { "I155", RDP_SCANCODE_ }, // evdev 155 KEY_XFER
- // { "I156", RDP_SCANCODE_ }, // evdev 156 KEY_PROG1 VK_LAUNCH_APP1
- // { "I157", RDP_SCANCODE_ }, // evdev 157 KEY_PROG2 VK_LAUNCH_APP2
- // { "I158", RDP_SCANCODE_ }, // evdev 158 KEY_WWW
- // { "I159", RDP_SCANCODE_ }, // evdev 159 KEY_MSDOS
- // { "I160", RDP_SCANCODE_ }, // evdev 160 KEY_COFFEE
- // { "I161", RDP_SCANCODE_ }, // evdev 161 KEY_DIRECTION
- // { "I162", RDP_SCANCODE_ }, // evdev 162 KEY_CYCLEWINDOWS
- { "I163", RDP_SCANCODE_LAUNCH_MAIL }, // evdev 163 KEY_MAIL
- { "I164", RDP_SCANCODE_BROWSER_FAVORITES }, // evdev 164 KEY_BOOKMARKS
- // { "I165", RDP_SCANCODE_ }, // evdev 165 KEY_COMPUTER
- { "I166", RDP_SCANCODE_BROWSER_BACK }, // evdev 166 KEY_BACK
- { "I167", RDP_SCANCODE_BROWSER_FORWARD }, // evdev 167 KEY_FORWARD
- // { "I168", RDP_SCANCODE_ }, // evdev 168 KEY_CLOSECD
- // { "I169", RDP_SCANCODE_ }, // evdev 169 KEY_EJECTCD
- // { "I170", RDP_SCANCODE_ }, // evdev 170 KEY_EJECTCLOSECD
- { "I171", RDP_SCANCODE_MEDIA_NEXT_TRACK }, // evdev 171 KEY_NEXTSONG
- { "I172", RDP_SCANCODE_MEDIA_PLAY_PAUSE }, // evdev 172 KEY_PLAYPAUSE
- { "I173", RDP_SCANCODE_MEDIA_PREV_TRACK }, // evdev 173 KEY_PREVIOUSSONG
- { "I174", RDP_SCANCODE_MEDIA_STOP }, // evdev 174 KEY_STOPCD
- // { "I175", RDP_SCANCODE_ }, // evdev 175 KEY_RECORD 167
- // { "I176", RDP_SCANCODE_ }, // evdev 176 KEY_REWIND
- // { "I177", RDP_SCANCODE_ }, // evdev 177 KEY_PHONE
- // { "I178", RDP_SCANCODE_ }, // evdev 178 KEY_ISO
- // { "I179", RDP_SCANCODE_ }, // evdev 179 KEY_CONFIG
- { "I180", RDP_SCANCODE_BROWSER_HOME }, // evdev 180 KEY_HOMEPAGE
- { "I181", RDP_SCANCODE_BROWSER_REFRESH }, // evdev 181 KEY_REFRESH
- // { "I182", RDP_SCANCODE_ }, // evdev 182 KEY_EXIT
- // { "I183", RDP_SCANCODE_ }, // evdev 183 KEY_MOVE
- // { "I184", RDP_SCANCODE_ }, // evdev 184 KEY_EDIT
- // { "I185", RDP_SCANCODE_ }, // evdev 185 KEY_SCROLLUP
- // { "I186", RDP_SCANCODE_ }, // evdev 186 KEY_SCROLLDOWN
- // { "I187", RDP_SCANCODE_ }, // evdev 187 KEY_KPLEFTPAREN
- // { "I188", RDP_SCANCODE_ }, // evdev 188 KEY_KPRIGHTPAREN
- // { "I189", RDP_SCANCODE_ }, // evdev 189 KEY_NEW
- // { "I190", RDP_SCANCODE_ }, // evdev 190 KEY_REDO
- // { "I208", RDP_SCANCODE_ }, // evdev 208 KEY_PLAYCD
- // { "I209", RDP_SCANCODE_ }, // evdev 209 KEY_PAUSECD
- // { "I210", RDP_SCANCODE_ }, // evdev 210 KEY_PROG3
- // { "I211", RDP_SCANCODE_ }, // evdev 211 KEY_PROG4
- // { "I212", RDP_SCANCODE_ }, // evdev 212 KEY_DASHBOARD
- // { "I213", RDP_SCANCODE_ }, // evdev 213 KEY_SUSPEND
- // { "I214", RDP_SCANCODE_ }, // evdev 214 KEY_CLOSE
- // { "I215", RDP_SCANCODE_ }, // evdev 215 KEY_PLAY
- // { "I216", RDP_SCANCODE_ }, // evdev 216 KEY_FASTFORWARD
- // { "I217", RDP_SCANCODE_ }, // evdev 217 KEY_BASSBOOST
- // { "I218", RDP_SCANCODE_ }, // evdev 218 KEY_PRINT
- // { "I219", RDP_SCANCODE_ }, // evdev 219 KEY_HP
- // { "I220", RDP_SCANCODE_ }, // evdev 220 KEY_CAMERA
- // { "I221", RDP_SCANCODE_ }, // evdev 221 KEY_SOUND
- // { "I222", RDP_SCANCODE_ }, // evdev 222 KEY_QUESTION
- // { "I223", RDP_SCANCODE_ }, // evdev 223 KEY_EMAIL
- // { "I224", RDP_SCANCODE_ }, // evdev 224 KEY_CHAT
- { "I225", RDP_SCANCODE_BROWSER_SEARCH }, // evdev 225 KEY_SEARCH
- // { "I226", RDP_SCANCODE_ }, // evdev 226 KEY_CONNECT
- // { "I227", RDP_SCANCODE_ }, // evdev 227 KEY_FINANCE
- // { "I228", RDP_SCANCODE_ }, // evdev 228 KEY_SPORT
- // { "I229", RDP_SCANCODE_ }, // evdev 229 KEY_SHOP
- // { "I230", RDP_SCANCODE_ }, // evdev 230 KEY_ALTERASE
- // { "I231", RDP_SCANCODE_ }, // evdev 231 KEY_CANCEL
- // { "I232", RDP_SCANCODE_ }, // evdev 232 KEY_BRIGHTNESSDOWN
- // { "I233", RDP_SCANCODE_ }, // evdev 233 KEY_BRIGHTNESSUP
- // { "I234", RDP_SCANCODE_ }, // evdev 234 KEY_MEDIA
- // { "I235", RDP_SCANCODE_ }, // evdev 235 KEY_SWITCHVIDEOMODE
- // { "I236", RDP_SCANCODE_ }, // evdev 236 KEY_KBDILLUMTOGGLE
- // { "I237", RDP_SCANCODE_ }, // evdev 237 KEY_KBDILLUMDOWN
- // { "I238", RDP_SCANCODE_ }, // evdev 238 KEY_KBDILLUMUP
- // { "I239", RDP_SCANCODE_ }, // evdev 239 KEY_SEND
- // { "I240", RDP_SCANCODE_ }, // evdev 240 KEY_REPLY
- // { "I241", RDP_SCANCODE_ }, // evdev 241 KEY_FORWARDMAIL
- // { "I242", RDP_SCANCODE_ }, // evdev 242 KEY_SAVE
- // { "I243", RDP_SCANCODE_ }, // evdev 243 KEY_DOCUMENTS
- // { "I244", RDP_SCANCODE_ }, // evdev 244 KEY_BATTERY
- // { "I245", RDP_SCANCODE_ }, // evdev 245 KEY_BLUETOOTH
- // { "I246", RDP_SCANCODE_ }, // evdev 246 KEY_WLAN
- // { "I247", RDP_SCANCODE_ }, // evdev 247 KEY_UWB
- // { "I248", RDP_SCANCODE_ }, // evdev 248 KEY_UNKNOWN
- // { "I249", RDP_SCANCODE_ }, // evdev 249 KEY_VIDEO_NEXT
- // { "I250", RDP_SCANCODE_ }, // evdev 250 KEY_VIDEO_PREV
- // { "I251", RDP_SCANCODE_ }, // evdev 251 KEY_BRIGHTNESS_CYCLE
- // { "I252", RDP_SCANCODE_ }, // evdev 252 KEY_BRIGHTNESS_ZERO
- // { "I253", RDP_SCANCODE_ }, // evdev 253 KEY_DISPLAY_OFF
- { "INS", RDP_SCANCODE_INSERT }, // evdev 118
- // { "JPCM", RDP_SCANCODE_ }, // evdev 103 KPJPComma
- // { "KATA", RDP_SCANCODE_ }, // evdev 98 Katakana VK_DBE_KATAKANA
- { "KP0", RDP_SCANCODE_NUMPAD0 }, // evdev 90
- { "KP1", RDP_SCANCODE_NUMPAD1 }, // evdev 87
- { "KP2", RDP_SCANCODE_NUMPAD2 }, // evdev 88
- { "KP3", RDP_SCANCODE_NUMPAD3 }, // evdev 89
- { "KP4", RDP_SCANCODE_NUMPAD4 }, // evdev 83
- { "KP5", RDP_SCANCODE_NUMPAD5 }, // evdev 84
- { "KP6", RDP_SCANCODE_NUMPAD6 }, // evdev 85
- { "KP7", RDP_SCANCODE_NUMPAD7 }, // evdev 79
- { "KP8", RDP_SCANCODE_NUMPAD8 }, // evdev 80
- { "KP9", RDP_SCANCODE_NUMPAD9 }, // evdev 81
- { "KPAD", RDP_SCANCODE_ADD }, // evdev 86
- { "KPDL", RDP_SCANCODE_DECIMAL }, // evdev 91
- { "KPDV", RDP_SCANCODE_DIVIDE }, // evdev 106
- { "KPEN", RDP_SCANCODE_RETURN_KP }, // evdev 104 KP!
- // { "KPEQ", RDP_SCANCODE_ }, // evdev 125
- { "KPMU", RDP_SCANCODE_MULTIPLY }, // evdev 63
- { "KPPT", RDP_SCANCODE_ABNT_C2 }, // BR alias of evdev 129
- { "KPSU", RDP_SCANCODE_SUBTRACT }, // evdev 82
- { "LALT", RDP_SCANCODE_LMENU }, // evdev 64
- { "LCTL", RDP_SCANCODE_LCONTROL }, // evdev 37
- { "LEFT", RDP_SCANCODE_LEFT }, // evdev 113
- { "LFSH", RDP_SCANCODE_LSHIFT }, // evdev 50
- { "LMTA", RDP_SCANCODE_LWIN }, // alias of evdev 133 LWIN
- // { "LNFD", RDP_SCANCODE_ }, // evdev 109 KEY_LINEFEED
- { "LSGT", RDP_SCANCODE_OEM_102 }, // evdev 94
- { "LVL3", RDP_SCANCODE_RMENU }, // evdev 92, fake keycode for virtual key
- { "LWIN", RDP_SCANCODE_LWIN }, // evdev 133
- { "MDSW", RDP_SCANCODE_RMENU }, // evdev 203, fake keycode for virtual key
- { "MENU", RDP_SCANCODE_APPS }, // alias of evdev 135 COMP
- { "META", RDP_SCANCODE_LMENU }, // evdev 205, fake keycode for virtual key
- { "MUHE", RDP_SCANCODE_NONCONVERT_JP }, // JP evdev 102 Muhenkan
- { "MUTE", RDP_SCANCODE_VOLUME_MUTE }, // evdev 121
- { "NFER", RDP_SCANCODE_NONCONVERT_JP }, // JP alias of evdev 102 Muhenkan
- { "NMLK", RDP_SCANCODE_NUMLOCK }, // evdev 77
- // { "OPEN", RDP_SCANCODE_ }, // evdev 142
- // { "PAST", RDP_SCANCODE_ }, // evdev 143
- { "PAUS", RDP_SCANCODE_PAUSE }, // evdev 127
- { "PGDN", RDP_SCANCODE_NEXT }, // evdev 117
- { "PGUP", RDP_SCANCODE_PRIOR }, // evdev 112
- // { "POWR", RDP_SCANCODE_ }, // evdev 124
- // { "PROP", RDP_SCANCODE_ }, // evdev 138
- { "PRSC", RDP_SCANCODE_PRINTSCREEN }, // evdev 107
- { "RALT", RDP_SCANCODE_RMENU }, // evdev 108 RALT
- { "RCTL", RDP_SCANCODE_RCONTROL }, // evdev 105
- { "RGHT", RDP_SCANCODE_RIGHT }, // evdev 114
- { "RMTA", RDP_SCANCODE_RWIN }, // alias of evdev 134 RWIN
- // { "RO", RDP_SCANCODE_ }, // JP evdev 97 Romaji
- { "RTRN", RDP_SCANCODE_RETURN }, // not KP, evdev 36
- { "RTSH", RDP_SCANCODE_RSHIFT }, // evdev 62
- { "RWIN", RDP_SCANCODE_RWIN }, // evdev 134
- { "SCLK", RDP_SCANCODE_SCROLLLOCK }, // evdev 78
- { "SPCE", RDP_SCANCODE_SPACE }, // evdev 65
- { "STOP", RDP_SCANCODE_BROWSER_STOP }, // evdev 136
- { "SUPR", RDP_SCANCODE_LWIN }, // evdev 206, fake keycode for virtual key
- { "SYRQ", RDP_SCANCODE_SYSREQ }, // evdev 107
- { "TAB", RDP_SCANCODE_TAB }, // evdev 23
- { "TLDE", RDP_SCANCODE_OEM_3 }, // evdev 49
- // { "UNDO", RDP_SCANCODE_ }, // evdev 139
- { "UP", RDP_SCANCODE_UP }, // evdev 111
- { "VOL-", RDP_SCANCODE_VOLUME_DOWN }, // evdev 122
- { "VOL+", RDP_SCANCODE_VOLUME_UP }, // evdev 123
- { "XFER", RDP_SCANCODE_CONVERT_JP }, // JP alias of evdev 100 Henkan
+ { "", RDP_SCANCODE_UNKNOWN }, /* 008: [(null)] */
+ { "ESC", RDP_SCANCODE_ESCAPE }, /* 009: ESC [Escape] */
+ { "AE01", RDP_SCANCODE_KEY_1 }, /* 010: AE01 [1] */
+ { "AE02", RDP_SCANCODE_KEY_2 }, /* 011: AE02 [2] */
+ { "AE03", RDP_SCANCODE_KEY_3 }, /* 012: AE03 [3] */
+ { "AE04", RDP_SCANCODE_KEY_4 }, /* 013: AE04 [4] */
+ { "AE05", RDP_SCANCODE_KEY_5 }, /* 014: AE05 [5] */
+ { "AE06", RDP_SCANCODE_KEY_6 }, /* 015: AE06 [6] */
+ { "AE07", RDP_SCANCODE_KEY_7 }, /* 016: AE07 [7] */
+ { "AE08", RDP_SCANCODE_KEY_8 }, /* 017: AE08 [8] */
+ { "AE09", RDP_SCANCODE_KEY_9 }, /* 018: AE09 [9] */
+ { "AE10", RDP_SCANCODE_KEY_0 }, /* 019: AE10 [0] */
+ { "AE11", RDP_SCANCODE_OEM_MINUS }, /* 020: AE11 [minus] */
+ { "AE12", RDP_SCANCODE_OEM_PLUS }, /* 021: AE12 [equal] */
+ { "BKSP", RDP_SCANCODE_BACKSPACE }, /* 022: BKSP [BackSpace] */
+ { "TAB", RDP_SCANCODE_TAB }, /* 023: TAB [Tab] */
+ { "AD01", RDP_SCANCODE_KEY_Q }, /* 024: AD01 [q] */
+ { "AD02", RDP_SCANCODE_KEY_W }, /* 025: AD02 [w] */
+ { "AD03", RDP_SCANCODE_KEY_E }, /* 026: AD03 [e] */
+ { "AD04", RDP_SCANCODE_KEY_R }, /* 027: AD04 [r] */
+ { "AD05", RDP_SCANCODE_KEY_T }, /* 028: AD05 [t] */
+ { "AD06", RDP_SCANCODE_KEY_Y }, /* 029: AD06 [y] */
+ { "AD07", RDP_SCANCODE_KEY_U }, /* 030: AD07 [u] */
+ { "AD08", RDP_SCANCODE_KEY_I }, /* 031: AD08 [i] */
+ { "AD09", RDP_SCANCODE_KEY_O }, /* 032: AD09 [o] */
+ { "AD10", RDP_SCANCODE_KEY_P }, /* 033: AD10 [p] */
+ { "AD11", RDP_SCANCODE_OEM_4 }, /* 034: AD11 [bracketleft] */
+ { "AD12", RDP_SCANCODE_OEM_6 }, /* 035: AD12 [bracketright] */
+ { "RTRN", RDP_SCANCODE_RETURN }, /* 036: RTRN [Return] */
+ { "LCTL", RDP_SCANCODE_LCONTROL }, /* 037: LCTL [Control_L] */
+ { "AC01", RDP_SCANCODE_KEY_A }, /* 038: AC01 [a] */
+ { "AC02", RDP_SCANCODE_KEY_S }, /* 039: AC02 [s] */
+ { "AC03", RDP_SCANCODE_KEY_D }, /* 040: AC03 [d] */
+ { "AC04", RDP_SCANCODE_KEY_F }, /* 041: AC04 [f] */
+ { "AC05", RDP_SCANCODE_KEY_G }, /* 042: AC05 [g] */
+ { "AC06", RDP_SCANCODE_KEY_H }, /* 043: AC06 [h] */
+ { "AC07", RDP_SCANCODE_KEY_J }, /* 044: AC07 [j] */
+ { "AC08", RDP_SCANCODE_KEY_K }, /* 045: AC08 [k] */
+ { "AC09", RDP_SCANCODE_KEY_L }, /* 046: AC09 [l] */
+ { "AC10", RDP_SCANCODE_OEM_1 }, /* 047: AC10 [semicolon] */
+ { "AC11", RDP_SCANCODE_OEM_7 }, /* 048: AC11 [dead_acute] */
+ { "TLDE", RDP_SCANCODE_OEM_3 }, /* 049: TLDE [dead_grave] */
+ { "LFSH", RDP_SCANCODE_LSHIFT }, /* 050: LFSH [Shift_L] */
+ { "BKSL", RDP_SCANCODE_OEM_5 }, /* 051: BKSL [backslash] */
+ { "AB01", RDP_SCANCODE_KEY_Z }, /* 052: AB01 [z] */
+ { "AB02", RDP_SCANCODE_KEY_X }, /* 053: AB02 [x] */
+ { "AB03", RDP_SCANCODE_KEY_C }, /* 054: AB03 [c] */
+ { "AB04", RDP_SCANCODE_KEY_V }, /* 055: AB04 [v] */
+ { "AB05", RDP_SCANCODE_KEY_B }, /* 056: AB05 [b] */
+ { "AB06", RDP_SCANCODE_KEY_N }, /* 057: AB06 [n] */
+ { "AB07", RDP_SCANCODE_KEY_M }, /* 058: AB07 [m] */
+ { "AB08", RDP_SCANCODE_OEM_COMMA }, /* 059: AB08 [comma] */
+ { "AB09", RDP_SCANCODE_OEM_PERIOD }, /* 060: AB09 [period] */
+ { "AB10", RDP_SCANCODE_OEM_2 }, /* 061: AB10 [slash] */
+ { "RTSH", RDP_SCANCODE_RSHIFT }, /* 062: RTSH [Shift_R] */
+ { "KPMU", RDP_SCANCODE_MULTIPLY }, /* 063: KPMU [KP_Multiply] */
+ { "LALT", RDP_SCANCODE_LMENU }, /* 064: LALT [Alt_L] */
+ { "SPCE", RDP_SCANCODE_SPACE }, /* 065: SPCE [space] */
+ { "CAPS", RDP_SCANCODE_CAPSLOCK }, /* 066: CAPS [Caps_Lock] */
+ { "FK01", RDP_SCANCODE_F1 }, /* 067: FK01 [F1] */
+ { "FK02", RDP_SCANCODE_F2 }, /* 068: FK02 [F2] */
+ { "FK03", RDP_SCANCODE_F3 }, /* 069: FK03 [F3] */
+ { "FK04", RDP_SCANCODE_F4 }, /* 070: FK04 [F4] */
+ { "FK05", RDP_SCANCODE_F5 }, /* 071: FK05 [F5] */
+ { "FK06", RDP_SCANCODE_F6 }, /* 072: FK06 [F6] */
+ { "FK07", RDP_SCANCODE_F7 }, /* 073: FK07 [F7] */
+ { "FK08", RDP_SCANCODE_F8 }, /* 074: FK08 [F8] */
+ { "FK09", RDP_SCANCODE_F9 }, /* 075: FK09 [F9] */
+ { "FK10", RDP_SCANCODE_F10 }, /* 076: FK10 [F10] */
+ { "NMLK", RDP_SCANCODE_NUMLOCK }, /* 077: NMLK [Num_Lock] */
+ { "SCLK", RDP_SCANCODE_SCROLLLOCK }, /* 078: SCLK [Multi_key] */
+ { "KP7", RDP_SCANCODE_NUMPAD7 }, /* 079: KP7 [KP_Home] */
+ { "KP8", RDP_SCANCODE_NUMPAD8 }, /* 080: KP8 [KP_Up] */
+ { "KP9", RDP_SCANCODE_NUMPAD9 }, /* 081: KP9 [KP_Prior] */
+ { "KPSU", RDP_SCANCODE_SUBTRACT }, /* 082: KPSU [KP_Subtract] */
+ { "KP4", RDP_SCANCODE_NUMPAD4 }, /* 083: KP4 [KP_Left] */
+ { "KP5", RDP_SCANCODE_NUMPAD5 }, /* 084: KP5 [KP_Begin] */
+ { "KP6", RDP_SCANCODE_NUMPAD6 }, /* 085: KP6 [KP_Right] */
+ { "KPAD", RDP_SCANCODE_ADD }, /* 086: KPAD [KP_Add] */
+ { "KP1", RDP_SCANCODE_NUMPAD1 }, /* 087: KP1 [KP_End] */
+ { "KP2", RDP_SCANCODE_NUMPAD2 }, /* 088: KP2 [KP_Down] */
+ { "KP3", RDP_SCANCODE_NUMPAD3 }, /* 089: KP3 [KP_Next] */
+ { "KP0", RDP_SCANCODE_NUMPAD0 }, /* 090: KP0 [KP_Insert] */
+ { "KPDL", RDP_SCANCODE_DECIMAL }, /* 091: KPDL [KP_Delete] */
+ { "LVL3", RDP_SCANCODE_RMENU }, /* 092: LVL3 [ISO_Level3_Shift] */
+ { "", RDP_SCANCODE_UNKNOWN }, /* 093: [(null)] */
+ { "LSGT", RDP_SCANCODE_OEM_102 }, /* 094: LSGT [backslash] */
+ { "FK11", RDP_SCANCODE_F11 }, /* 095: FK11 [F11] */
+ { "FK12", RDP_SCANCODE_F12 }, /* 096: FK12 [F12] */
+ { "AB11", RDP_SCANCODE_ABNT_C1 }, /* 097: AB11 [(null)] */
+ { "KATA", RDP_SCANCODE_KANA_HANGUL }, /* 098: KATA [Katakana] */
+ { "HIRA", RDP_SCANCODE_HIRAGANA }, /* 099: HIRA [Hiragana] */
+ { "HENK", RDP_SCANCODE_CONVERT_JP }, /* 100: HENK [Henkan_Mode] */
+ { "HKTG", RDP_SCANCODE_HIRAGANA }, /* 101: HKTG [Hiragana_Katakana] */
+ { "MUHE", RDP_SCANCODE_NONCONVERT_JP }, /* 102: MUHE [Muhenkan] */
+ { "JPCM", RDP_SCANCODE_UNKNOWN }, /* 103: JPCM [(null)] */
+ { "KPEN", RDP_SCANCODE_RETURN_KP }, /* 104: KPEN [KP_Enter] */
+ { "RCTL", RDP_SCANCODE_RCONTROL }, /* 105: RCTL [Control_R] */
+ { "KPDV", RDP_SCANCODE_DIVIDE }, /* 106: KPDV [KP_Divide] */
+ { "PRSC", RDP_SCANCODE_PRINTSCREEN }, /* 107: PRSC [Print] */
+ { "RALT", RDP_SCANCODE_RMENU }, /* 108: RALT [ISO_Level3_Shift] */
+ { "LNFD", RDP_SCANCODE_UNKNOWN }, /* 109: LNFD [Linefeed] */
+ { "HOME", RDP_SCANCODE_HOME }, /* 110: HOME [Home] */
+ { "UP", RDP_SCANCODE_UP }, /* 111: UP [Up] */
+ { "PGUP", RDP_SCANCODE_PRIOR }, /* 112: PGUP [Prior] */
+ { "LEFT", RDP_SCANCODE_LEFT }, /* 113: LEFT [Left] */
+ { "RGHT", RDP_SCANCODE_RIGHT }, /* 114: RGHT [Right] */
+ { "END", RDP_SCANCODE_END }, /* 115: END [End] */
+ { "DOWN", RDP_SCANCODE_DOWN }, /* 116: DOWN [Down] */
+ { "PGDN", RDP_SCANCODE_NEXT }, /* 117: PGDN [Next] */
+ { "INS", RDP_SCANCODE_INSERT }, /* 118: INS [Insert] */
+ { "DELE", RDP_SCANCODE_DELETE }, /* 119: DELE [Delete] */
+ { "I120", RDP_SCANCODE_UNKNOWN }, /* 120: I120 [(null)] */
+ { "MUTE", RDP_SCANCODE_VOLUME_MUTE }, /* 121: MUTE [XF86AudioMute] */
+ { "VOL-", RDP_SCANCODE_VOLUME_DOWN }, /* 122: VOL- [XF86AudioLowerVolume] */
+ { "VOL+", RDP_SCANCODE_VOLUME_UP }, /* 123: VOL+ [XF86AudioRaiseVolume] */
+ { "POWR", RDP_SCANCODE_UNKNOWN }, /* 124: POWR [XF86PowerOff] */
+ { "KPEQ", RDP_SCANCODE_UNKNOWN }, /* 125: KPEQ [KP_Equal] */
+ { "I126", RDP_SCANCODE_UNKNOWN }, /* 126: I126 [plusminus] */
+ { "PAUS", RDP_SCANCODE_PAUSE }, /* 127: PAUS [Pause] */
+ { "I128", RDP_SCANCODE_LAUNCH_MEDIA_SELECT }, /* 128: I128 [XF86LaunchA] */
+ { "I129", RDP_SCANCODE_ABNT_C2 }, /* 129: I129 [KP_Decimal] */
+ { "HNGL", RDP_SCANCODE_HANGUL }, /* 130: HNGL [Hangul] */
+ { "HJCV", RDP_SCANCODE_HANJA }, /* 131: HJCV [Hangul_Hanja] */
+ { "AE13", RDP_SCANCODE_BACKSLASH_JP }, /* 132: AE13 [(null)] */
+ { "LWIN", RDP_SCANCODE_LWIN }, /* 133: LWIN [Super_L] */
+ { "RWIN", RDP_SCANCODE_RWIN }, /* 134: RWIN [Super_R] */
+ { "COMP", RDP_SCANCODE_APPS }, /* 135: COMP [Menu] */
+ { "STOP", RDP_SCANCODE_BROWSER_STOP }, /* 136: STOP [Cancel] */
+ { "AGAI", RDP_SCANCODE_UNKNOWN }, /* 137: AGAI [Redo] */
+ { "PROP", RDP_SCANCODE_UNKNOWN }, /* 138: PROP [SunProps] */
+ { "UNDO", RDP_SCANCODE_UNKNOWN }, /* 139: UNDO [Undo] */
+ { "FRNT", RDP_SCANCODE_UNKNOWN }, /* 140: FRNT [SunFront] */
+ { "COPY", RDP_SCANCODE_UNKNOWN }, /* 141: COPY [XF86Copy] */
+ { "OPEN", RDP_SCANCODE_UNKNOWN }, /* 142: OPEN [XF86Open] */
+ { "PAST", RDP_SCANCODE_UNKNOWN }, /* 143: PAST [XF86Paste] */
+ { "FIND", RDP_SCANCODE_UNKNOWN }, /* 144: FIND [Find] */
+ { "CUT", RDP_SCANCODE_UNKNOWN }, /* 145: CUT [XF86Cut] */
+ { "HELP", RDP_SCANCODE_HELP }, /* 146: HELP [Help] */
+ { "I147", RDP_SCANCODE_UNKNOWN }, /* 147: I147 [XF86MenuKB] */
+ { "I148", RDP_SCANCODE_UNKNOWN }, /* 148: I148 [XF86Calculator] */
+ { "I149", RDP_SCANCODE_UNKNOWN }, /* 149: I149 [(null)] */
+ { "I150", RDP_SCANCODE_SLEEP }, /* 150: I150 [XF86Sleep] */
+ { "I151", RDP_SCANCODE_UNKNOWN }, /* 151: I151 [XF86WakeUp] */
+ { "I152", RDP_SCANCODE_UNKNOWN }, /* 152: I152 [XF86Explorer] */
+ { "I153", RDP_SCANCODE_UNKNOWN }, /* 153: I153 [XF86Send] */
+ { "I154", RDP_SCANCODE_UNKNOWN }, /* 154: I154 [(null)] */
+ { "I155", RDP_SCANCODE_UNKNOWN }, /* 155: I155 [XF86Xfer] */
+ { "I156", RDP_SCANCODE_LAUNCH_APP1 }, /* 156: I156 [XF86Launch1] */
+ { "I157", RDP_SCANCODE_LAUNCH_APP2 }, /* 157: I157 [XF86Launch2] */
+ { "I158", RDP_SCANCODE_BROWSER_HOME }, /* 158: I158 [XF86WWW] */
+ { "I159", RDP_SCANCODE_UNKNOWN }, /* 159: I159 [XF86DOS] */
+ { "I160", RDP_SCANCODE_UNKNOWN }, /* 160: I160 [XF86ScreenSaver] */
+ { "I161", RDP_SCANCODE_UNKNOWN }, /* 161: I161 [XF86RotateWindows] */
+ { "I162", RDP_SCANCODE_UNKNOWN }, /* 162: I162 [XF86TaskPane] */
+ { "I163", RDP_SCANCODE_LAUNCH_MAIL }, /* 163: I163 [XF86Mail] */
+ { "I164", RDP_SCANCODE_BROWSER_FAVORITES }, /* 164: I164 [XF86Favorites] */
+ { "I165", RDP_SCANCODE_UNKNOWN }, /* 165: I165 [XF86MyComputer] */
+ { "I166", RDP_SCANCODE_BROWSER_BACK }, /* 166: I166 [XF86Back] */
+ { "I167", RDP_SCANCODE_BROWSER_FORWARD }, /* 167: I167 [XF86Forward] */
+ { "I168", RDP_SCANCODE_UNKNOWN }, /* 168: I168 [(null)] */
+ { "I169", RDP_SCANCODE_UNKNOWN }, /* 169: I169 [XF86Eject] */
+ { "I170", RDP_SCANCODE_UNKNOWN }, /* 170: I170 [XF86Eject] */
+ { "I171", RDP_SCANCODE_MEDIA_NEXT_TRACK }, /* 171: I171 [XF86AudioNext] */
+ { "I172", RDP_SCANCODE_MEDIA_PLAY_PAUSE }, /* 172: I172 [XF86AudioPlay] */
+ { "I173", RDP_SCANCODE_MEDIA_PREV_TRACK }, /* 173: I173 [XF86AudioPrev] */
+ { "I174", RDP_SCANCODE_MEDIA_STOP }, /* 174: I174 [XF86AudioStop] */
+ { "I175", RDP_SCANCODE_UNKNOWN }, /* 175: I175 [XF86AudioRecord] */
+ { "I176", RDP_SCANCODE_UNKNOWN }, /* 176: I176 [XF86AudioRewind] */
+ { "I177", RDP_SCANCODE_UNKNOWN }, /* 177: I177 [XF86Phone] */
+ { "I178", RDP_SCANCODE_UNKNOWN }, /* 178: I178 [(null)] */
+ { "I179", RDP_SCANCODE_UNKNOWN }, /* 179: I179 [XF86Tools] */
+ { "I180", RDP_SCANCODE_BROWSER_HOME }, /* 180: I180 [XF86HomePage] */
+ { "I181", RDP_SCANCODE_BROWSER_REFRESH }, /* 181: I181 [XF86Reload] */
+ { "I182", RDP_SCANCODE_UNKNOWN }, /* 182: I182 [XF86Close] */
+ { "I183", RDP_SCANCODE_UNKNOWN }, /* 183: I183 [(null)] */
+ { "I184", RDP_SCANCODE_UNKNOWN }, /* 184: I184 [(null)] */
+ { "I185", RDP_SCANCODE_UNKNOWN }, /* 185: I185 [XF86ScrollUp] */
+ { "I186", RDP_SCANCODE_UNKNOWN }, /* 186: I186 [XF86ScrollDown] */
+ { "I187", RDP_SCANCODE_UNKNOWN }, /* 187: I187 [parenleft] */
+ { "I188", RDP_SCANCODE_UNKNOWN }, /* 188: I188 [parenright] */
+ { "I189", RDP_SCANCODE_UNKNOWN }, /* 189: I189 [XF86New] */
+ { "I190", RDP_SCANCODE_UNKNOWN }, /* 190: I190 [Redo] */
+ { "FK13", RDP_SCANCODE_F13 }, /* 191: FK13 [XF86Tools] */
+ { "FK14", RDP_SCANCODE_F14 }, /* 192: FK14 [XF86Launch5] */
+ { "FK15", RDP_SCANCODE_F15 }, /* 193: FK15 [XF86Launch6] */
+ { "FK16", RDP_SCANCODE_F16 }, /* 194: FK16 [XF86Launch7] */
+ { "FK17", RDP_SCANCODE_F17 }, /* 195: FK17 [XF86Launch8] */
+ { "FK18", RDP_SCANCODE_F18 }, /* 196: FK18 [XF86Launch9] */
+ { "FK19", RDP_SCANCODE_F19 }, /* 197: FK19 [(null)] */
+ { "FK20", RDP_SCANCODE_F20 }, /* 198: FK20 [XF86AudioMicMute] */
+ { "FK21", RDP_SCANCODE_F21 }, /* 199: FK21 [XF86TouchpadToggle] */
+ { "FK22", RDP_SCANCODE_F22 }, /* 200: FK22 [XF86TouchpadOn] */
+ { "FK23", RDP_SCANCODE_F23 }, /* 201: FK23 [XF86TouchpadOff] */
+ { "FK24", RDP_SCANCODE_F24 }, /* 202: FK24 [(null)] */
+ { "LVL5", RDP_SCANCODE_UNKNOWN }, /* 203: LVL5 [ISO_Level5_Shift] */
+ { "ALT", RDP_SCANCODE_LMENU }, /* 204: ALT [(null)] */
+ { "META", RDP_SCANCODE_LMENU }, /* 205: META [(null)] */
+ { "SUPR", RDP_SCANCODE_LWIN }, /* 206: SUPR [(null)] */
+ { "HYPR", RDP_SCANCODE_LWIN }, /* 207: HYPR [(null)] */
+ { "I208", RDP_SCANCODE_MEDIA_PLAY_PAUSE }, /* 208: I208 [XF86AudioPlay] */
+ { "I209", RDP_SCANCODE_MEDIA_PLAY_PAUSE }, /* 209: I209 [XF86AudioPause] */
+ { "I210", RDP_SCANCODE_UNKNOWN }, /* 210: I210 [XF86Launch3] */
+ { "I211", RDP_SCANCODE_UNKNOWN }, /* 211: I211 [XF86Launch4] */
+ { "I212", RDP_SCANCODE_UNKNOWN }, /* 212: I212 [XF86LaunchB] */
+ { "I213", RDP_SCANCODE_UNKNOWN }, /* 213: I213 [XF86Suspend] */
+ { "I214", RDP_SCANCODE_UNKNOWN }, /* 214: I214 [XF86Close] */
+ { "I215", RDP_SCANCODE_MEDIA_PLAY_PAUSE }, /* 215: I215 [XF86AudioPlay] */
+ { "I216", RDP_SCANCODE_MEDIA_NEXT_TRACK }, /* 216: I216 [XF86AudioForward] */
+ { "I217", RDP_SCANCODE_UNKNOWN }, /* 217: I217 [(null)] */
+ { "I218", RDP_SCANCODE_UNKNOWN }, /* 218: I218 [Print] */
+ { "I219", RDP_SCANCODE_UNKNOWN }, /* 219: I219 [(null)] */
+ { "I220", RDP_SCANCODE_UNKNOWN }, /* 220: I220 [XF86WebCam] */
+ { "I221", RDP_SCANCODE_UNKNOWN }, /* 221: I221 [XF86AudioPreset] */
+ { "I222", RDP_SCANCODE_UNKNOWN }, /* 222: I222 [(null)] */
+ { "I223", RDP_SCANCODE_LAUNCH_MAIL }, /* 223: I223 [XF86Mail] */
+ { "I224", RDP_SCANCODE_UNKNOWN }, /* 224: I224 [XF86Messenger] */
+ { "I225", RDP_SCANCODE_BROWSER_SEARCH }, /* 225: I225 [XF86Search] */
+ { "I226", RDP_SCANCODE_UNKNOWN }, /* 226: I226 [XF86Go] */
+ { "I227", RDP_SCANCODE_UNKNOWN }, /* 227: I227 [XF86Finance] */
+ { "I228", RDP_SCANCODE_UNKNOWN }, /* 228: I228 [XF86Game] */
+ { "I229", RDP_SCANCODE_UNKNOWN }, /* 229: I229 [XF86Shop] */
+ { "I230", RDP_SCANCODE_UNKNOWN }, /* 230: I230 [(null)] */
+ { "I231", RDP_SCANCODE_UNKNOWN }, /* 231: I231 [Cancel] */
+ { "I232", RDP_SCANCODE_UNKNOWN }, /* 232: I232 [XF86MonBrightnessDown] */
+ { "I233", RDP_SCANCODE_UNKNOWN }, /* 233: I233 [XF86MonBrightnessUp] */
+ { "I234", RDP_SCANCODE_LAUNCH_MEDIA_SELECT }, /* 234: I234 [XF86AudioMedia] */
+ { "I235", RDP_SCANCODE_UNKNOWN }, /* 235: I235 [XF86Display] */
+ { "I236", RDP_SCANCODE_UNKNOWN }, /* 236: I236 [XF86KbdLightOnOff] */
+ { "I237", RDP_SCANCODE_UNKNOWN }, /* 237: I237 [XF86KbdBrightnessDown] */
+ { "I238", RDP_SCANCODE_UNKNOWN }, /* 238: I238 [XF86KbdBrightnessUp] */
+ { "I239", RDP_SCANCODE_UNKNOWN }, /* 239: I239 [XF86Send] */
+ { "I240", RDP_SCANCODE_UNKNOWN }, /* 240: I240 [XF86Reply] */
+ { "I241", RDP_SCANCODE_UNKNOWN }, /* 241: I241 [XF86MailForward] */
+ { "I242", RDP_SCANCODE_UNKNOWN }, /* 242: I242 [XF86Save] */
+ { "I243", RDP_SCANCODE_UNKNOWN }, /* 243: I243 [XF86Documents] */
+ { "I244", RDP_SCANCODE_UNKNOWN }, /* 244: I244 [XF86Battery] */
+ { "I245", RDP_SCANCODE_UNKNOWN }, /* 245: I245 [XF86Bluetooth] */
+ { "I246", RDP_SCANCODE_UNKNOWN }, /* 246: I246 [XF86WLAN] */
+ { "I247", RDP_SCANCODE_UNKNOWN }, /* 247: I247 [XF86UWB] */
+ { "I248", RDP_SCANCODE_UNKNOWN }, /* 248: I248 [(null)] */
+ { "I249", RDP_SCANCODE_UNKNOWN }, /* 249: I249 [XF86Next_VMode] */
+ { "I250", RDP_SCANCODE_UNKNOWN }, /* 250: I250 [XF86Prev_VMode] */
+ { "I251", RDP_SCANCODE_UNKNOWN }, /* 251: I251 [XF86MonBrightnessCycle] */
+ { "I252", RDP_SCANCODE_UNKNOWN }, /* 252: I252 [XF86BrightnessAuto] */
+ { "I253", RDP_SCANCODE_UNKNOWN }, /* 253: I253 [XF86DisplayOff] */
+ { "I254", RDP_SCANCODE_UNKNOWN }, /* 254: I254 [XF86WWAN] */
+ { "I255", RDP_SCANCODE_UNKNOWN } /* 255: I255 [XF86RFKill] */
};
static int detect_keyboard_layout_from_xkbfile(void* display, DWORD* keyboardLayoutId);
@@ -428,6 +417,46 @@ int detect_keyboard_layout_from_xkbfile(void* display, DWORD* keyboardLayoutId)
return 0;
}
+static int xkb_cmp(const void* pva, const void* pvb)
+{
+ const XKB_KEY_NAME_SCANCODE* a = pva;
+ const XKB_KEY_NAME_SCANCODE* b = pvb;
+ if (!a)
+ return 1;
+ if (!b)
+ return -1;
+ if (!a && !b)
+ return 0;
+ return strcmp(a->xkb_keyname, b->xkb_keyname);
+}
+
+static BOOL try_add(size_t offset, const char* xkb_keyname, DWORD* x11_keycode_to_rdp_scancode,
+
+ size_t count)
+{
+ static BOOL initialized = FALSE;
+ static XKB_KEY_NAME_SCANCODE copy[ARRAYSIZE(XKB_KEY_NAME_SCANCODE_TABLE)] = { 0 };
+ if (!initialized)
+ {
+ memcpy(copy, XKB_KEY_NAME_SCANCODE_TABLE, sizeof(copy));
+ qsort(copy, ARRAYSIZE(copy), sizeof(XKB_KEY_NAME_SCANCODE), xkb_cmp);
+ initialized = TRUE;
+ }
+
+ XKB_KEY_NAME_SCANCODE key = { 0 };
+ key.xkb_keyname = xkb_keyname;
+ XKB_KEY_NAME_SCANCODE* found =
+ bsearch(&key, copy, ARRAYSIZE(copy), sizeof(XKB_KEY_NAME_SCANCODE), xkb_cmp);
+ if (found)
+ {
+ DEBUG_KBD("%4s: keycode: 0x%02" PRIuz " -> rdp scancode: 0x%08" PRIx32 "", xkb_keyname,
+ offset, found->rdp_scancode);
+ x11_keycode_to_rdp_scancode[offset] = found->rdp_scancode;
+ return TRUE;
+ }
+ return FALSE;
+}
+
int freerdp_keyboard_load_map_from_xkbfile(void* display, DWORD* x11_keycode_to_rdp_scancode,
size_t count)
{
@@ -463,22 +492,7 @@ int freerdp_keyboard_load_map_from_xkbfile(void* display, DWORD* x11_keycode_to_
if (strnlen(xkb_keyname, ARRAYSIZE(xkb_keyname)) < 1)
continue;
- for (size_t j = 0; j < ARRAYSIZE(XKB_KEY_NAME_SCANCODE_TABLE); j++)
- {
- if (!strcmp(xkb_keyname, XKB_KEY_NAME_SCANCODE_TABLE[j].xkb_keyname))
- {
- DEBUG_KBD("%4s: keycode: 0x%02X -> rdp scancode: 0x%08" PRIX32 "", xkb_keyname,
- i, XKB_KEY_NAME_SCANCODE_TABLE[j].rdp_scancode);
-
- if (found)
- {
- DEBUG_KBD("Internal error! duplicate key %s!", xkb_keyname);
- }
-
- x11_keycode_to_rdp_scancode[i] = XKB_KEY_NAME_SCANCODE_TABLE[j].rdp_scancode;
- found = TRUE;
- }
- }
+ found = try_add(i, xkb_keyname, x11_keycode_to_rdp_scancode, count);
if (!found)
{
diff --git a/libfreerdp/primitives/prim_YUV_neon.c b/libfreerdp/primitives/prim_YUV_neon.c
index 5e2039e..107ced2 100644
--- a/libfreerdp/primitives/prim_YUV_neon.c
+++ b/libfreerdp/primitives/prim_YUV_neon.c
@@ -157,7 +157,8 @@ static INLINE pstatus_t neon_YUV420ToX(const BYTE* const WINPR_RESTRICT pSrc[3],
uint8_t* pRGB2 = pRGB1 + dstStep;
const BOOL lastY = y >= nHeight - 1;
- for (UINT32 x = 0; x < nWidth - pad;)
+ UINT32 x = 0;
+ for (; x < nWidth - pad;)
{
const uint8x8_t Uraw = vld1_u8(pU);
const uint8x8x2_t Uu = vzip_u8(Uraw, Uraw);
@@ -409,7 +410,8 @@ static pstatus_t neon_LumaToYUV444(const BYTE* const WINPR_RESTRICT pSrcRaw[3],
BYTE* pU1 = pU + dstStep[1];
BYTE* pV1 = pV + dstStep[2];
- for (UINT32 x = 0; x + 16 < halfWidth; x += 16)
+ UINT32 x = 0;
+ for (; x + 16 < halfWidth; x += 16)
{
{
const uint8x16_t u = vld1q_u8(Um);
@@ -477,7 +479,8 @@ static pstatus_t neon_ChromaFilter(BYTE* WINPR_RESTRICT pDst[3], const UINT32 ds
if (val2y1 > nHeight)
continue;
- for (UINT32 x = roi->left / 2; x < halfWidth + roi->left / 2 - halfPad; x += 16)
+ UINT32 x = roi->left / 2;
+ for (; x < halfWidth + roi->left / 2 - halfPad; x += 16)
{
{
/* U = (U2x,2y << 2) - U2x1,2y - U2x,2y1 - U2x1,2y1 */
@@ -597,7 +600,8 @@ static pstatus_t neon_ChromaV1ToYUV444(const BYTE* const WINPR_RESTRICT pSrcRaw[
BYTE* pU = pDst[1] + dstStep[1] * val2y;
BYTE* pV = pDst[2] + dstStep[2] * val2y;
- for (UINT32 x = 0; x < halfWidth - halfPad; x += 16)
+ UINT32 x = 0;
+ for (; x < halfWidth - halfPad; x += 16)
{
{
uint8x16x2_t u = vld2q_u8(&pU[2 * x]);
@@ -646,7 +650,8 @@ static pstatus_t neon_ChromaV2ToYUV444(const BYTE* const WINPR_RESTRICT pSrc[3],
BYTE* pU = pDst[1] + dstStep[1] * yTop + roi->left;
BYTE* pV = pDst[2] + dstStep[2] * yTop + roi->left;
- for (UINT32 x = 0; x < halfWidth - halfPad; x += 16)
+ UINT32 x = 0;
+ for (; x < halfWidth - halfPad; x += 16)
{
{
uint8x16x2_t u = vld2q_u8(&pU[2 * x]);
@@ -678,7 +683,8 @@ static pstatus_t neon_ChromaV2ToYUV444(const BYTE* const WINPR_RESTRICT pSrc[3],
BYTE* pU = pDst[1] + dstStep[1] * (2 * y + 1 + roi->top) + roi->left;
BYTE* pV = pDst[2] + dstStep[2] * (2 * y + 1 + roi->top) + roi->left;
- for (UINT32 x = 0; x < quaterWidth - quaterPad; x += 16)
+ UINT32 x = 0;
+ for (; x < quaterWidth - quaterPad; x += 16)
{
{
uint8x16x4_t u = vld4q_u8(&pU[4 * x]);
diff --git a/libfreerdp/primitives/prim_alphaComp.c b/libfreerdp/primitives/prim_alphaComp.c
index fe4f8dc..ae4917d 100644
--- a/libfreerdp/primitives/prim_alphaComp.c
+++ b/libfreerdp/primitives/prim_alphaComp.c
@@ -17,7 +17,6 @@
* newval = alpha1*val1 + (1-alpha1)*val2
* rather than
* newval = alpha1*val1 + (1-alpha1)*alpha2*val2
- * The IPP gives other options.
*/
#include <freerdp/config.h>
diff --git a/libfreerdp/primitives/prim_copy.c b/libfreerdp/primitives/prim_copy.c
index f140c20..14b936d 100644
--- a/libfreerdp/primitives/prim_copy.c
+++ b/libfreerdp/primitives/prim_copy.c
@@ -18,10 +18,6 @@
#include <string.h>
#include <freerdp/types.h>
#include <freerdp/primitives.h>
-#ifdef WITH_IPP
-#include <ipps.h>
-#include <ippi.h>
-#endif /* WITH_IPP */
#include "prim_internal.h"
static primitives_t* generic = NULL;
@@ -132,19 +128,6 @@ static pstatus_t general_copy_8u_AC4r(const BYTE* pSrc, INT32 srcStep, BYTE* pDs
return PRIMITIVES_SUCCESS;
}
-#ifdef WITH_IPP
-/* ------------------------------------------------------------------------- */
-/* This is just ippiCopy_8u_AC4R without the IppiSize structure parameter. */
-static pstatus_t ippiCopy_8u_AC4r(const BYTE* pSrc, INT32 srcStep, BYTE* pDst, INT32 dstStep,
- INT32 width, INT32 height)
-{
- IppiSize roi;
- roi.width = width;
- roi.height = height;
- return (pstatus_t)ippiCopy_8u_AC4R(pSrc, srcStep, pDst, dstStep, roi);
-}
-#endif /* WITH_IPP */
-
/* ------------------------------------------------------------------------- */
void primitives_init_copy(primitives_t* prims)
{
@@ -161,10 +144,6 @@ void primitives_init_copy_opt(primitives_t* prims)
generic = primitives_get_generic();
primitives_init_copy(prims);
/* Pick tuned versions if possible. */
-#ifdef WITH_IPP
- prims->copy_8u = (__copy_8u_t)ippsCopy_8u;
- prims->copy_8u_AC4r = (__copy_8u_AC4r_t)ippiCopy_8u_AC4r;
-#endif
/* Performance with an SSE2 version with no prefetch seemed to be
* all over the map vs. memcpy.
* Sometimes it was significantly faster, sometimes dreadfully slower,
diff --git a/libfreerdp/primitives/test/measure.h b/libfreerdp/primitives/test/measure.h
index ee04abd..2d4f36e 100644
--- a/libfreerdp/primitives/test/measure.h
+++ b/libfreerdp/primitives/test/measure.h
@@ -29,6 +29,7 @@
#include <time.h>
#include <winpr/string.h>
+#include <winpr/sysinfo.h>
#ifndef _WIN32
#include <sys/param.h>
@@ -69,28 +70,24 @@
#define PROFILER_STOP
#endif // GOOGLE_PROFILER
-extern float _delta_time(const struct timespec* t0, const struct timespec* t1);
-extern void _floatprint(float t, char* output);
-
-#ifndef CLOCK_MONOTONIC_RAW
-#define CLOCK_MONOTONIC_RAW 4
-#endif // !CLOCK_MONOTONIC_RAW
-
-#define MEASURE_LOOP_START(_prefix_, _count_) \
- { \
- struct timespec _start, _stop; \
- char* _prefix; \
- int _count = (_count_); \
- int _loop; \
- float _delta; \
- char _str1[32], _str2[32]; \
- _prefix = _strdup(_prefix_); \
- _str1[0] = '\0'; \
- _str2[0] = '\0'; \
- clock_gettime(CLOCK_MONOTONIC_RAW, &_start); \
- PROFILER_START(_prefix); \
- _loop = (_count); \
- do \
+extern float measure_delta_time(UINT64 t0, UINT64 t1);
+extern void measure_floatprint(float t, char* output);
+
+#define MEASURE_LOOP_START(_prefix_, _count_) \
+ { \
+ UINT64 _start, _stop; \
+ char* _prefix; \
+ int _count = (_count_); \
+ int _loop; \
+ float _delta; \
+ char _str1[32], _str2[32]; \
+ _prefix = _strdup(_prefix_); \
+ _str1[0] = '\0'; \
+ _str2[0] = '\0'; \
+ _start = winpr_GetTickCount64NS(); \
+ PROFILER_START(_prefix); \
+ _loop = (_count); \
+ do \
{
#define MEASURE_LOOP_STOP \
@@ -100,28 +97,28 @@ extern void _floatprint(float t, char* output);
#define MEASURE_GET_RESULTS(_result_) \
PROFILER_STOP; \
- clock_gettime(CLOCK_MONOTONIC_RAW, &_stop); \
- _delta = _delta_time(&_start, &_stop); \
+ _stop = winpr_GetTickCount64NS(); \
+ _delta = measure_delta_time(_start, _stop); \
(_result_) = (float)_count / _delta; \
free(_prefix); \
}
#define MEASURE_SHOW_RESULTS(_result_) \
PROFILER_STOP; \
- clock_gettime(CLOCK_MONOTONIC_RAW, &_stop); \
- _delta = _delta_time(&_start, &_stop); \
+ _stop = winpr_GetTickCount64NS(); \
+ _delta = measure_delta_time(_start, _stop); \
(_result_) = (float)_count / _delta; \
- _floatprint((float)_count / _delta, _str1); \
+ measure_floatprint((float)_count / _delta, _str1); \
printf("%s: %9d iterations in %5.1f seconds = %s/s \n", _prefix, _count, _delta, _str1); \
free(_prefix); \
}
#define MEASURE_SHOW_RESULTS_SCALED(_scale_, _label_) \
PROFILER_STOP; \
- clock_gettime(CLOCK_MONOTONIC_RAW, &_stop); \
- _delta = _delta_time(&_start, &_stop); \
- _floatprint((float)_count / _delta, _str1); \
- _floatprint((float)_count / _delta * (_scale_), _str2); \
+ _stop = winpr_GetTickCount64NS(); \
+ _delta = measure_delta_time(_start, _stop); \
+ measure_floatprint((float)_count / _delta, _str1); \
+ measure_floatprint((float)_count / _delta * (_scale_), _str2); \
printf("%s: %9d iterations in %5.1f seconds = %s/s = %s%s \n", _prefix, _count, _delta, _str1, \
_str2, _label_); \
free(_prefix); \
diff --git a/libfreerdp/primitives/test/prim_test.c b/libfreerdp/primitives/test/prim_test.c
index ede8316..5ec85f8 100644
--- a/libfreerdp/primitives/test/prim_test.c
+++ b/libfreerdp/primitives/test/prim_test.c
@@ -36,31 +36,15 @@ int test_sizes[] = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
/* ------------------------------------------------------------------------- */
-#ifdef _WIN32
-float _delta_time(const struct timespec* t0, const struct timespec* t1)
+float measure_delta_time(UINT64 t0, UINT64 t1)
{
- return 0.0f;
+ INT64 diff = (INT64)(t1 - t0);
+ double retval = diff / 1000000000.0;
+ return (retval < 0.0) ? 0.0f : (float)retval;
}
-#else
-float _delta_time(const struct timespec* t0, const struct timespec* t1)
-{
- INT64 secs = (INT64)(t1->tv_sec) - (INT64)(t0->tv_sec);
- long nsecs = t1->tv_nsec - t0->tv_nsec;
- double retval = NAN;
-
- if (nsecs < 0)
- {
- --secs;
- nsecs += 1000000000;
- }
-
- retval = (double)secs + (double)nsecs / (double)1000000000.0;
- return (retval < 0.0) ? 0.0 : (float)retval;
-}
-#endif
/* ------------------------------------------------------------------------- */
-void _floatprint(float t, char* output)
+void measure_floatprint(float t, char* output)
{
/* I don't want to link against -lm, so avoid log,exp,... */
float f = 10.0;
diff --git a/libfreerdp/utils/CMakeLists.txt b/libfreerdp/utils/CMakeLists.txt
index 52690bf..d644837 100644
--- a/libfreerdp/utils/CMakeLists.txt
+++ b/libfreerdp/utils/CMakeLists.txt
@@ -47,10 +47,6 @@ if(WIN32)
freerdp_library_add(cfgmgr32)
endif()
-if(${CMAKE_SYSTEM_NAME} MATCHES SunOS)
- freerdp_library_add(rt)
-endif()
-
if(BUILD_TESTING)
add_subdirectory(test)
endif()
diff --git a/libfreerdp/utils/encoded_types.c b/libfreerdp/utils/encoded_types.c
index 68e6e4d..efce694 100644
--- a/libfreerdp/utils/encoded_types.c
+++ b/libfreerdp/utils/encoded_types.c
@@ -123,8 +123,95 @@ BOOL freerdp_read_four_byte_signed_integer(wStream* s, INT32* value)
return TRUE;
}
+BOOL freerdp_write_four_byte_signed_integer(wStream* s, INT32 value)
+{
+ FOUR_BYTE_SIGNED_INTEGER si = { 0 };
+
+ WINPR_ASSERT(s);
+ if (value > FREERDP_FOUR_BYTE_SIGNED_INT_MAX)
+ return FALSE;
+ if (value < FREERDP_FOUR_BYTE_SIGNED_INT_MIN)
+ return FALSE;
+
+ if (value < 0)
+ {
+ si.s = NEGATIVE_VAL;
+ value = -value;
+ }
+
+ if (value <= 0x1F)
+ {
+ si.c = ONE_BYTE_VAL;
+ si.val1 = value & 0x1f;
+ }
+ else if (value <= 0x1FFF)
+ {
+ si.c = TWO_BYTE_VAL;
+ si.val1 = (value >> 8) & 0x1f;
+ si.val2 = value & 0xff;
+ }
+ else if (value <= 0x1FFFFF)
+ {
+ si.c = THREE_BYTE_VAL;
+ si.val1 = (value >> 16) & 0x1f;
+ si.val2 = (value >> 8) & 0xff;
+ si.val3 = value & 0xff;
+ }
+ else if (value <= 0x1FFFFFFF)
+ {
+ si.c = FOUR_BYTE_VAL;
+ si.val1 = (value >> 24) & 0x1f;
+ si.val2 = (value >> 16) & 0xff;
+ si.val3 = (value >> 8) & 0xff;
+ si.val4 = value & 0xff;
+ }
+ else
+ {
+ WLog_ERR(TAG, "Invalid byte count for value %" PRId32, value);
+ return FALSE;
+ }
+
+ if (!Stream_EnsureRemainingCapacity(s, si.c + 1))
+ return FALSE;
+
+ const BYTE byte = ((si.c << 6) & 0xC0) | ((si.s << 5) & 0x20) | (si.val1 & 0x1F);
+ Stream_Write_UINT8(s, byte);
+
+ switch (si.c)
+ {
+ case ONE_BYTE_VAL:
+ break;
+ case TWO_BYTE_VAL:
+ Stream_Write_UINT8(s, si.val2);
+ break;
+ case THREE_BYTE_VAL:
+ Stream_Write_UINT8(s, si.val2);
+ Stream_Write_UINT8(s, si.val3);
+ break;
+ case FOUR_BYTE_VAL:
+ Stream_Write_UINT8(s, si.val2);
+ Stream_Write_UINT8(s, si.val3);
+ Stream_Write_UINT8(s, si.val4);
+ break;
+ case FIVE_BYTE_VAL:
+ case SIX_BYTE_VAL:
+ case SEVEN_BYTE_VAL:
+ case EIGHT_BYTE_VAL:
+ default:
+ WLog_ERR(TAG, "Invalid byte count value in si.c: %u", si.c);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
BOOL freerdp_read_four_byte_float(wStream* s, double* value)
{
+ return freerdp_read_four_byte_float_exp(s, value, NULL);
+}
+
+BOOL freerdp_read_four_byte_float_exp(wStream* s, double* value, BYTE* exp)
+{
FOUR_BYTE_FLOAT f = { 0 };
UINT32 base = 0;
BYTE byte = 0;
@@ -183,5 +270,132 @@ BOOL freerdp_read_four_byte_float(wStream* s, double* value)
if (f.s == NEGATIVE_VAL)
*value *= -1.0;
+ if (exp)
+ *exp = f.e;
+
+ return TRUE;
+}
+
+BOOL freerdp_write_four_byte_float(wStream* s, double value)
+{
+ FOUR_BYTE_FLOAT si = { 0 };
+
+ WINPR_ASSERT(s);
+
+ if (value > FREERDP_FOUR_BYTE_FLOAT_MAX)
+ return FALSE;
+ if (value < FREERDP_FOUR_BYTE_FLOAT_MIN)
+ return FALSE;
+
+ if (value < 0)
+ {
+ si.s = NEGATIVE_VAL;
+ value = -value;
+ }
+
+ int exp = 0;
+ double ival = FP_NAN;
+ const double aval = fabs(value);
+ const double frac = modf(aval, &ival);
+ if (frac != 0.0)
+ {
+ const double maxfrac = frac * 10000000.0;
+ if (maxfrac <= 1.0)
+ exp = 0;
+ else if (maxfrac <= 10.0)
+ exp = 1;
+ else if (maxfrac <= 100.0)
+ exp = 2;
+ else if (maxfrac <= 1000.0)
+ exp = 3;
+ else if (maxfrac <= 10000.0)
+ exp = 4;
+ else if (maxfrac <= 100000.0)
+ exp = 5;
+ else if (maxfrac <= 1000000.0)
+ exp = 6;
+ else
+ exp = 7;
+ }
+
+ UINT64 base = aval;
+ while (exp >= 0)
+ {
+ const double div = pow(10.0, exp);
+ const double dval = (aval * div);
+ base = (UINT64)dval;
+ if (base <= 0x03ffffff)
+ break;
+ exp--;
+ }
+
+ if (exp < 0)
+ return FALSE;
+
+ si.e = (BYTE)exp;
+ if (base <= 0x03)
+ {
+ si.c = ONE_BYTE_VAL;
+ si.val1 = base & 0x03;
+ }
+ else if (base <= 0x03ff)
+ {
+ si.c = TWO_BYTE_VAL;
+ si.val1 = (base >> 8) & 0x03;
+ si.val2 = base & 0xff;
+ }
+ else if (base <= 0x03ffff)
+ {
+ si.c = THREE_BYTE_VAL;
+ si.val1 = (base >> 16) & 0x03;
+ si.val2 = (base >> 8) & 0xff;
+ si.val3 = base & 0xff;
+ }
+ else if (base <= 0x03ffffff)
+ {
+ si.c = FOUR_BYTE_VAL;
+ si.val1 = (base >> 24) & 0x03;
+ si.val2 = (base >> 16) & 0xff;
+ si.val3 = (base >> 8) & 0xff;
+ si.val4 = base & 0xff;
+ }
+ else
+ {
+ WLog_ERR(TAG, "Invalid byte count for value %ld", value);
+ return FALSE;
+ }
+
+ if (!Stream_EnsureRemainingCapacity(s, si.c + 1))
+ return FALSE;
+
+ const BYTE byte =
+ ((si.c << 6) & 0xC0) | ((si.s << 5) & 0x20) | ((si.e << 2) & 0x1c) | (si.val1 & 0x03);
+ Stream_Write_UINT8(s, byte);
+
+ switch (si.c)
+ {
+ case ONE_BYTE_VAL:
+ break;
+ case TWO_BYTE_VAL:
+ Stream_Write_UINT8(s, si.val2);
+ break;
+ case THREE_BYTE_VAL:
+ Stream_Write_UINT8(s, si.val2);
+ Stream_Write_UINT8(s, si.val3);
+ break;
+ case FOUR_BYTE_VAL:
+ Stream_Write_UINT8(s, si.val2);
+ Stream_Write_UINT8(s, si.val3);
+ Stream_Write_UINT8(s, si.val4);
+ break;
+ case FIVE_BYTE_VAL:
+ case SIX_BYTE_VAL:
+ case SEVEN_BYTE_VAL:
+ case EIGHT_BYTE_VAL:
+ default:
+ WLog_ERR(TAG, "Invalid byte count value in si.c: %u", si.c);
+ return FALSE;
+ }
+
return TRUE;
}
diff --git a/libfreerdp/utils/http.c b/libfreerdp/utils/http.c
index 70963f0..5c34439 100644
--- a/libfreerdp/utils/http.c
+++ b/libfreerdp/utils/http.c
@@ -126,12 +126,18 @@ BOOL freerdp_http_request(const char* url, const char* body, long* status_code,
{
blen = strlen(body);
if (winpr_asprintf(&headers, &size, post_header_fmt, path, hostname, blen) < 0)
+ {
+ free(hostname);
return FALSE;
+ }
}
else
{
if (winpr_asprintf(&headers, &size, get_header_fmt, path, hostname) < 0)
+ {
+ free(hostname);
return FALSE;
+ }
}
ssl_ctx = SSL_CTX_new(TLS_client_method());
diff --git a/libfreerdp/utils/pcap.c b/libfreerdp/utils/pcap.c
index db50909..c18caf2 100644
--- a/libfreerdp/utils/pcap.c
+++ b/libfreerdp/utils/pcap.c
@@ -27,27 +27,11 @@
#include <winpr/assert.h>
#include <winpr/file.h>
#include <winpr/crt.h>
+#include <winpr/sysinfo.h>
#include <freerdp/log.h>
#define TAG FREERDP_TAG("utils")
-#ifndef _WIN32
-#include <sys/time.h>
-#else
-#include <time.h>
-#include <sys/timeb.h>
-#include <winpr/windows.h>
-
-int gettimeofday(struct timeval* tp, void* tz)
-{
- struct _timeb timebuffer;
- _ftime(&timebuffer);
- tp->tv_sec = (long)timebuffer.time;
- tp->tv_usec = timebuffer.millitm * 1000;
- return 0;
-}
-#endif
-
#include <freerdp/types.h>
#include <freerdp/utils/pcap.h>
@@ -131,14 +115,11 @@ static BOOL pcap_write_record(rdpPcap* pcap, const pcap_record* record)
BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length)
{
- pcap_record* record = NULL;
- struct timeval tp;
-
WINPR_ASSERT(pcap);
WINPR_ASSERT(data || (length == 0));
WINPR_ASSERT(length <= UINT32_MAX);
- record = (pcap_record*)calloc(1, sizeof(pcap_record));
+ pcap_record* record = (pcap_record*)calloc(1, sizeof(pcap_record));
if (!record)
return FALSE;
@@ -147,9 +128,10 @@ BOOL pcap_add_record(rdpPcap* pcap, const void* data, size_t length)
record->header.incl_len = (UINT32)length;
record->header.orig_len = (UINT32)length;
- gettimeofday(&tp, 0);
- record->header.ts_sec = (UINT32)tp.tv_sec;
- record->header.ts_usec = (UINT32)tp.tv_usec;
+ const UINT64 ns = winpr_GetUnixTimeNS();
+
+ record->header.ts_sec = WINPR_TIME_NS_TO_S(ns);
+ record->header.ts_usec = WINPR_TIME_NS_REM_US(ns);
if (pcap->tail == NULL)
{
diff --git a/libfreerdp/utils/stopwatch.c b/libfreerdp/utils/stopwatch.c
index 3989638..70b60b3 100644
--- a/libfreerdp/utils/stopwatch.c
+++ b/libfreerdp/utils/stopwatch.c
@@ -22,38 +22,18 @@
#include <stdio.h>
#include <stdlib.h>
+#include <winpr/sysinfo.h>
#include <freerdp/utils/stopwatch.h>
-#ifdef _WIN32
-LARGE_INTEGER stopwatch_freq = { 0 };
-#else
-#include <sys/time.h>
-#endif
-
static void stopwatch_set_time(UINT64* usecs)
{
-#ifdef _WIN32
- LARGE_INTEGER perfcount;
- QueryPerformanceCounter(&perfcount);
- *usecs = (perfcount.QuadPart * 1000000) / stopwatch_freq.QuadPart;
-#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- *usecs = tv.tv_sec * 1000000 + tv.tv_usec;
-#endif
+ const UINT64 ns = winpr_GetTickCount64NS();
+ *usecs = WINPR_TIME_NS_TO_US(ns);
}
STOPWATCH* stopwatch_create(void)
{
- STOPWATCH* sw = NULL;
-#ifdef _WIN32
- if (stopwatch_freq.QuadPart == 0)
- {
- QueryPerformanceFrequency(&stopwatch_freq);
- }
-#endif
-
- sw = (STOPWATCH*)malloc(sizeof(STOPWATCH));
+ STOPWATCH* sw = (STOPWATCH*)calloc(1, sizeof(STOPWATCH));
if (!sw)
return NULL;
stopwatch_reset(sw);
diff --git a/libfreerdp/utils/test/CMakeLists.txt b/libfreerdp/utils/test/CMakeLists.txt
index f2b6977..a7a84fc 100644
--- a/libfreerdp/utils/test/CMakeLists.txt
+++ b/libfreerdp/utils/test/CMakeLists.txt
@@ -7,6 +7,7 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestRingBuffer.c
TestPodArrays.c
+ TestEncodedTypes.c
)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
@@ -15,7 +16,10 @@ create_test_sourcelist(${MODULE_PREFIX}_SRCS
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
-target_link_libraries(${MODULE_NAME} freerdp winpr)
+target_link_libraries(${MODULE_NAME} PRIVATE freerdp winpr)
+if (NOT WIN32)
+ target_link_libraries(${MODULE_NAME} PRIVATE m)
+endif()
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
diff --git a/libfreerdp/utils/test/TestEncodedTypes.c b/libfreerdp/utils/test/TestEncodedTypes.c
new file mode 100644
index 0000000..f051d9c
--- /dev/null
+++ b/libfreerdp/utils/test/TestEncodedTypes.c
@@ -0,0 +1,212 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ *
+ * Copyright 2024 Thincast Technologies GmbH
+ * Copyright 2024 Armin Novak <anovak@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.
+ */
+
+#include <stdio.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+
+#include <winpr/crypto.h>
+#include <freerdp/utils/encoded_types.h>
+
+#define MIN(x, y) ((x) < (y)) ? (x) : (y)
+#define MAX(x, y) ((x) > (y)) ? (x) : (y)
+
+static BOOL test_signed_integer_read_write_equal(INT32 value)
+{
+ INT32 rvalue = 0;
+ BYTE buffer[32] = { 0 };
+ wStream sbuffer = { 0 };
+ wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
+ WINPR_ASSERT(s);
+
+ if (!freerdp_write_four_byte_signed_integer(s, value))
+ {
+ fprintf(stderr, "[%s(%" PRId32 ")] failed to write to stream\n", __func__, value);
+ return FALSE;
+ }
+ if (!Stream_SetPosition(s, 0))
+ {
+ fprintf(stderr, "[%s(%" PRId32 ")] failed to reset stream position\n", __func__, value);
+ return FALSE;
+ }
+ if (!freerdp_read_four_byte_signed_integer(s, &rvalue))
+ {
+ fprintf(stderr, "[%s(%" PRId32 ")] failed to read from stream\n", __func__, value);
+ return FALSE;
+ }
+ if (value != rvalue)
+ {
+ fprintf(stderr, "[%s(%" PRId32 ")] read invalid value %" PRId32 " from stream\n", __func__,
+ value, rvalue);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL test_signed_integer_write_oor(INT32 value)
+{
+ BYTE buffer[32] = { 0 };
+ wStream sbuffer = { 0 };
+ wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
+ WINPR_ASSERT(s);
+
+ if (freerdp_write_four_byte_signed_integer(s, value))
+ {
+ fprintf(stderr, "[%s(%" PRId32 ")] out of range value not detected and written to stream\n",
+ __func__, value);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL test_signed_integers(void)
+{
+ const INT32 outofrange[] = { FREERDP_FOUR_BYTE_SIGNED_INT_MAX + 1,
+ FREERDP_FOUR_BYTE_SIGNED_INT_MIN - 1, INT32_MAX, INT32_MIN };
+ const INT32 limits[] = { 1, 0, -1, FREERDP_FOUR_BYTE_SIGNED_INT_MAX,
+ FREERDP_FOUR_BYTE_SIGNED_INT_MIN };
+
+ for (size_t x = 0; x < ARRAYSIZE(limits); x++)
+ {
+ if (!test_signed_integer_read_write_equal(limits[x]))
+ return FALSE;
+ }
+ for (size_t x = 0; x < ARRAYSIZE(outofrange); x++)
+ {
+ if (!test_signed_integer_write_oor(outofrange[x]))
+ return FALSE;
+ }
+ for (size_t x = 0; x < 100000; x++)
+ {
+ INT32 val = 0;
+ winpr_RAND(&val, sizeof(val));
+ val = MAX(val, 0);
+ val = MIN(val, FREERDP_FOUR_BYTE_SIGNED_INT_MAX);
+
+ const INT32 nval = -val;
+ if (!test_signed_integer_read_write_equal(val))
+ return FALSE;
+ if (!test_signed_integer_read_write_equal(nval))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL test_float_read_write_equal(double value)
+{
+ BYTE exp = 0;
+ double rvalue = FP_NAN;
+ BYTE buffer[32] = { 0 };
+ wStream sbuffer = { 0 };
+ wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
+ WINPR_ASSERT(s);
+
+ if (!freerdp_write_four_byte_float(s, value))
+ {
+ fprintf(stderr, "[%s(%lf)] failed to write to stream\n", __func__, value);
+ return FALSE;
+ }
+ if (!Stream_SetPosition(s, 0))
+ {
+ fprintf(stderr, "[%s(%lf)] failed to reset stream position\n", __func__, value);
+ return FALSE;
+ }
+ if (!freerdp_read_four_byte_float_exp(s, &rvalue, &exp))
+ {
+ fprintf(stderr, "[%s(%lf)] failed to read from stream\n", __func__, value);
+ return FALSE;
+ }
+ const double diff = fabs(value - rvalue);
+ const UINT64 expdiff = diff * pow(10, exp);
+ if (expdiff > 0)
+ {
+ fprintf(stderr, "[%s(%lf)] read invalid value %lf from stream\n", __func__, value, rvalue);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static BOOL test_floag_write_oor(double value)
+{
+ BYTE buffer[32] = { 0 };
+ wStream sbuffer = { 0 };
+ wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
+ WINPR_ASSERT(s);
+
+ if (freerdp_write_four_byte_float(s, value))
+ {
+ fprintf(stderr, "[%s(%lf)] out of range value not detected and written to stream\n",
+ __func__, value);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static double get(void)
+{
+ double val = NAN;
+ do
+ {
+ winpr_RAND(&val, sizeof(val));
+ } while ((val < 0.0) || (val > FREERDP_FOUR_BYTE_FLOAT_MAX) || isnan(val) || isinf(val));
+ return val;
+}
+
+static BOOL test_floats(void)
+{
+ const double outofrange[] = { FREERDP_FOUR_BYTE_FLOAT_MAX + 1, FREERDP_FOUR_BYTE_FLOAT_MIN - 1,
+ DBL_MAX, -DBL_MAX };
+ const double limits[] = { 100045.26129238126, 1, 0, -1, FREERDP_FOUR_BYTE_FLOAT_MAX,
+ FREERDP_FOUR_BYTE_FLOAT_MIN };
+
+ for (size_t x = 0; x < ARRAYSIZE(limits); x++)
+ {
+ if (!test_float_read_write_equal(limits[x]))
+ return FALSE;
+ }
+ for (size_t x = 0; x < ARRAYSIZE(outofrange); x++)
+ {
+ if (!test_floag_write_oor(outofrange[x]))
+ return FALSE;
+ }
+ for (size_t x = 0; x < 100000; x++)
+ {
+ double val = get();
+
+ const double nval = -val;
+ if (!test_float_read_write_equal(val))
+ return FALSE;
+ if (!test_float_read_write_equal(nval))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int TestEncodedTypes(int argc, char* argv[])
+{
+ WINPR_UNUSED(argc);
+ WINPR_UNUSED(argv);
+
+ if (!test_signed_integers())
+ return -1;
+ if (!test_floats())
+ return -1;
+ return 0;
+}