diff options
Diffstat (limited to 'libfreerdp')
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(®ion); + if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride, + IMG_HEIGHT, ®ion)) + goto fail; + + region16_clear(®ion); + if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride, + IMG_HEIGHT, ®ion)) + goto fail; + region16_print(®ion); + + rc = 0; +fail: + region16_uninit(®ion); + 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; +} |