diff -Nru freerdp2-2.6.1+dfsg1/debian/changelog freerdp2-2.6.1+dfsg1/debian/changelog --- freerdp2-2.6.1+dfsg1/debian/changelog 2022-03-08 07:25:13.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/changelog 2022-04-11 14:33:33.000000000 +0000 @@ -1,3 +1,10 @@ +freerdp2 (2.6.1+dfsg1-3ubuntu1) jammy; urgency=medium + + * Cherry-pick commits from stable-2.0 branch up to 20220411 2b65b7c + (LP: #1968577) + + -- Jeremy Bicha Mon, 11 Apr 2022 10:33:33 -0400 + freerdp2 (2.6.1+dfsg1-3) unstable; urgency=medium * debian/patches: diff -Nru freerdp2-2.6.1+dfsg1/debian/control freerdp2-2.6.1+dfsg1/debian/control --- freerdp2-2.6.1+dfsg1/debian/control 2022-03-08 07:21:02.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/control 2022-04-11 14:33:33.000000000 +0000 @@ -1,7 +1,8 @@ Source: freerdp2 Section: x11 Priority: optional -Maintainer: Debian Remote Maintainers +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Debian Remote Maintainers Uploaders: Mike Gabriel , Bernhard Miklautz , diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch freerdp2-2.6.1+dfsg1/debian/patches/1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch 2022-03-08 07:25:13.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch 2022-04-11 14:33:33.000000000 +0000 @@ -1,10 +1,34 @@ -Description: Keep DumpThreadHandles as a symbol even if WITH_DEBUG_THREADS is OFF. -Author: Mike Gabriel +From: Mike Gabriel +Date: Mon, 11 Apr 2022 10:02:36 -0400 +Subject: Keep DumpThreadHandles as a symbol even if WITH_DEBUG_THREADS is + OFF. + Forwarded: https://github.com/FreeRDP/FreeRDP/pull/7708 +--- + winpr/include/winpr/thread.h | 3 --- + winpr/libwinpr/thread/thread.c | 4 ++-- + 2 files changed, 2 insertions(+), 5 deletions(-) +diff --git a/winpr/include/winpr/thread.h b/winpr/include/winpr/thread.h +index 4e603b3..c01b04b 100644 +--- a/winpr/include/winpr/thread.h ++++ b/winpr/include/winpr/thread.h +@@ -248,10 +248,7 @@ extern "C" + /* CommandLineToArgvA is not present in the original Windows API, WinPR always exports it */ + + WINPR_API LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs); +- +-#if defined(WITH_DEBUG_THREADS) + WINPR_API VOID DumpThreadHandles(void); +-#endif + + #ifdef __cplusplus + } +diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c +index e671b64..40303f5 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c -@@ -783,9 +783,9 @@ +@@ -783,9 +783,9 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) return TRUE; } @@ -15,7 +39,7 @@ char** msg; size_t used, i; void* stack = winpr_backtrace(20); -@@ -846,6 +846,6 @@ +@@ -846,6 +846,6 @@ VOID DumpThreadHandles(void) } WLog_DBG(TAG, "---------------- End Dumping thread handles -------------"); @@ -23,16 +47,3 @@ #endif +} #endif ---- a/winpr/include/winpr/thread.h -+++ b/winpr/include/winpr/thread.h -@@ -248,10 +248,7 @@ - /* CommandLineToArgvA is not present in the original Windows API, WinPR always exports it */ - - WINPR_API LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs); -- --#if defined(WITH_DEBUG_THREADS) - WINPR_API VOID DumpThreadHandles(void); --#endif - - #ifdef __cplusplus - } diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1002-Added-more-log-messages-for-SurfaceCommand-failures.patch freerdp2-2.6.1+dfsg1/debian/patches/1002-Added-more-log-messages-for-SurfaceCommand-failures.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1002-Added-more-log-messages-for-SurfaceCommand-failures.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1002-Added-more-log-messages-for-SurfaceCommand-failures.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,118 @@ +From: Armin Novak +Date: Tue, 8 Mar 2022 15:01:09 +0100 +Subject: Added more log messages for SurfaceCommand failures + +(cherry picked from commit c6f204091291990f85c23450778fcab35571eed5) +(cherry picked from commit 631e71bebd041fbac2932555f17de050f6def91f) +--- + libfreerdp/core/surface.c | 40 +++++++++++++++++++++++++++++++++++++--- + 1 file changed, 37 insertions(+), 3 deletions(-) + +diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c +index ca89d23..a99da01 100644 +--- a/libfreerdp/core/surface.c ++++ b/libfreerdp/core/surface.c +@@ -37,7 +37,11 @@ static BOOL update_recv_surfcmd_bitmap_header_ex(wStream* s, TS_COMPRESSED_BITMA + return FALSE; + + if (Stream_GetRemainingLength(s) < 24) ++ { ++ WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), ++ 24); + return FALSE; ++ } + + Stream_Read_UINT32(s, header->highUniqueId); + Stream_Read_UINT32(s, header->lowUniqueId); +@@ -54,7 +58,11 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp) + return FALSE; + + if (Stream_GetRemainingLength(s) < 12) ++ { ++ WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), ++ 12); + return FALSE; ++ } + + Stream_Read_UINT8(s, bmp->bpp); + Stream_Read_UINT8(s, bmp->flags); +@@ -86,7 +94,11 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp) + } + + if (Stream_GetRemainingLength(s) < bmp->bitmapDataLength) ++ { ++ WLog_ERR(TAG, "expected bitmapDataLength %" PRIu32 ", not enough data", ++ bmp->bitmapDataLength); + return FALSE; ++ } + + pos = Stream_GetPosition(s) + bmp->bitmapDataLength; + bmp->bitmapData = Stream_Pointer(s); +@@ -132,7 +144,10 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT + SURFACE_BITS_COMMAND cmd = { 0 }; + + if (Stream_GetRemainingLength(s) < 8) ++ { ++ WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 8); + goto fail; ++ } + + cmd.cmdType = cmdType; + Stream_Read_UINT16(s, cmd.destLeft); +@@ -152,7 +167,12 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT + goto fail; + } + +- return update->SurfaceBits(update->context, &cmd); ++ if (!update->SurfaceBits(update->context, &cmd)) ++ { ++ WLog_DBG(TAG, "update->SurfaceBits implementation failed"); ++ goto fail; ++ } ++ return TRUE; + fail: + return FALSE; + } +@@ -162,7 +182,10 @@ static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s) + SURFACE_FRAME_MARKER marker; + + if (Stream_GetRemainingLength(s) < 6) ++ { ++ WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 6); + return FALSE; ++ } + + Stream_Read_UINT16(s, marker.frameAction); + Stream_Read_UINT32(s, marker.frameId); +@@ -176,7 +199,13 @@ static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s) + return FALSE; + } + +- return update->SurfaceFrameMarker(update->context, &marker); ++ if (!update->SurfaceFrameMarker(update->context, &marker)) ++ { ++ WLog_DBG(TAG, "update->SurfaceFrameMarker implementation failed"); ++ return FALSE; ++ } ++ ++ return TRUE; + } + + int update_recv_surfcmds(rdpUpdate* update, wStream* s) +@@ -246,10 +275,15 @@ static BOOL update_write_surfcmd_bitmap_ex(wStream* s, const TS_BITMAP_DATA_EX* + if (!Stream_EnsureRemainingCapacity(s, 12)) + return FALSE; + ++ if (bmp->codecID > UINT8_MAX) ++ { ++ WLog_ERR(TAG, "Invalid TS_BITMAP_DATA_EX::codecID=0x%04" PRIx16 "", bmp->codecID); ++ return FALSE; ++ } + Stream_Write_UINT8(s, bmp->bpp); + Stream_Write_UINT8(s, bmp->flags); + Stream_Write_UINT8(s, 0); /* reserved1, reserved2 */ +- Stream_Write_UINT8(s, bmp->codecID); ++ Stream_Write_UINT8(s, (UINT8)bmp->codecID); + Stream_Write_UINT16(s, bmp->width); + Stream_Write_UINT16(s, bmp->height); + Stream_Write_UINT32(s, bmp->bitmapDataLength); diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1003-rfx_process_message-verbose-error-log.patch freerdp2-2.6.1+dfsg1/debian/patches/1003-rfx_process_message-verbose-error-log.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1003-rfx_process_message-verbose-error-log.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1003-rfx_process_message-verbose-error-log.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,43 @@ +From: Armin Novak +Date: Tue, 8 Mar 2022 15:21:23 +0100 +Subject: rfx_process_message verbose error log + +(cherry picked from commit c194a68b1bb44af3a180d7bdad678655bd673dc9) +(cherry picked from commit 79207e6700e83ffcbd707985086bb3a6dc06dfb9) +--- + libfreerdp/codec/rfx.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c +index 8c65e75..b41c157 100644 +--- a/libfreerdp/codec/rfx.c ++++ b/libfreerdp/codec/rfx.c +@@ -1071,7 +1071,10 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, + UINT8 channelId; + + if (Stream_GetRemainingLength(s) < 2) ++ { ++ WLog_ERR(TAG, "extraBlockLen too small(%" PRIuz ")", Stream_GetRemainingLength(s)); + return FALSE; ++ } + + extraBlockLen = 2; + Stream_Read_UINT8(s, codecId); /* codecId (1 byte) must be set to 0x01 */ +@@ -1212,6 +1215,9 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, + NULL, FREERDP_FLIP_NONE)) + { + region16_uninit(&updateRegion); ++ WLog_ERR(TAG, ++ "nbUpdateRectx[% " PRIu32 " (%" PRIu32 ")] freerdp_image_copy failed", ++ j, nbUpdateRects); + return FALSE; + } + +@@ -1226,6 +1232,7 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, + return TRUE; + } + ++ WLog_ERR(TAG, "%s failed", __FUNCTION__); + return FALSE; + } + diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1004-Implemented-4341-Default-to-network-auto.patch freerdp2-2.6.1+dfsg1/debian/patches/1004-Implemented-4341-Default-to-network-auto.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1004-Implemented-4341-Default-to-network-auto.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1004-Implemented-4341-Default-to-network-auto.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,76 @@ +From: Armin Novak +Date: Thu, 29 Jul 2021 13:26:05 +0200 +Subject: Implemented #4341: Default to /network:auto + +If no arguments are supplied, default to the behaviour of +/network:auto. This ensures the default experience is using the +best available graphics options. +As soon as any /network, /bpp, /rfx, /gfx, ... argument is used +only use these. + +(cherry picked from commit d3168a1436eefe6864727991b18e458c2d6c87b3) +(cherry picked from commit baf35cece9ff369d27deae1fed23d56907d82c31) +--- + client/common/cmdline.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/client/common/cmdline.c b/client/common/cmdline.c +index 15d4813..453a38c 100644 +--- a/client/common/cmdline.c ++++ b/client/common/cmdline.c +@@ -27,6 +27,8 @@ + #include + #include + ++#include ++ + #include + #include + #include +@@ -46,6 +48,8 @@ + #include "cmdline.h" + + #include ++ ++#define WINPR_ASSERT(x) assert(x) + #define TAG CLIENT_TAG("common.cmdline") + + static BOOL freerdp_client_print_codepages(const char* arg) +@@ -1567,6 +1571,28 @@ static BOOL parseSizeValue(const char* input, unsigned long* v1, unsigned long* + return TRUE; + } + ++static BOOL prepare_default_settings(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* args, ++ BOOL rdp_file) ++{ ++ size_t x; ++ const char* arguments[] = { "network", "gfx", "rfx", "bpp" }; ++ WINPR_ASSERT(settings); ++ WINPR_ASSERT(args); ++ ++ if (rdp_file) ++ return FALSE; ++ ++ for (x = 0; x < ARRAYSIZE(arguments); x++) ++ { ++ const char* arg = arguments[x]; ++ COMMAND_LINE_ARGUMENT_A* p = CommandLineFindArgumentA(args, arg); ++ if (p && (p->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) ++ return FALSE; ++ } ++ ++ return freerdp_set_connection_type(settings, CONNECTION_TYPE_AUTODETECT); ++} ++ + int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, int argc, + char** argv, BOOL allowUnknown) + { +@@ -1637,6 +1663,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, + + if (status < 0) + return status; ++ ++ prepare_default_settings(settings, largs, ext); + } + + CommandLineFindArgumentA(largs, "v"); diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1005-Workaround-for-MS-RDPBCGR-2.2.9.2.3-Frame-Marker-Com.patch freerdp2-2.6.1+dfsg1/debian/patches/1005-Workaround-for-MS-RDPBCGR-2.2.9.2.3-Frame-Marker-Com.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1005-Workaround-for-MS-RDPBCGR-2.2.9.2.3-Frame-Marker-Com.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1005-Workaround-for-MS-RDPBCGR-2.2.9.2.3-Frame-Marker-Com.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,42 @@ +From: Armin Novak +Date: Wed, 9 Mar 2022 09:01:11 +0100 +Subject: Workaround for [MS-RDPBCGR] 2.2.9.2.3 Frame Marker Command + (TS_FRAME_MARKER) + +Connections with windows 2016 and 2019 sometimes receive short +frame marker. Ignore these to prevent disconnects + +(cherry picked from commit 91ef44ed35c99c409d39f6c480592f8601b45e35) +(cherry picked from commit 6462eca724a886e8c1abb5b41955108023d1c1e6) +--- + libfreerdp/core/surface.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c +index a99da01..e288799 100644 +--- a/libfreerdp/core/surface.c ++++ b/libfreerdp/core/surface.c +@@ -181,14 +181,21 @@ static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s) + { + SURFACE_FRAME_MARKER marker; + +- if (Stream_GetRemainingLength(s) < 6) ++ if (Stream_GetRemainingLength(s) < 2) + { + WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 6); + return FALSE; + } + + Stream_Read_UINT16(s, marker.frameAction); +- Stream_Read_UINT32(s, marker.frameId); ++ if (Stream_GetRemainingLength(s) < 4) ++ WLog_WARN(TAG, ++ "[SERVER-BUG]: got %" PRIuz ", expected %" PRIuz ++ " bytes. [MS-RDPBCGR] 2.2.9.2.3 Frame Marker Command (TS_FRAME_MARKER) is " ++ "missing frameId, ignoring", ++ Stream_GetRemainingLength(s), 4); ++ else ++ Stream_Read_UINT32(s, marker.frameId); + WLog_Print(update->log, WLOG_DEBUG, + "SurfaceFrameMarker: action: %s (%" PRIu32 ") id: %" PRIu32 "", + (!marker.frameAction) ? "Begin" : "End", marker.frameAction, marker.frameId); diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1006-Changelog.patch freerdp2-2.6.1+dfsg1/debian/patches/1006-Changelog.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1006-Changelog.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1006-Changelog.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,34 @@ +From: Armin Novak +Date: Wed, 9 Mar 2022 15:35:47 +0100 +Subject: Changelog + +(cherry picked from commit 1c91d66a50b2f3f602765fddd1ed2767c427a8fe) +--- + ChangeLog | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/ChangeLog b/ChangeLog +index 5d32697..608c697 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,7 +1,19 @@ ++# 2022-XX-YY Version 2.X.Y ++ ++Noteworthy changes: ++ ++Fixed issues: ++* Backported #6786: Use /network:auto by default ++* Backported #7714: Workaround for broken surface frame marker ++ ++Important notes: ++ ++For a complete and detailed change log since the last release run: ++git log 2.6.1..2.X.Y ++ + # 2022-03-07 Version 2.6.1 + + Noteworthy changes: +-* Decreased logging verbosity, now freerdp is much less verbose by default + + Fixed issues: + * Backported freerdp_abort_connect during freerdp_connect fix (#7700) diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1007-Added-WINPR_ASSERT.patch freerdp2-2.6.1+dfsg1/debian/patches/1007-Added-WINPR_ASSERT.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1007-Added-WINPR_ASSERT.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1007-Added-WINPR_ASSERT.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,71 @@ +From: Armin Novak +Date: Wed, 9 Jun 2021 13:05:33 +0200 +Subject: Added WINPR_ASSERT + +Added a WinPR macro that can be used for WinPR and FreeRDP to +replace standard C assert. +It is more verbose and logs issues to WLog which makes it easier +for us to trace problems in the field. + +(cherry picked from commit b435e6db9b21bfe0a456a38f086f51151d3c20ad) +(cherry picked from commit 76660aab19020f45d398fe42100351960ad40bb2) +--- + winpr/include/winpr/assert.h | 49 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + create mode 100644 winpr/include/winpr/assert.h + +diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h +new file mode 100644 +index 0000000..724f82b +--- /dev/null ++++ b/winpr/include/winpr/assert.h +@@ -0,0 +1,49 @@ ++/** ++ * WinPR: Windows Portable Runtime ++ * Runtime ASSERT macros ++ * ++ * Copyright 2021 Armin Novak ++ * Copyright 2021 Thincast Technologies GmbH ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#ifndef WINPR_ASSERT_H ++#define WINPR_ASSERT_H ++ ++#include ++#include ++#include ++#include ++ ++#define WINPR_ASSERT(cond) \ ++ do \ ++ { \ ++ if (!(cond)) \ ++ { \ ++ WLog_FATAL("com.freerdp.winpr.assert", "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ ++ __FUNCTION__, __LINE__); \ ++ abort(); \ ++ } \ ++ } while (0) ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* WINPR_ERROR_H */ diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1008-Added-option-do-disable-WINPR_ASSERT.patch freerdp2-2.6.1+dfsg1/debian/patches/1008-Added-option-do-disable-WINPR_ASSERT.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1008-Added-option-do-disable-WINPR_ASSERT.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1008-Added-option-do-disable-WINPR_ASSERT.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,53 @@ +From: akallabeth +Date: Thu, 10 Jun 2021 08:57:40 +0200 +Subject: Added option do disable WINPR_ASSERT + +(cherry picked from commit 3a75228242401de96eaf66222e77a72a40dc3b40) +(cherry picked from commit f522bcb63a8d2f272b1f50f5ba19617345f55259) +--- + winpr/CMakeLists.txt | 6 ++++++ + winpr/include/winpr/assert.h | 7 +++++++ + 2 files changed, 13 insertions(+) + +diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt +index 7e5860d..1827a0a 100644 +--- a/winpr/CMakeLists.txt ++++ b/winpr/CMakeLists.txt +@@ -21,6 +21,12 @@ project(WinPR C) + + set(CMAKE_COLOR_MAKEFILE ON) + ++option(WITH_VERBOSE_WINPR_ASSERT "Compile with verbose WINPR_ASSERT." ON) ++ ++if (WITH_VERBOSE_WINPR_ASSERT) ++ add_definitions(-DWITH_VERBOSE_WINPR_ASSERT) ++endif() ++ + if(FREERDP_VERSION) + set(FREERDP_BUILD 1) + endif() +diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h +index 724f82b..ae9deb2 100644 +--- a/winpr/include/winpr/assert.h ++++ b/winpr/include/winpr/assert.h +@@ -26,6 +26,7 @@ + #include + #include + ++#if WITH_VERBOSE_WINPR_ASSERT + #define WINPR_ASSERT(cond) \ + do \ + { \ +@@ -36,6 +37,12 @@ + abort(); \ + } \ + } while (0) ++#else ++#define WINPR_ASSERT(cond) \ ++ do \ ++ { \ ++ } while (0) ++#endif + + #ifdef __cplusplus + extern "C" diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1009-Improve-WINPR_ASSERT-log-backtrace.patch freerdp2-2.6.1+dfsg1/debian/patches/1009-Improve-WINPR_ASSERT-log-backtrace.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1009-Improve-WINPR_ASSERT-log-backtrace.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1009-Improve-WINPR_ASSERT-log-backtrace.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,44 @@ +From: Armin Novak +Date: Wed, 16 Jun 2021 13:11:07 +0200 +Subject: Improve WINPR_ASSERT, log backtrace + +(cherry picked from commit 9e94f1dace7295e506e01b9ece59d77f62343e3c) +(cherry picked from commit 83dffd0009b4d8b7b241c621b6aff4efe12a0380) +--- + winpr/include/winpr/assert.h | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h +index ae9deb2..03f2ff2 100644 +--- a/winpr/include/winpr/assert.h ++++ b/winpr/include/winpr/assert.h +@@ -25,17 +25,19 @@ + #include + #include + #include ++#include + +-#if WITH_VERBOSE_WINPR_ASSERT +-#define WINPR_ASSERT(cond) \ +- do \ +- { \ +- if (!(cond)) \ +- { \ +- WLog_FATAL("com.freerdp.winpr.assert", "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ +- __FUNCTION__, __LINE__); \ +- abort(); \ +- } \ ++#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0) ++#define WINPR_ASSERT(cond) \ ++ do \ ++ { \ ++ if (!(cond)) \ ++ { \ ++ const char* tag = "com.freerdp.winpr.assert"; \ ++ WLog_FATAL(tag, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, __FUNCTION__, __LINE__); \ ++ winpr_log_backtrace(tag, WLOG_FATAL, 20); \ ++ abort(); \ ++ } \ + } while (0) + #else + #define WINPR_ASSERT(cond) \ diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1010-Fixed-warnings-from-WLOG_ASSERT.patch freerdp2-2.6.1+dfsg1/debian/patches/1010-Fixed-warnings-from-WLOG_ASSERT.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1010-Fixed-warnings-from-WLOG_ASSERT.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1010-Fixed-warnings-from-WLOG_ASSERT.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,44 @@ +From: Armin Novak +Date: Tue, 1 Feb 2022 08:17:43 +0100 +Subject: Fixed warnings from WLOG_ASSERT + +(cherry picked from commit 02896b0656de693a7014cc8ca6ff12de1d9ffabd) +(cherry picked from commit e675ffcb35e3211b9424c8a067494057b803b935) +--- + winpr/include/winpr/assert.h | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h +index 03f2ff2..b8530bf 100644 +--- a/winpr/include/winpr/assert.h ++++ b/winpr/include/winpr/assert.h +@@ -28,16 +28,19 @@ + #include + + #if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0) +-#define WINPR_ASSERT(cond) \ +- do \ +- { \ +- if (!(cond)) \ +- { \ +- const char* tag = "com.freerdp.winpr.assert"; \ +- WLog_FATAL(tag, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, __FUNCTION__, __LINE__); \ +- winpr_log_backtrace(tag, WLOG_FATAL, 20); \ +- abort(); \ +- } \ ++#define WINPR_ASSERT(cond) \ ++ do \ ++ { \ ++ if (!(cond)) \ ++ { \ ++ static wLog* _log_cached_ptr = NULL; \ ++ if (!_log_cached_ptr) \ ++ _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert"); \ ++ WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ ++ __FUNCTION__, __LINE__); \ ++ winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20); \ ++ abort(); \ ++ } \ + } while (0) + #else + #define WINPR_ASSERT(cond) \ diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1011-Removed-cached-wlog-pointer.patch freerdp2-2.6.1+dfsg1/debian/patches/1011-Removed-cached-wlog-pointer.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1011-Removed-cached-wlog-pointer.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1011-Removed-cached-wlog-pointer.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,25 @@ +From: Armin Novak +Date: Tue, 1 Feb 2022 11:49:12 +0100 +Subject: Removed cached wlog pointer + +(cherry picked from commit 77580466ae31c93af63c55e4cb56b297c01093f3) +(cherry picked from commit 0089ce25b48535e081e9680bf4f2bb9d7e0d0534) +--- + winpr/include/winpr/assert.h | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h +index b8530bf..0cef841 100644 +--- a/winpr/include/winpr/assert.h ++++ b/winpr/include/winpr/assert.h +@@ -33,9 +33,7 @@ + { \ + if (!(cond)) \ + { \ +- static wLog* _log_cached_ptr = NULL; \ +- if (!_log_cached_ptr) \ +- _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert"); \ ++ wLog* _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert"); \ + WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ + __FUNCTION__, __LINE__); \ + winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20); \ diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1012-Replaced-WINPR_ASSERT-defines-use-include.patch freerdp2-2.6.1+dfsg1/debian/patches/1012-Replaced-WINPR_ASSERT-defines-use-include.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1012-Replaced-WINPR_ASSERT-defines-use-include.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1012-Replaced-WINPR_ASSERT-defines-use-include.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,208 @@ +From: Armin Novak +Date: Mon, 28 Mar 2022 11:33:38 +0200 +Subject: Replaced WINPR_ASSERT defines, use include + +(cherry picked from commit 2008751c04bc7b51c8737f161c09ad17ae56838e) +--- + channels/ainput/client/ainput_main.c | 4 +--- + channels/ainput/server/ainput_main.c | 4 +--- + channels/rdpgfx/rdpgfx_common.c | 4 +--- + client/common/cmdline.c | 4 +--- + libfreerdp/codec/h264_mediacodec.c | 4 +--- + libfreerdp/codec/progressive.c | 4 +--- + libfreerdp/core/utils.c | 4 +--- + winpr/libwinpr/registry/registry_reg.c | 4 +--- + winpr/libwinpr/sspicli/sspicli.c | 4 +--- + 9 files changed, 9 insertions(+), 27 deletions(-) + +diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c +index bf4ce26..d8eb8ec 100644 +--- a/channels/ainput/client/ainput_main.c ++++ b/channels/ainput/client/ainput_main.c +@@ -26,7 +26,7 @@ + #include + + #include +-#include ++#include + #include + #include + +@@ -37,8 +37,6 @@ + + #include "../common/ainput_common.h" + +-#define WINPR_ASSERT(x) assert(x) +- + #define TAG CHANNELS_TAG("ainput.client") + + typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK; +diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c +index 670b668..bc1737e 100644 +--- a/channels/ainput/server/ainput_main.c ++++ b/channels/ainput/server/ainput_main.c +@@ -27,7 +27,7 @@ + #include + + #include +-#include ++#include + #include + #include + #include +@@ -39,8 +39,6 @@ + + #include "../common/ainput_common.h" + +-#define WINPR_ASSERT(x) assert(x) +- + #define TAG CHANNELS_TAG("ainput.server") + + typedef enum +diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c +index c0bc0b0..03fc97c 100644 +--- a/channels/rdpgfx/rdpgfx_common.c ++++ b/channels/rdpgfx/rdpgfx_common.c +@@ -24,12 +24,10 @@ + #endif + + #include +-#include ++#include + #include + #include + +-#define WINPR_ASSERT(x) assert(x) +- + #define TAG CHANNELS_TAG("rdpgfx.common") + + #include "rdpgfx_common.h" +diff --git a/client/common/cmdline.c b/client/common/cmdline.c +index 453a38c..da53f85 100644 +--- a/client/common/cmdline.c ++++ b/client/common/cmdline.c +@@ -24,10 +24,9 @@ + #endif + + #include +-#include + #include + +-#include ++#include + + #include + #include +@@ -49,7 +48,6 @@ + + #include + +-#define WINPR_ASSERT(x) assert(x) + #define TAG CLIENT_TAG("common.cmdline") + + static BOOL freerdp_client_print_codepages(const char* arg) +diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c +index ba207e5..9caec04 100644 +--- a/libfreerdp/codec/h264_mediacodec.c ++++ b/libfreerdp/codec/h264_mediacodec.c +@@ -18,7 +18,7 @@ + */ + + #include +-#include ++#include + #include + + #include +@@ -29,8 +29,6 @@ + + #include "h264.h" + +-#define WINPR_ASSERT(x) assert(x) +- + #define RESOLVE_MEDIANDK_FUNC(sys, name) \ + ({ \ + BOOL rc = TRUE; \ +diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c +index 60343b8..5fc98f1 100644 +--- a/libfreerdp/codec/progressive.c ++++ b/libfreerdp/codec/progressive.c +@@ -23,7 +23,7 @@ + #include "config.h" + #endif + +-#include ++#include + #include + #include + #include +@@ -41,8 +41,6 @@ + #include "rfx_types.h" + #include "progressive.h" + +-#define WINPR_ASSERT(x) assert(x) +- + #define TAG FREERDP_TAG("codec.progressive") + + struct _RFX_PROGRESSIVE_UPGRADE_STATE +diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c +index 6b6770b..72432a2 100644 +--- a/libfreerdp/core/utils.c ++++ b/libfreerdp/core/utils.c +@@ -22,7 +22,7 @@ + #include "config.h" + #endif + +-#include ++#include + + #include + +@@ -31,8 +31,6 @@ + + #include "utils.h" + +-#define WINPR_ASSERT(x) assert(x) +- + BOOL utils_abort_connect(rdpContext* context) + { + WINPR_ASSERT(context); +diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c +index 511d927..3867b06 100644 +--- a/winpr/libwinpr/registry/registry_reg.c ++++ b/winpr/libwinpr/registry/registry_reg.c +@@ -27,7 +27,7 @@ + #include + + #include +-#include ++#include + #include + #include + +@@ -36,8 +36,6 @@ + #include "../log.h" + #define TAG WINPR_TAG("registry") + +-#define WINPR_ASSERT assert +- + #define WINPR_HKLM_HIVE "/etc/winpr/HKLM.reg" + + struct reg_data_type +diff --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c +index 5a13b99..1d491b8 100644 +--- a/winpr/libwinpr/sspicli/sspicli.c ++++ b/winpr/libwinpr/sspicli/sspicli.c +@@ -21,11 +21,9 @@ + #include "config.h" + #endif + +-#include ++#include + #include + +-#define WINPR_ASSERT(x) assert(x) +- + /** + * sspicli.dll: + * diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1013-Updated-changelog.patch freerdp2-2.6.1+dfsg1/debian/patches/1013-Updated-changelog.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1013-Updated-changelog.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1013-Updated-changelog.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,21 @@ +From: Armin Novak +Date: Mon, 28 Mar 2022 11:34:24 +0200 +Subject: Updated changelog + +(cherry picked from commit 732e94628945c2c218968c80b3a7a041b0b8a6e9) +--- + ChangeLog | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ChangeLog b/ChangeLog +index 608c697..3e41b9f 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,6 +1,7 @@ + # 2022-XX-YY Version 2.X.Y + + Noteworthy changes: ++* Backported WINPR_ASSERT to ease future backports + + Fixed issues: + * Backported #6786: Use /network:auto by default diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1014-Use-GetComputerName-instead-of-gethostname.patch freerdp2-2.6.1+dfsg1/debian/patches/1014-Use-GetComputerName-instead-of-gethostname.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1014-Use-GetComputerName-instead-of-gethostname.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1014-Use-GetComputerName-instead-of-gethostname.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,52 @@ +From: Armin Novak +Date: Tue, 15 Mar 2022 15:19:41 +0100 +Subject: Use GetComputerName instead of gethostname + +(cherry picked from commit 82165d95a925a775f2f895518dba8ff6f1a732d1) +(cherry picked from commit c6bd48f9265da174863861a1289aba5ef7d8eb7e) +--- + channels/rdpdr/client/rdpdr_main.c | 6 +++++- + libfreerdp/core/settings.c | 6 ++++-- + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c +index 309d24c..681ebce 100644 +--- a/channels/rdpdr/client/rdpdr_main.c ++++ b/channels/rdpdr/client/rdpdr_main.c +@@ -31,6 +31,7 @@ + #include + + #include ++#include + #include + + #include +@@ -1114,7 +1115,10 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) + size_t computerNameLenW; + + if (!rdpdr->computerName[0]) +- gethostname(rdpdr->computerName, sizeof(rdpdr->computerName) - 1); ++ { ++ DWORD size = sizeof(rdpdr->computerName) - 1; ++ GetComputerNameA(rdpdr->computerName, &size); ++ } + + computerNameLenW = ConvertToUnicode(CP_UTF8, 0, rdpdr->computerName, -1, &computerNameW, 0) * 2; + s = Stream_New(NULL, 16 + computerNameLenW + 2); +diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c +index d0c2b56..bd259d6 100644 +--- a/libfreerdp/core/settings.c ++++ b/libfreerdp/core/settings.c +@@ -405,8 +405,10 @@ rdpSettings* freerdp_settings_new(DWORD flags) + + if (!settings->ClientHostname) + goto out_fail; +- +- gethostname(settings->ClientHostname, 31); ++ DWORD size = 31; ++ GetComputerNameA(ClientHostname, &size); ++ if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, ClientHostname)) ++ goto out_fail; + settings->ClientHostname[31] = 0; + settings->ColorPointerFlag = TRUE; + settings->LargePointerFlag = (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384); diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1015-Refactored-WinPR-NTLM.patch freerdp2-2.6.1+dfsg1/debian/patches/1015-Refactored-WinPR-NTLM.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1015-Refactored-WinPR-NTLM.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1015-Refactored-WinPR-NTLM.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,3359 @@ +From: Armin Novak +Date: Mon, 14 Mar 2022 14:50:32 +0100 +Subject: Refactored WinPR::NTLM + +* added assertions +* added log messages +* removed code duplication + +(cherry picked from commit 813966da1a44acff1385de058dd89a8be93d2d1c) +(cherry picked from commit f1d9faa7fc30ae42f722047550c489690ff87049) +--- + winpr/libwinpr/sspi/NTLM/ntlm.c | 230 ++++-- + winpr/libwinpr/sspi/NTLM/ntlm.h | 18 +- + winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c | 65 +- + winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h | 4 +- + winpr/libwinpr/sspi/NTLM/ntlm_compute.c | 468 ++++++++----- + winpr/libwinpr/sspi/NTLM/ntlm_compute.h | 31 +- + winpr/libwinpr/sspi/NTLM/ntlm_message.c | 1114 +++++++++++++++++++----------- + winpr/libwinpr/sspi/NTLM/ntlm_message.h | 8 +- + winpr/libwinpr/sspi/test/TestNTLM.c | 19 +- + 9 files changed, 1252 insertions(+), 705 deletions(-) + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c +index 9560371..c0af65b 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm.c +@@ -49,6 +49,8 @@ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) + DWORD nSize = 0; + CHAR* computerName; + ++ WINPR_ASSERT(context); ++ + if (!Workstation) + { + if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || +@@ -91,6 +93,8 @@ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) + + static int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName) + { ++ WINPR_ASSERT(context); ++ + if (!ServicePrincipalName) + { + context->ServicePrincipalName.Buffer = NULL; +@@ -116,6 +120,8 @@ static int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName) + DWORD nSize = 0; + CHAR* computerName = NULL; + ++ WINPR_ASSERT(context); ++ + if (!name) + { + if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || +@@ -254,7 +260,7 @@ static NTLM_CONTEXT* ntlm_ContextNew(void) + + context->NegotiateFlags = 0; + context->LmCompatibilityLevel = 3; +- context->state = NTLM_STATE_INITIAL; ++ ntlm_change_state(context, NTLM_STATE_INITIAL); + FillMemory(context->MachineID, sizeof(context->MachineID), 0xAA); + + if (context->NTLMv2) +@@ -414,79 +420,87 @@ ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSec + sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME); + } + +- if (context->state == NTLM_STATE_INITIAL) ++ switch (ntlm_get_state(context)) + { +- context->state = NTLM_STATE_NEGOTIATE; +- +- if (!pInput) +- return SEC_E_INVALID_TOKEN; +- +- if (pInput->cBuffers < 1) +- return SEC_E_INVALID_TOKEN; +- +- input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); ++ case NTLM_STATE_INITIAL: ++ { ++ ntlm_change_state(context, NTLM_STATE_NEGOTIATE); + +- if (!input_buffer) +- return SEC_E_INVALID_TOKEN; ++ if (!pInput) ++ return SEC_E_INVALID_TOKEN; + +- if (input_buffer->cbBuffer < 1) +- return SEC_E_INVALID_TOKEN; ++ if (pInput->cBuffers < 1) ++ return SEC_E_INVALID_TOKEN; + +- status = ntlm_read_NegotiateMessage(context, input_buffer); ++ input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); + +- if (context->state == NTLM_STATE_CHALLENGE) +- { +- if (!pOutput) ++ if (!input_buffer) + return SEC_E_INVALID_TOKEN; + +- if (pOutput->cBuffers < 1) ++ if (input_buffer->cbBuffer < 1) + return SEC_E_INVALID_TOKEN; + +- output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN); ++ status = ntlm_read_NegotiateMessage(context, input_buffer); ++ if (status != SEC_I_CONTINUE_NEEDED) ++ return status; + +- if (!output_buffer->BufferType) +- return SEC_E_INVALID_TOKEN; ++ if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE) ++ { ++ if (!pOutput) ++ return SEC_E_INVALID_TOKEN; + +- if (output_buffer->cbBuffer < 1) +- return SEC_E_INSUFFICIENT_MEMORY; ++ if (pOutput->cBuffers < 1) ++ return SEC_E_INVALID_TOKEN; + +- return ntlm_write_ChallengeMessage(context, output_buffer); +- } ++ output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN); + +- return SEC_E_OUT_OF_SEQUENCE; +- } +- else if (context->state == NTLM_STATE_AUTHENTICATE) +- { +- if (!pInput) +- return SEC_E_INVALID_TOKEN; ++ if (!output_buffer->BufferType) ++ return SEC_E_INVALID_TOKEN; + +- if (pInput->cBuffers < 1) +- return SEC_E_INVALID_TOKEN; ++ if (output_buffer->cbBuffer < 1) ++ return SEC_E_INSUFFICIENT_MEMORY; + +- input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); ++ return ntlm_write_ChallengeMessage(context, output_buffer); ++ } + +- if (!input_buffer) +- return SEC_E_INVALID_TOKEN; ++ return SEC_E_OUT_OF_SEQUENCE; ++ } ++ break; ++ case NTLM_STATE_AUTHENTICATE: ++ { ++ if (!pInput) ++ return SEC_E_INVALID_TOKEN; + +- if (input_buffer->cbBuffer < 1) +- return SEC_E_INVALID_TOKEN; ++ if (pInput->cBuffers < 1) ++ return SEC_E_INVALID_TOKEN; + +- status = ntlm_read_AuthenticateMessage(context, input_buffer); ++ input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); + +- if (pOutput) +- { +- ULONG i; ++ if (!input_buffer) ++ return SEC_E_INVALID_TOKEN; ++ ++ if (input_buffer->cbBuffer < 1) ++ return SEC_E_INVALID_TOKEN; + +- for (i = 0; i < pOutput->cBuffers; i++) ++ status = ntlm_read_AuthenticateMessage(context, input_buffer); ++ ++ if (pOutput) + { +- pOutput->pBuffers[i].cbBuffer = 0; +- pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN; ++ ULONG i; ++ ++ for (i = 0; i < pOutput->cBuffers; i++) ++ { ++ pOutput->pBuffers[i].cbBuffer = 0; ++ pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN; ++ } + } +- } + +- return status; ++ return status; ++ } ++ break; ++ default: ++ break; + } +- + return SEC_E_OUT_OF_SEQUENCE; + } + +@@ -540,7 +554,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( + sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME); + } + +- if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE)) ++ if ((!pInput) || (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE)) + { + if (!pOutput) + return SEC_E_INVALID_TOKEN; +@@ -556,10 +570,10 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( + if (output_buffer->cbBuffer < 1) + return SEC_E_INVALID_TOKEN; + +- if (context->state == NTLM_STATE_INITIAL) +- context->state = NTLM_STATE_NEGOTIATE; ++ if (ntlm_get_state(context) == NTLM_STATE_INITIAL) ++ ntlm_change_state(context, NTLM_STATE_NEGOTIATE); + +- if (context->state == NTLM_STATE_NEGOTIATE) ++ if (ntlm_get_state(context) == NTLM_STATE_NEGOTIATE) + return ntlm_write_NegotiateMessage(context, output_buffer); + + return SEC_E_OUT_OF_SEQUENCE; +@@ -585,7 +599,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( + context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*)channel_bindings->pvBuffer; + } + +- if (context->state == NTLM_STATE_CHALLENGE) ++ if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE) + { + status = ntlm_read_ChallengeMessage(context, input_buffer); + +@@ -603,7 +617,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( + if (output_buffer->cbBuffer < 1) + return SEC_E_INSUFFICIENT_MEMORY; + +- if (context->state == NTLM_STATE_AUTHENTICATE) ++ if (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE) + return ntlm_write_AuthenticateMessage(context, output_buffer); + } + +@@ -672,7 +686,12 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContex + SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof) + { + BYTE* blob; +- SecBuffer* target = &ntlm->ChallengeTargetInfo; ++ SecBuffer* target; ++ ++ WINPR_ASSERT(ntlm); ++ WINPR_ASSERT(ntproof); ++ ++ target = &ntlm->ChallengeTargetInfo; + + if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer)) + return SEC_E_INSUFFICIENT_MEMORY; +@@ -693,8 +712,13 @@ SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof) + SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue) + { + BYTE* blob; +- ULONG msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer + +- ntlm->AuthenticateMessage.cbBuffer; ++ ULONG msgSize; ++ ++ WINPR_ASSERT(ntlm); ++ WINPR_ASSERT(micvalue); ++ ++ msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer + ++ ntlm->AuthenticateMessage.cbBuffer; + + if (!sspi_SecBufferAlloc(micvalue, msgSize)) + return SEC_E_INSUFFICIENT_MEMORY; +@@ -969,8 +993,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULON + void* data; + UINT32 SeqNo; + UINT32 value; +- BYTE digest[WINPR_MD5_DIGEST_LENGTH]; +- BYTE checksum[8]; ++ BYTE digest[WINPR_MD5_DIGEST_LENGTH] = { 0 }; ++ BYTE checksum[8] = { 0 }; + BYTE* signature; + ULONG version = 1; + WINPR_HMAC_CTX* hmac; +@@ -1066,12 +1090,12 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSec + void* data; + UINT32 SeqNo; + UINT32 value; +- BYTE digest[WINPR_MD5_DIGEST_LENGTH]; +- BYTE checksum[8]; ++ BYTE digest[WINPR_MD5_DIGEST_LENGTH] = { 0 }; ++ BYTE checksum[8] = { 0 }; + UINT32 version = 1; + WINPR_HMAC_CTX* hmac; + NTLM_CONTEXT* context; +- BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH]; ++ BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH] = { 0 }; + PSecBuffer data_buffer = NULL; + PSecBuffer signature_buffer = NULL; + SeqNo = (UINT32)MessageSeqNo; +@@ -1258,3 +1282,81 @@ const SecPkgInfoW NTLM_SecPkgInfoW = { + NTLM_SecPkgInfoW_Name, /* Name */ + NTLM_SecPkgInfoW_Comment /* Comment */ + }; ++ ++char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags) ++{ ++ int x; ++ if (!buffer || (size == 0)) ++ return buffer; ++ ++ for (x = 0; x < 31; x++) ++ { ++ size_t len = strnlen(buffer, size); ++ if (flags & x) ++ { ++ const char* str = ntlm_get_negotiate_string(1 << x); ++ size_t flen = strlen(str); ++ if (len > 0) ++ { ++ if (size - len < 1) ++ break; ++ strcat(buffer, "|"); ++ len++; ++ } ++ ++ if (size - len < flen) ++ break; ++ strcat(buffer, str); ++ } ++ } ++ return buffer; ++} ++ ++const char* ntlm_message_type_string(UINT32 messageType) ++{ ++ switch (messageType) ++ { ++ case MESSAGE_TYPE_NEGOTIATE: ++ return "MESSAGE_TYPE_NEGOTIATE"; ++ case MESSAGE_TYPE_CHALLENGE: ++ return "MESSAGE_TYPE_CHALLENGE"; ++ case MESSAGE_TYPE_AUTHENTICATE: ++ return "MESSAGE_TYPE_AUTHENTICATE"; ++ default: ++ return "MESSAGE_TYPE_UNKNOWN"; ++ } ++} ++ ++const char* ntlm_state_string(NTLM_STATE state) ++{ ++ switch (state) ++ { ++ case NTLM_STATE_INITIAL: ++ return "NTLM_STATE_INITIAL"; ++ case NTLM_STATE_NEGOTIATE: ++ return "NTLM_STATE_NEGOTIATE"; ++ case NTLM_STATE_CHALLENGE: ++ return "NTLM_STATE_CHALLENGE"; ++ case NTLM_STATE_AUTHENTICATE: ++ return "NTLM_STATE_AUTHENTICATE"; ++ case NTLM_STATE_COMPLETION: ++ return "NTLM_STATE_COMPLETION"; ++ case NTLM_STATE_FINAL: ++ return "NTLM_STATE_FINAL"; ++ default: ++ return "NTLM_STATE_UNKNOWN"; ++ } ++} ++void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state) ++{ ++ WINPR_ASSERT(ntlm); ++ WLog_DBG(TAG, "change state from %s to %s", ntlm_state_string(ntlm->state), ++ ntlm_state_string(state)); ++ ntlm->state = state; ++} ++ ++NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm) ++{ ++ WINPR_ASSERT(ntlm); ++ return ntlm->state; ++} +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.h b/winpr/libwinpr/sspi/NTLM/ntlm.h +index c6216ea..d4db9eb 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm.h ++++ b/winpr/libwinpr/sspi/NTLM/ntlm.h +@@ -176,8 +176,7 @@ typedef struct _NTLM_MESSAGE_HEADER NTLM_MESSAGE_HEADER; + + struct _NTLM_NEGOTIATE_MESSAGE + { +- BYTE Signature[8]; +- UINT32 MessageType; ++ NTLM_MESSAGE_HEADER header; + UINT32 NegotiateFlags; + NTLM_VERSION_INFO Version; + NTLM_MESSAGE_FIELDS DomainName; +@@ -187,8 +186,7 @@ typedef struct _NTLM_NEGOTIATE_MESSAGE NTLM_NEGOTIATE_MESSAGE; + + struct _NTLM_CHALLENGE_MESSAGE + { +- BYTE Signature[8]; +- UINT32 MessageType; ++ NTLM_MESSAGE_HEADER header; + UINT32 NegotiateFlags; + BYTE ServerChallenge[8]; + BYTE Reserved[8]; +@@ -200,8 +198,7 @@ typedef struct _NTLM_CHALLENGE_MESSAGE NTLM_CHALLENGE_MESSAGE; + + struct _NTLM_AUTHENTICATE_MESSAGE + { +- BYTE Signature[8]; +- UINT32 MessageType; ++ NTLM_MESSAGE_HEADER header; + UINT32 NegotiateFlags; + NTLM_VERSION_INFO Version; + NTLM_MESSAGE_FIELDS DomainName; +@@ -251,7 +248,7 @@ struct _NTLM_CONTEXT + NTLM_NEGOTIATE_MESSAGE NEGOTIATE_MESSAGE; + NTLM_CHALLENGE_MESSAGE CHALLENGE_MESSAGE; + NTLM_AUTHENTICATE_MESSAGE AUTHENTICATE_MESSAGE; +- UINT32 MessageIntegrityCheckOffset; ++ size_t MessageIntegrityCheckOffset; + SecBuffer NegotiateMessage; + SecBuffer ChallengeMessage; + SecBuffer AuthenticateMessage; +@@ -280,6 +277,13 @@ struct _NTLM_CONTEXT + }; + typedef struct _NTLM_CONTEXT NTLM_CONTEXT; + ++char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags); ++const char* ntlm_message_type_string(UINT32 messageType); ++ ++const char* ntlm_state_string(NTLM_STATE state); ++void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state); ++NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm); ++ + SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof); + SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue); + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c +index 47669bb..9b2efd3 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c +@@ -21,12 +21,13 @@ + #include "config.h" + #endif + +-#include ++#include + + #include "ntlm.h" + #include "../sspi.h" + + #include ++#include + #include + #include + #include +@@ -75,8 +76,8 @@ static const char* get_av_pair_string(UINT16 pair) + return "MsvAvSingleHost"; + case MsvAvTargetName: + return "MsvAvTargetName"; +- case MsvChannelBindings: +- return "MsvChannelBindings"; ++ case MsvAvChannelBindings: ++ return "MsvAvChannelBindings"; + default: + return "UNKNOWN"; + } +@@ -87,11 +88,13 @@ static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvP + + static INLINE void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id) + { ++ WINPR_ASSERT(pAvPair); + Data_Write_UINT16(&pAvPair->AvId, id); + } + + static INLINE void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len) + { ++ WINPR_ASSERT(pAvPair); + Data_Write_UINT16(&pAvPair->AvLen, len); + } + +@@ -124,6 +127,7 @@ static INLINE BOOL ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair, size_t size, + + ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) + { ++ size_t size; + size_t cbAvPair; + NTLM_AV_PAIR* pAvPair; + +@@ -131,7 +135,9 @@ ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) + if (!pAvPair) + return 0; + +- return ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR); ++ size = ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR); ++ WINPR_ASSERT(size <= ULONG_MAX); ++ return (ULONG)size; + } + + static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pAvLen) +@@ -149,6 +155,7 @@ static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size + return TRUE; + } + ++#ifdef WITH_DEBUG_NTLM + void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) + { + UINT16 pair; +@@ -158,19 +165,20 @@ void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) + if (!ntlm_av_pair_check(pAvPair, cbAvPair)) + return; + +- WLog_INFO(TAG, "AV_PAIRs ="); ++ WLog_VRB(TAG, "AV_PAIRs ="); + + while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL)) + { + size_t cbLen = 0; + ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen); + +- WLog_INFO(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair); +- winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair), cbLen); ++ WLog_VRB(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair); ++ winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen); + + pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair); + } + } ++#endif + + static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength) + { +@@ -180,6 +188,7 @@ static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength + + PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair) + { ++ WINPR_ASSERT(pAvPair); + return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR); + } + +@@ -259,11 +268,11 @@ static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTL + if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen) + return FALSE; + +- ntlm_av_pair_set_id(pAvPair, AvId); ++ ntlm_av_pair_set_id(pAvPair, (UINT16)AvId); + ntlm_av_pair_set_len(pAvPair, AvLen); + if (AvLen) + { +- assert(Value != NULL); ++ WINPR_ASSERT(Value != NULL); + CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen); + } + +@@ -286,8 +295,9 @@ static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList + if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen)) + return FALSE; + ++ WINPR_ASSERT(avLen <= UINT16_MAX); + return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair, +- ntlm_av_pair_get_value_pointer(pAvPair), avLen); ++ ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen); + } + + static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type) +@@ -297,6 +307,8 @@ static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FO + DWORD nSize = 0; + CHAR* computerName; + ++ WINPR_ASSERT(pName); ++ + if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || GetLastError() != ERROR_MORE_DATA) + return -1; + +@@ -394,6 +406,9 @@ static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) + BYTE* ChannelBindingToken; + UINT32 ChannelBindingTokenLength; + SEC_CHANNEL_BINDINGS* ChannelBindings; ++ ++ WINPR_ASSERT(context); ++ + ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH); + ChannelBindings = context->Bindings.Bindings; + +@@ -436,6 +451,7 @@ out: + + static void ntlm_compute_single_host_data(NTLM_CONTEXT* context) + { ++ WINPR_ASSERT(context); + /** + * The Single_Host_Data structure allows a client to send machine-specific information + * within an authentication exchange to services on the same machine. The client can +@@ -451,10 +467,10 @@ static void ntlm_compute_single_host_data(NTLM_CONTEXT* context) + FillMemory(context->SingleHostData.MachineID, 32, 0xAA); + } + +-int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) ++BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) + { +- int rc = -1; +- int length; ++ BOOL rc = FALSE; ++ ULONG length; + ULONG AvPairsCount; + ULONG AvPairsLength; + NTLM_AV_PAIR* pAvPairList; +@@ -464,6 +480,8 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) + UNICODE_STRING DnsDomainName = { 0 }; + UNICODE_STRING DnsComputerName = { 0 }; + ++ WINPR_ASSERT(context); ++ + if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0) + goto fail; + +@@ -516,7 +534,7 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) + sizeof(context->Timestamp))) + goto fail; + +- rc = 1; ++ rc = TRUE; + fail: + ntlm_free_unicode_string(&NbDomainName); + ntlm_free_unicode_string(&NbComputerName); +@@ -525,7 +543,7 @@ fail: + return rc; + } + +-int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) ++BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) + { + ULONG size; + ULONG AvPairsCount; +@@ -546,6 +564,9 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) + size_t cbAvDnsTreeName; + size_t cbChallengeTargetInfo; + size_t cbAuthenticateTargetInfo; ++ ++ WINPR_ASSERT(context); ++ + AvPairsCount = 1; + AvPairsValueLength = 0; + ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer; +@@ -635,7 +656,7 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) + * SEC_CHANNEL_BINDINGS structure + * http://msdn.microsoft.com/en-us/library/windows/desktop/dd919963/ + */ +- AvPairsCount++; /* MsvChannelBindings */ ++ AvPairsCount++; /* MsvAvChannelBindings */ + AvPairsValueLength += 16; + ntlm_compute_channel_bindings(context); + +@@ -714,15 +735,17 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) + + if (context->SendSingleHostData) + { ++ WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX); + if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost, +- (PBYTE)&context->SingleHostData, context->SingleHostData.Size)) ++ (PBYTE)&context->SingleHostData, ++ (UINT16)context->SingleHostData.Size)) + goto fail; + } + + if (!context->SuppressExtendedProtection) + { +- if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvChannelBindings, +- context->ChannelBindingsHash, 16)) ++ if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, ++ MsvAvChannelBindings, context->ChannelBindingsHash, 16)) + goto fail; + + if (context->ServicePrincipalName.Length > 0) +@@ -745,8 +768,8 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) + ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR)); + } + +- return 1; ++ return TRUE; + fail: + sspi_SecBufferFree(&context->AuthenticateTargetInfo); +- return -1; ++ return FALSE; + } +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h +index ac228a8..82d2364 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h +@@ -30,7 +30,7 @@ PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair); + NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId, + size_t* pcbAvPairListRemaining); + +-int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context); +-int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context); ++BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context); ++BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context); + + #endif /* WINPR_SSPI_NTLM_AV_PAIRS_H */ +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +index dbd7f7f..5360a2c 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +@@ -21,7 +21,7 @@ + #include "config.h" + #endif + +-#include ++#include + + #include "ntlm.h" + #include "../sspi.h" +@@ -38,16 +38,10 @@ + #include "../../log.h" + #define TAG WINPR_TAG("sspi.NTLM") + +-const char LM_MAGIC[] = "KGS!@#$%"; +- +-static const char NTLM_CLIENT_SIGN_MAGIC[] = +- "session key to client-to-server signing key magic constant"; +-static const char NTLM_SERVER_SIGN_MAGIC[] = +- "session key to server-to-client signing key magic constant"; +-static const char NTLM_CLIENT_SEAL_MAGIC[] = +- "session key to client-to-server sealing key magic constant"; +-static const char NTLM_SERVER_SEAL_MAGIC[] = +- "session key to server-to-client sealing key magic constant"; ++static char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant"; ++static char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client signing key magic constant"; ++static char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant"; ++static char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant"; + + static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +@@ -58,16 +52,21 @@ static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 + * @param s + */ + +-void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) ++BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) + { +- OSVERSIONINFOA osVersionInfo; ++ OSVERSIONINFOA osVersionInfo = { 0 }; ++ ++ WINPR_ASSERT(versionInfo); ++ + osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); +- GetVersionExA(&osVersionInfo); ++ if (!GetVersionExA(&osVersionInfo)) ++ return FALSE; + versionInfo->ProductMajorVersion = (UINT8)osVersionInfo.dwMajorVersion; + versionInfo->ProductMinorVersion = (UINT8)osVersionInfo.dwMinorVersion; + versionInfo->ProductBuild = (UINT16)osVersionInfo.dwBuildNumber; + ZeroMemory(versionInfo->Reserved, sizeof(versionInfo->Reserved)); + versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; ++ return TRUE; + } + + /** +@@ -76,17 +75,24 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) + * @param s + */ + +-int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) ++BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(versionInfo); ++ + if (Stream_GetRemainingLength(s) < 8) +- return -1; ++ { ++ WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz, ++ Stream_GetRemainingLength(s), 8); ++ return FALSE; ++ } + + Stream_Read_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */ + Stream_Read_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */ + Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */ + Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */ + Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */ +- return 1; ++ return TRUE; + } + + /** +@@ -95,13 +101,24 @@ int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) + * @param s + */ + +-void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) ++BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(versionInfo); ++ ++ if (Stream_GetRemainingCapacity(s) < 5 + sizeof(versionInfo->Reserved)) ++ { ++ WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz, ++ Stream_GetRemainingCapacity(s), 5 + sizeof(versionInfo->Reserved)); ++ return FALSE; ++ } ++ + Stream_Write_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */ + Stream_Write_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */ + Stream_Write_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */ + Stream_Write(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */ + Stream_Write_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */ ++ return TRUE; + } + + /** +@@ -109,23 +126,33 @@ void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) + * VERSION @msdn{cc236654} + * @param s + */ +- +-void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo) ++#ifdef WITH_DEBUG_NTLM ++void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo) + { +- WLog_INFO(TAG, "VERSION ={"); +- WLog_INFO(TAG, "\tProductMajorVersion: %" PRIu8 "", versionInfo->ProductMajorVersion); +- WLog_INFO(TAG, "\tProductMinorVersion: %" PRIu8 "", versionInfo->ProductMinorVersion); +- WLog_INFO(TAG, "\tProductBuild: %" PRIu16 "", versionInfo->ProductBuild); +- WLog_INFO(TAG, "\tReserved: 0x%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "", versionInfo->Reserved[0], +- versionInfo->Reserved[1], versionInfo->Reserved[2]); +- WLog_INFO(TAG, "\tNTLMRevisionCurrent: 0x%02" PRIX8 "", versionInfo->NTLMRevisionCurrent); ++ WINPR_ASSERT(versionInfo); ++ ++ WLog_VRB(TAG, "VERSION ={"); ++ WLog_VRB(TAG, "\tProductMajorVersion: %" PRIu8 "", versionInfo->ProductMajorVersion); ++ WLog_VRB(TAG, "\tProductMinorVersion: %" PRIu8 "", versionInfo->ProductMinorVersion); ++ WLog_VRB(TAG, "\tProductBuild: %" PRIu16 "", versionInfo->ProductBuild); ++ WLog_VRB(TAG, "\tReserved: 0x%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "", versionInfo->Reserved[0], ++ versionInfo->Reserved[1], versionInfo->Reserved[2]); ++ WLog_VRB(TAG, "\tNTLMRevisionCurrent: 0x%02" PRIX8 "", versionInfo->NTLMRevisionCurrent); + } ++#endif + +-static int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge) ++static BOOL ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge) + { + size_t size; ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(challenge); ++ + if (Stream_GetRemainingLength(s) < 28) +- return -1; ++ { ++ WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE expected 28bytes, got %" PRIuz "bytes", ++ Stream_GetRemainingLength(s)); ++ return FALSE; ++ } + + Stream_Read_UINT8(s, challenge->RespType); + Stream_Read_UINT8(s, challenge->HiRespType); +@@ -137,21 +164,39 @@ static int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENG + size = Stream_Length(s) - Stream_GetPosition(s); + + if (size > UINT32_MAX) +- return -1; ++ { ++ WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::cbAvPairs too large, got %" PRIuz "bytes", size); ++ return FALSE; ++ } + +- challenge->cbAvPairs = size; ++ challenge->cbAvPairs = (UINT32)size; + challenge->AvPairs = (NTLM_AV_PAIR*)malloc(challenge->cbAvPairs); + + if (!challenge->AvPairs) +- return -1; ++ { ++ WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::AvPairs failed to allocate %" PRIu32 "bytes", ++ challenge->cbAvPairs); ++ return FALSE; ++ } + + Stream_Read(s, challenge->AvPairs, size); +- return 1; ++ return TRUE; + } + +-static int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge) ++static BOOL ntlm_write_ntlm_v2_client_challenge(wStream* s, ++ const NTLMv2_CLIENT_CHALLENGE* challenge) + { + ULONG length; ++ ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(challenge); ++ ++ if (Stream_GetRemainingCapacity(s) < 28) ++ { ++ WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE expected 28bytes, have %" PRIuz "bytes", ++ Stream_GetRemainingCapacity(s)); ++ return FALSE; ++ } + Stream_Write_UINT8(s, challenge->RespType); + Stream_Write_UINT8(s, challenge->HiRespType); + Stream_Write_UINT16(s, challenge->Reserved1); +@@ -160,20 +205,44 @@ static int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLEN + Stream_Write(s, challenge->ClientChallenge, 8); + Stream_Write_UINT32(s, challenge->Reserved3); + length = ntlm_av_pair_list_length(challenge->AvPairs, challenge->cbAvPairs); ++ if (Stream_GetRemainingCapacity(s) < length) ++ { ++ WLog_ERR(TAG, ++ "NTLMv2_CLIENT_CHALLENGE::AvPairs expected %" PRIu32 "bytes, have %" PRIuz "bytes", ++ length, Stream_GetRemainingCapacity(s)); ++ return FALSE; ++ } + Stream_Write(s, challenge->AvPairs, length); +- return 1; ++ return TRUE; + } + +-int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response) ++BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(response); ++ + if (Stream_GetRemainingLength(s) < 16) +- return -1; ++ { ++ WLog_ERR(TAG, "NTLMv2_RESPONSE expected 16bytes, have %" PRIuz "bytes", ++ Stream_GetRemainingLength(s)); ++ ++ return FALSE; ++ } + Stream_Read(s, response->Response, 16); + return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge)); + } + +-int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response) ++BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(response); ++ ++ if (Stream_GetRemainingCapacity(s) < 16) ++ { ++ WLog_ERR(TAG, "NTLMv2_RESPONSE expected 16bytes, have %" PRIuz "bytes", ++ Stream_GetRemainingCapacity(s)); ++ return FALSE; ++ } + Stream_Write(s, response->Response, 16); + return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge)); + } +@@ -185,8 +254,11 @@ int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response) + + void ntlm_current_time(BYTE* timestamp) + { +- FILETIME filetime; +- ULARGE_INTEGER time64; ++ FILETIME filetime = { 0 }; ++ ULARGE_INTEGER time64 = { 0 }; ++ ++ WINPR_ASSERT(timestamp); ++ + GetSystemTimeAsFileTime(&filetime); + time64.u.LowPart = filetime.dwLowDateTime; + time64.u.HighPart = filetime.dwHighDateTime; +@@ -200,6 +272,8 @@ void ntlm_current_time(BYTE* timestamp) + + void ntlm_generate_timestamp(NTLM_CONTEXT* context) + { ++ WINPR_ASSERT(context); ++ + if (memcmp(context->ChallengeTimestamp, NTLM_NULL_BUFFER, 8) != 0) + CopyMemory(context->Timestamp, context->ChallengeTimestamp, 8); + else +@@ -210,7 +284,12 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) + { + WINPR_SAM* sam; + WINPR_SAM_ENTRY* entry; +- SSPI_CREDENTIALS* credentials = context->credentials; ++ SSPI_CREDENTIALS* credentials; ++ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(hash); ++ ++ credentials = context->credentials; + sam = SamOpen(context->SamFile, TRUE); + + if (!sam) +@@ -223,7 +302,7 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) + if (entry) + { + #ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "NTLM Hash:"); ++ WLog_VRB(TAG, "NTLM Hash:"); + winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16); + #endif + NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User, +@@ -240,7 +319,7 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) + if (entry) + { + #ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "NTLM Hash:"); ++ WLog_VRB(TAG, "NTLM Hash:"); + winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16); + #endif + NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User, +@@ -256,71 +335,82 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) + WLog_ERR(TAG, "Error: Could not find user in SAM database"); + return 0; + } +- +- SamClose(sam); +- return 1; + } + + static int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash) + { + int status; +- int i, hn, ln; ++ int i; + char* PasswordHash = NULL; +- UINT32 PasswordHashLength = 0; +- SSPI_CREDENTIALS* credentials = context->credentials; ++ INT64 PasswordHashLength = 0; ++ SSPI_CREDENTIALS* credentials; ++ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(hash); ++ ++ credentials = context->credentials; + /* Password contains a password hash of length (PasswordLength - + * SSPI_CREDENTIALS_HASH_LENGTH_OFFSET) */ + PasswordHashLength = credentials->identity.PasswordLength - SSPI_CREDENTIALS_HASH_LENGTH_OFFSET; ++ WINPR_ASSERT(PasswordHashLength >= 0); ++ WINPR_ASSERT(PasswordHashLength <= INT_MAX); + status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR)credentials->identity.Password, +- PasswordHashLength, &PasswordHash, 0, NULL, NULL); ++ (int)PasswordHashLength, &PasswordHash, 0, NULL, NULL); + + if (status <= 0) + return -1; + +- CharUpperBuffA(PasswordHash, PasswordHashLength); ++ CharUpperBuffA(PasswordHash, (DWORD)PasswordHashLength); + + for (i = 0; i < 32; i += 2) + { +- hn = PasswordHash[i] > '9' ? PasswordHash[i] - 'A' + 10 : PasswordHash[i] - '0'; +- ln = PasswordHash[i + 1] > '9' ? PasswordHash[i + 1] - 'A' + 10 : PasswordHash[i + 1] - '0'; +- hash[i / 2] = (hn << 4) | ln; ++ BYTE hn = ++ (BYTE)(PasswordHash[i] > '9' ? PasswordHash[i] - 'A' + 10 : PasswordHash[i] - '0'); ++ BYTE ln = (BYTE)(PasswordHash[i + 1] > '9' ? PasswordHash[i + 1] - 'A' + 10 ++ : PasswordHash[i + 1] - '0'); ++ hash[i / 2] = (BYTE)((hn << 4) | ln); + } + + free(PasswordHash); + return 1; + } + +-static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) ++static BOOL ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) + { +- SSPI_CREDENTIALS* credentials = context->credentials; ++ SSPI_CREDENTIALS* credentials; ++ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(hash); ++ ++ credentials = context->credentials; + #ifdef WITH_DEBUG_NTLM + + if (credentials) + { +- WLog_DBG(TAG, "Password (length = %" PRIu32 ")", credentials->identity.PasswordLength * 2); +- winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.Password, ++ WLog_VRB(TAG, "Password (length = %" PRIu32 ")", credentials->identity.PasswordLength * 2); ++ winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Password, + credentials->identity.PasswordLength * 2); +- WLog_DBG(TAG, "Username (length = %" PRIu32 ")", credentials->identity.UserLength * 2); +- winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.User, ++ WLog_VRB(TAG, "Username (length = %" PRIu32 ")", credentials->identity.UserLength * 2); ++ winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.User, + credentials->identity.UserLength * 2); +- WLog_DBG(TAG, "Domain (length = %" PRIu32 ")", credentials->identity.DomainLength * 2); +- winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.Domain, ++ WLog_VRB(TAG, "Domain (length = %" PRIu32 ")", credentials->identity.DomainLength * 2); ++ winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Domain, + credentials->identity.DomainLength * 2); + } + else +- WLog_DBG(TAG, "Strange, NTLM_CONTEXT is missing valid credentials..."); ++ WLog_VRB(TAG, "Strange, NTLM_CONTEXT is missing valid credentials..."); + +- WLog_DBG(TAG, "Workstation (length = %" PRIu16 ")", context->Workstation.Length); +- winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)context->Workstation.Buffer, context->Workstation.Length); +- WLog_DBG(TAG, "NTOWFv2, NTLMv2 Hash"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH); ++ WLog_VRB(TAG, "Workstation (length = %" PRIu16 ")", context->Workstation.Length); ++ winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)context->Workstation.Buffer, context->Workstation.Length); ++ WLog_VRB(TAG, "NTOWFv2, NTLMv2 Hash"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH); + #endif + + if (memcmp(context->NtlmV2Hash, NTLM_NULL_BUFFER, 16) != 0) +- return 1; ++ return TRUE; + + if (!credentials) +- return -1; ++ return FALSE; + else if (memcmp(context->NtlmHash, NTLM_NULL_BUFFER, 16) != 0) + { + NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User, +@@ -331,7 +421,7 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) + { + /* Special case for WinPR: password hash */ + if (ntlm_convert_password_hash(context, context->NtlmHash) < 0) +- return -1; ++ return FALSE; + + NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User, + credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain, +@@ -350,55 +440,57 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) + SecBuffer proofValue, micValue; + + if (ntlm_computeProofValue(context, &proofValue) != SEC_E_OK) +- return -1; ++ return FALSE; + + if (ntlm_computeMicValue(context, &micValue) != SEC_E_OK) + { + sspi_SecBufferFree(&proofValue); +- return -1; ++ return FALSE; + } + + ret = context->HashCallback(context->HashCallbackArg, &credentials->identity, &proofValue, + context->EncryptedRandomSessionKey, +- (&context->AUTHENTICATE_MESSAGE)->MessageIntegrityCheck, +- &micValue, hash); ++ context->AUTHENTICATE_MESSAGE.MessageIntegrityCheck, &micValue, ++ hash); + sspi_SecBufferFree(&proofValue); + sspi_SecBufferFree(&micValue); +- return ret ? 1 : -1; ++ return ret ? TRUE : FALSE; + } + else if (context->UseSamFileDatabase) + { + return ntlm_fetch_ntlm_v2_hash(context, hash); + } + +- return 1; ++ return TRUE; + } + +-int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) ++BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) + { + BYTE* response; +- BYTE value[WINPR_MD5_DIGEST_LENGTH]; ++ BYTE value[WINPR_MD5_DIGEST_LENGTH] = { 0 }; ++ ++ WINPR_ASSERT(context); + + if (context->LmCompatibilityLevel < 2) + { + if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24)) +- return -1; ++ return FALSE; + + ZeroMemory(context->LmChallengeResponse.pvBuffer, 24); +- return 1; ++ return TRUE; + } + + /* Compute the NTLMv2 hash */ + +- if (ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash) < 0) +- return -1; ++ if (!ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash)) ++ return FALSE; + + /* Concatenate the server and client challenges */ + CopyMemory(value, context->ServerChallenge, 8); + CopyMemory(&value[8], context->ClientChallenge, 8); + + if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24)) +- return -1; ++ return FALSE; + + response = (BYTE*)context->LmChallengeResponse.pvBuffer; + /* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */ +@@ -407,7 +499,7 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) + /* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response + * (24 bytes) */ + CopyMemory(&response[16], context->ClientChallenge, 8); +- return 1; ++ return TRUE; + } + + /** +@@ -417,13 +509,17 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) + * @param NTLM context + */ + +-int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) ++BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) + { + BYTE* blob; + SecBuffer ntlm_v2_temp = { 0 }; + SecBuffer ntlm_v2_temp_chal = { 0 }; +- PSecBuffer TargetInfo = &context->ChallengeTargetInfo; +- int ret = -1; ++ PSecBuffer TargetInfo; ++ ++ WINPR_ASSERT(context); ++ ++ TargetInfo = &context->ChallengeTargetInfo; ++ BOOL ret = FALSE; + + if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28)) + goto exit; +@@ -432,7 +528,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) + blob = (BYTE*)ntlm_v2_temp.pvBuffer; + + /* Compute the NTLMv2 hash */ +- if (ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash) < 0) ++ if (!ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash)) + goto exit; + + /* Construct temp */ +@@ -445,8 +541,8 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) + /* Reserved3 (4 bytes) */ + CopyMemory(&blob[28], TargetInfo->pvBuffer, TargetInfo->cbBuffer); + #ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "NTLMv2 Response Temp Blob"); +- winpr_HexDump(TAG, WLOG_DEBUG, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); ++ WLog_VRB(TAG, "NTLMv2 Response Temp Blob"); ++ winpr_HexDump(TAG, WLOG_TRACE, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); + #endif + + /* Concatenate server challenge with temp */ +@@ -473,7 +569,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) + winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH, + context->NtProofString, WINPR_MD5_DIGEST_LENGTH, context->SessionBaseKey, + WINPR_MD5_DIGEST_LENGTH); +- ret = 1; ++ ret = TRUE; + exit: + sspi_SecBufferFree(&ntlm_v2_temp); + sspi_SecBufferFree(&ntlm_v2_temp_chal); +@@ -488,7 +584,7 @@ exit: + * @param ciphertext cipher text + */ + +-void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext) ++void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext) + { + WINPR_RC4_CTX* rc4 = winpr_RC4_New(key, 16); + +@@ -506,9 +602,11 @@ void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext) + + void ntlm_generate_client_challenge(NTLM_CONTEXT* context) + { ++ WINPR_ASSERT(context); ++ + /* ClientChallenge is used in computation of LMv2 and NTLMv2 responses */ +- if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, 8) == 0) +- winpr_RAND(context->ClientChallenge, 8); ++ if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, sizeof(context->ClientChallenge)) == 0) ++ winpr_RAND(context->ClientChallenge, sizeof(context->ClientChallenge)); + } + + /** +@@ -518,8 +616,10 @@ void ntlm_generate_client_challenge(NTLM_CONTEXT* context) + + void ntlm_generate_server_challenge(NTLM_CONTEXT* context) + { +- if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, 8) == 0) +- winpr_RAND(context->ServerChallenge, 8); ++ WINPR_ASSERT(context); ++ ++ if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, sizeof(context->ServerChallenge)) == 0) ++ winpr_RAND(context->ServerChallenge, sizeof(context->ServerChallenge)); + } + + /** +@@ -530,8 +630,11 @@ void ntlm_generate_server_challenge(NTLM_CONTEXT* context) + + void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context) + { ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(sizeof(context->KeyExchangeKey) == sizeof(context->SessionBaseKey)); ++ + /* In NTLMv2, KeyExchangeKey is the 128-bit SessionBaseKey */ +- CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, 16); ++ CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, sizeof(context->KeyExchangeKey)); + } + + /** +@@ -541,7 +644,8 @@ void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context) + + void ntlm_generate_random_session_key(NTLM_CONTEXT* context) + { +- winpr_RAND(context->RandomSessionKey, 16); ++ WINPR_ASSERT(context); ++ winpr_RAND(context->RandomSessionKey, sizeof(context->RandomSessionKey)); + } + + /** +@@ -551,7 +655,11 @@ void ntlm_generate_random_session_key(NTLM_CONTEXT* context) + + void ntlm_generate_exported_session_key(NTLM_CONTEXT* context) + { +- CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, 16); ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(sizeof(context->ExportedSessionKey) == sizeof(context->RandomSessionKey)); ++ ++ CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, ++ sizeof(context->ExportedSessionKey)); + } + + /** +@@ -563,6 +671,7 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context) + { + /* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the + * KeyExchangeKey */ ++ WINPR_ASSERT(context); + ntlm_rc4k(context->KeyExchangeKey, 16, context->RandomSessionKey, + context->EncryptedRandomSessionKey); + } +@@ -574,6 +683,8 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context) + + void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context) + { ++ WINPR_ASSERT(context); ++ + /* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the + * KeyExchangeKey */ + +@@ -583,10 +694,18 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context) + * AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey) else Set RandomSessionKey to KeyExchangeKey + */ + if (context->NegotiateKeyExchange) +- ntlm_rc4k(context->KeyExchangeKey, 16, context->EncryptedRandomSessionKey, +- context->RandomSessionKey); ++ { ++ WINPR_ASSERT(sizeof(context->EncryptedRandomSessionKey) == ++ sizeof(context->RandomSessionKey)); ++ ntlm_rc4k(context->KeyExchangeKey, sizeof(context->EncryptedRandomSessionKey), ++ context->EncryptedRandomSessionKey, context->RandomSessionKey); ++ } + else +- CopyMemory(context->RandomSessionKey, context->KeyExchangeKey, 16); ++ { ++ WINPR_ASSERT(sizeof(context->RandomSessionKey) == sizeof(context->KeyExchangeKey)); ++ CopyMemory(context->RandomSessionKey, context->KeyExchangeKey, ++ sizeof(context->RandomSessionKey)); ++ } + } + + /** +@@ -597,29 +716,32 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context) + * @param signing_key Destination signing key + */ + +-static int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, +- BYTE* signing_key) ++static BOOL ntlm_generate_signing_key(BYTE* exported_session_key, const SecBuffer* sign_magic, ++ BYTE* signing_key) + { +- int length; +- BYTE* value; ++ BOOL rc = FALSE; ++ size_t length; ++ BYTE* value = NULL; ++ ++ WINPR_ASSERT(exported_session_key); ++ WINPR_ASSERT(sign_magic); ++ WINPR_ASSERT(signing_key); ++ + length = WINPR_MD5_DIGEST_LENGTH + sign_magic->cbBuffer; + value = (BYTE*)malloc(length); + + if (!value) +- return -1; ++ goto out; + + /* Concatenate ExportedSessionKey with sign magic */ + CopyMemory(value, exported_session_key, WINPR_MD5_DIGEST_LENGTH); + CopyMemory(&value[WINPR_MD5_DIGEST_LENGTH], sign_magic->pvBuffer, sign_magic->cbBuffer); + +- if (!winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH)) +- { +- free(value); +- return -1; +- } ++ rc = winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH); + ++out: + free(value); +- return 1; ++ return rc; + } + + /** +@@ -628,12 +750,13 @@ static int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign + * @param NTLM context + */ + +-void ntlm_generate_client_signing_key(NTLM_CONTEXT* context) ++BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context) + { +- SecBuffer signMagic; +- signMagic.pvBuffer = (void*)NTLM_CLIENT_SIGN_MAGIC; +- signMagic.cbBuffer = sizeof(NTLM_CLIENT_SIGN_MAGIC); +- ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ClientSigningKey); ++ const SecBuffer signMagic = { sizeof(NTLM_CLIENT_SIGN_MAGIC), 0, NTLM_CLIENT_SIGN_MAGIC }; ++ ++ WINPR_ASSERT(context); ++ return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, ++ context->ClientSigningKey); + } + + /** +@@ -642,45 +765,13 @@ void ntlm_generate_client_signing_key(NTLM_CONTEXT* context) + * @param NTLM context + */ + +-void ntlm_generate_server_signing_key(NTLM_CONTEXT* context) ++BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context) + { +- SecBuffer signMagic; +- signMagic.pvBuffer = (void*)NTLM_SERVER_SIGN_MAGIC; +- signMagic.cbBuffer = sizeof(NTLM_SERVER_SIGN_MAGIC); +- ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ServerSigningKey); +-} +- +-/** +- * Generate sealing key. +- * @msdn{cc236712} +- * @param exported_session_key ExportedSessionKey +- * @param seal_magic Seal magic string +- * @param sealing_key Destination sealing key +- */ ++ const SecBuffer signMagic = { sizeof(NTLM_SERVER_SIGN_MAGIC), 0, NTLM_SERVER_SIGN_MAGIC }; + +-static int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, +- BYTE* sealing_key) +-{ +- BYTE* p; +- SecBuffer buffer; +- +- if (!sspi_SecBufferAlloc(&buffer, WINPR_MD5_DIGEST_LENGTH + seal_magic->cbBuffer)) +- return -1; +- +- p = (BYTE*)buffer.pvBuffer; +- /* Concatenate ExportedSessionKey with seal magic */ +- CopyMemory(p, exported_session_key, WINPR_MD5_DIGEST_LENGTH); +- CopyMemory(&p[WINPR_MD5_DIGEST_LENGTH], seal_magic->pvBuffer, seal_magic->cbBuffer); +- +- if (!winpr_Digest(WINPR_MD_MD5, buffer.pvBuffer, buffer.cbBuffer, sealing_key, +- WINPR_MD5_DIGEST_LENGTH)) +- { +- sspi_SecBufferFree(&buffer); +- return -1; +- } +- +- sspi_SecBufferFree(&buffer); +- return 1; ++ WINPR_ASSERT(context); ++ return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, ++ context->ServerSigningKey); + } + + /** +@@ -689,12 +780,13 @@ static int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal + * @param NTLM context + */ + +-void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) ++BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) + { +- SecBuffer sealMagic; +- sealMagic.pvBuffer = (void*)NTLM_CLIENT_SEAL_MAGIC; +- sealMagic.cbBuffer = sizeof(NTLM_CLIENT_SEAL_MAGIC); +- ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ClientSealingKey); ++ const SecBuffer sealMagic = { sizeof(NTLM_CLIENT_SEAL_MAGIC), 0, NTLM_CLIENT_SEAL_MAGIC }; ++ ++ WINPR_ASSERT(context); ++ return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, ++ context->ClientSealingKey); + } + + /** +@@ -703,12 +795,13 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) + * @param NTLM context + */ + +-void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context) ++BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context) + { +- SecBuffer sealMagic; +- sealMagic.pvBuffer = (void*)NTLM_SERVER_SEAL_MAGIC; +- sealMagic.cbBuffer = sizeof(NTLM_SERVER_SEAL_MAGIC); +- ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ServerSealingKey); ++ const SecBuffer sealMagic = { sizeof(NTLM_SERVER_SEAL_MAGIC), 0, NTLM_SERVER_SEAL_MAGIC }; ++ ++ WINPR_ASSERT(context); ++ return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, ++ context->ServerSealingKey); + } + + /** +@@ -718,14 +811,17 @@ void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context) + + void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) + { ++ WINPR_ASSERT(context); + if (context->server) + { + context->SendSigningKey = context->ServerSigningKey; + context->RecvSigningKey = context->ClientSigningKey; + context->SendSealingKey = context->ClientSealingKey; + context->RecvSealingKey = context->ServerSealingKey; +- context->SendRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16); +- context->RecvRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16); ++ context->SendRc4Seal = ++ winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey)); ++ context->RecvRc4Seal = ++ winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey)); + } + else + { +@@ -733,22 +829,29 @@ void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) + context->RecvSigningKey = context->ServerSigningKey; + context->SendSealingKey = context->ServerSealingKey; + context->RecvSealingKey = context->ClientSealingKey; +- context->SendRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16); +- context->RecvRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16); ++ context->SendRc4Seal = ++ winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey)); ++ context->RecvRc4Seal = ++ winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey)); + } + } + +-void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size) ++BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size) + { ++ BOOL rc = FALSE; + /* + * Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE, + * CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey + */ + WINPR_HMAC_CTX* hmac = winpr_HMAC_New(); +- assert(size >= WINPR_MD5_DIGEST_LENGTH); + ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(mic); ++ WINPR_ASSERT(size >= WINPR_MD5_DIGEST_LENGTH); ++ ++ memset(mic, 0, size); + if (!hmac) +- return; ++ return FALSE; + + if (winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->ExportedSessionKey, WINPR_MD5_DIGEST_LENGTH)) + { +@@ -756,10 +859,27 @@ void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT + context->NegotiateMessage.cbBuffer); + winpr_HMAC_Update(hmac, (BYTE*)context->ChallengeMessage.pvBuffer, + context->ChallengeMessage.cbBuffer); +- winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer, +- context->AuthenticateMessage.cbBuffer); ++ ++ if (context->MessageIntegrityCheckOffset > 0) ++ { ++ const BYTE* auth = (BYTE*)context->AuthenticateMessage.pvBuffer; ++ const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 }; ++ const size_t rest = context->MessageIntegrityCheckOffset + sizeof(data); ++ ++ WINPR_ASSERT(rest <= context->AuthenticateMessage.cbBuffer); ++ winpr_HMAC_Update(hmac, &auth[0], context->MessageIntegrityCheckOffset); ++ winpr_HMAC_Update(hmac, data, sizeof(data)); ++ winpr_HMAC_Update(hmac, &auth[rest], context->AuthenticateMessage.cbBuffer - rest); ++ } ++ else ++ { ++ winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer, ++ context->AuthenticateMessage.cbBuffer); ++ } + winpr_HMAC_Final(hmac, mic, WINPR_MD5_DIGEST_LENGTH); ++ rc = TRUE; + } + + winpr_HMAC_Free(hmac); ++ return rc; + } +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.h b/winpr/libwinpr/sspi/NTLM/ntlm_compute.h +index 47f6c5d..a5572b5 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.h ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.h +@@ -24,13 +24,16 @@ + + #include "ntlm_av_pairs.h" + +-void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo); +-int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); +-void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); +-void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo); ++BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo); ++BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); ++BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo); + +-int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); +-int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); ++#ifdef WITH_DEBUG_NTLM ++void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo); ++#endif ++ ++BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); ++BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response); + + void ntlm_output_target_name(NTLM_CONTEXT* context); + void ntlm_output_channel_bindings(NTLM_CONTEXT* context); +@@ -38,10 +41,10 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context); + void ntlm_current_time(BYTE* timestamp); + void ntlm_generate_timestamp(NTLM_CONTEXT* context); + +-int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context); +-int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context); ++BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context); ++BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context); + +-void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext); ++void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext); + void ntlm_generate_client_challenge(NTLM_CONTEXT* context); + void ntlm_generate_server_challenge(NTLM_CONTEXT* context); + void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context); +@@ -50,12 +53,12 @@ void ntlm_generate_exported_session_key(NTLM_CONTEXT* context); + void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context); + void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context); + +-void ntlm_generate_client_signing_key(NTLM_CONTEXT* context); +-void ntlm_generate_server_signing_key(NTLM_CONTEXT* context); +-void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context); +-void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context); ++BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context); ++BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context); ++BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context); ++BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context); + void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context); + +-void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size); ++BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size); + + #endif /* WINPR_AUTH_NTLM_COMPUTE_H */ +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c +index 7502ecf..7f3779d 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c +@@ -25,6 +25,7 @@ + #include "../sspi.h" + + #include ++#include + #include + #include + #include +@@ -33,140 +34,369 @@ + + #include "ntlm_message.h" + +-#include "../log.h" ++#include "../../log.h" + #define TAG WINPR_TAG("sspi.NTLM") + + static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' }; + +-#ifdef WITH_DEBUG_NTLM +-static const char* const NTLM_NEGOTIATE_STRINGS[] = { "NTLMSSP_NEGOTIATE_56", +- "NTLMSSP_NEGOTIATE_KEY_EXCH", +- "NTLMSSP_NEGOTIATE_128", +- "NTLMSSP_RESERVED1", +- "NTLMSSP_RESERVED2", +- "NTLMSSP_RESERVED3", +- "NTLMSSP_NEGOTIATE_VERSION", +- "NTLMSSP_RESERVED4", +- "NTLMSSP_NEGOTIATE_TARGET_INFO", +- "NTLMSSP_REQUEST_NON_NT_SESSION_KEY", +- "NTLMSSP_RESERVED5", +- "NTLMSSP_NEGOTIATE_IDENTIFY", +- "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY", +- "NTLMSSP_RESERVED6", +- "NTLMSSP_TARGET_TYPE_SERVER", +- "NTLMSSP_TARGET_TYPE_DOMAIN", +- "NTLMSSP_NEGOTIATE_ALWAYS_SIGN", +- "NTLMSSP_RESERVED7", +- "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED", +- "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED", +- "NTLMSSP_NEGOTIATE_ANONYMOUS", +- "NTLMSSP_RESERVED8", +- "NTLMSSP_NEGOTIATE_NTLM", +- "NTLMSSP_RESERVED9", +- "NTLMSSP_NEGOTIATE_LM_KEY", +- "NTLMSSP_NEGOTIATE_DATAGRAM", +- "NTLMSSP_NEGOTIATE_SEAL", +- "NTLMSSP_NEGOTIATE_SIGN", +- "NTLMSSP_RESERVED10", +- "NTLMSSP_REQUEST_TARGET", +- "NTLMSSP_NEGOTIATE_OEM", +- "NTLMSSP_NEGOTIATE_UNICODE" }; ++const char* ntlm_get_negotiate_string(UINT32 flag) ++{ ++ if (flag & NTLMSSP_NEGOTIATE_56) ++ return "NTLMSSP_NEGOTIATE_56"; ++ if (flag & NTLMSSP_NEGOTIATE_KEY_EXCH) ++ return "NTLMSSP_NEGOTIATE_KEY_EXCH"; ++ if (flag & NTLMSSP_NEGOTIATE_128) ++ return "NTLMSSP_NEGOTIATE_128"; ++ if (flag & NTLMSSP_RESERVED1) ++ return "NTLMSSP_RESERVED1"; ++ if (flag & NTLMSSP_RESERVED2) ++ return "NTLMSSP_RESERVED2"; ++ if (flag & NTLMSSP_RESERVED3) ++ return "NTLMSSP_RESERVED3"; ++ if (flag & NTLMSSP_NEGOTIATE_VERSION) ++ return "NTLMSSP_NEGOTIATE_VERSION"; ++ if (flag & NTLMSSP_RESERVED4) ++ return "NTLMSSP_RESERVED4"; ++ if (flag & NTLMSSP_NEGOTIATE_TARGET_INFO) ++ return "NTLMSSP_NEGOTIATE_TARGET_INFO"; ++ if (flag & NTLMSSP_REQUEST_NON_NT_SESSION_KEY) ++ return "NTLMSSP_REQUEST_NON_NT_SESSION_KEY"; ++ if (flag & NTLMSSP_RESERVED5) ++ return "NTLMSSP_RESERVED5"; ++ if (flag & NTLMSSP_NEGOTIATE_IDENTIFY) ++ return "NTLMSSP_NEGOTIATE_IDENTIFY"; ++ if (flag & NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY) ++ return "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY"; ++ if (flag & NTLMSSP_RESERVED6) ++ return "NTLMSSP_RESERVED6"; ++ if (flag & NTLMSSP_TARGET_TYPE_SERVER) ++ return "NTLMSSP_TARGET_TYPE_SERVER"; ++ if (flag & NTLMSSP_TARGET_TYPE_DOMAIN) ++ return "NTLMSSP_TARGET_TYPE_DOMAIN"; ++ if (flag & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) ++ return "NTLMSSP_NEGOTIATE_ALWAYS_SIGN"; ++ if (flag & NTLMSSP_RESERVED7) ++ return "NTLMSSP_RESERVED7"; ++ if (flag & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) ++ return "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED"; ++ if (flag & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) ++ return "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED"; ++ if (flag & NTLMSSP_NEGOTIATE_ANONYMOUS) ++ return "NTLMSSP_NEGOTIATE_ANONYMOUS"; ++ if (flag & NTLMSSP_RESERVED8) ++ return "NTLMSSP_RESERVED8"; ++ if (flag & NTLMSSP_NEGOTIATE_NTLM) ++ return "NTLMSSP_NEGOTIATE_NTLM"; ++ if (flag & NTLMSSP_RESERVED9) ++ return "NTLMSSP_RESERVED9"; ++ if (flag & NTLMSSP_NEGOTIATE_LM_KEY) ++ return "NTLMSSP_NEGOTIATE_LM_KEY"; ++ if (flag & NTLMSSP_NEGOTIATE_DATAGRAM) ++ return "NTLMSSP_NEGOTIATE_DATAGRAM"; ++ if (flag & NTLMSSP_NEGOTIATE_SEAL) ++ return "NTLMSSP_NEGOTIATE_SEAL"; ++ if (flag & NTLMSSP_NEGOTIATE_SIGN) ++ return "NTLMSSP_NEGOTIATE_SIGN"; ++ if (flag & NTLMSSP_RESERVED10) ++ return "NTLMSSP_RESERVED10"; ++ if (flag & NTLMSSP_REQUEST_TARGET) ++ return "NTLMSSP_REQUEST_TARGET"; ++ if (flag & NTLMSSP_NEGOTIATE_OEM) ++ return "NTLMSSP_NEGOTIATE_OEM"; ++ if (flag & NTLMSSP_NEGOTIATE_UNICODE) ++ return "NTLMSSP_NEGOTIATE_UNICODE"; ++ return "NTLMSSP_NEGOTIATE_UNKNOWN"; ++} ++ ++#if defined(WITH_DEBUG_NTLM) ++static void ntlm_print_message_fields(const NTLM_MESSAGE_FIELDS* fields, const char* name) ++{ ++ WINPR_ASSERT(fields); ++ WINPR_ASSERT(name); ++ ++ WLog_VRB(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name, ++ fields->Len, fields->MaxLen, fields->BufferOffset); ++ ++ if (fields->Len > 0) ++ winpr_HexDump(TAG, WLOG_TRACE, fields->Buffer, fields->Len); ++} + + static void ntlm_print_negotiate_flags(UINT32 flags) + { + int i; +- const char* str; +- WLog_INFO(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags); ++ ++ WLog_VRB(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags); + + for (i = 31; i >= 0; i--) + { + if ((flags >> i) & 1) + { +- str = NTLM_NEGOTIATE_STRINGS[(31 - i)]; +- WLog_INFO(TAG, "\t%s (%d),", str, (31 - i)); ++ const char* str = ntlm_get_negotiate_string(1 << i); ++ WLog_VRB(TAG, "\t%s (%d),", str, (31 - i)); + } + } + } ++ ++static void ntlm_print_negotiate_message(const SecBuffer* NegotiateMessage, ++ const NTLM_NEGOTIATE_MESSAGE* message) ++{ ++ WINPR_ASSERT(NegotiateMessage); ++ WINPR_ASSERT(message); ++ ++ WLog_VRB(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", NegotiateMessage->cbBuffer); ++ winpr_HexDump(TAG, WLOG_TRACE, NegotiateMessage->pvBuffer, NegotiateMessage->cbBuffer); ++ ntlm_print_negotiate_flags(message->NegotiateFlags); ++ ++ if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) ++ ntlm_print_version_info(&(message->Version)); ++} ++ ++static void ntlm_print_challenge_message(const SecBuffer* ChallengeMessage, ++ const NTLM_CHALLENGE_MESSAGE* message, ++ const SecBuffer* ChallengeTargetInfo) ++{ ++ WINPR_ASSERT(ChallengeMessage); ++ WINPR_ASSERT(message); ++ ++ WLog_VRB(TAG, "CHALLENGE_MESSAGE (length = %" PRIu32 ")", ChallengeMessage->cbBuffer); ++ winpr_HexDump(TAG, WLOG_TRACE, ChallengeMessage->pvBuffer, ChallengeMessage->cbBuffer); ++ ntlm_print_negotiate_flags(message->NegotiateFlags); ++ ++ if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) ++ ntlm_print_version_info(&(message->Version)); ++ ++ ntlm_print_message_fields(&(message->TargetName), "TargetName"); ++ ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); ++ ++ if (ChallengeTargetInfo && (ChallengeTargetInfo->cbBuffer > 0)) ++ { ++ WLog_VRB(TAG, "ChallengeTargetInfo (%" PRIu32 "):", ChallengeTargetInfo->cbBuffer); ++ ntlm_print_av_pair_list(ChallengeTargetInfo->pvBuffer, ChallengeTargetInfo->cbBuffer); ++ } ++} ++ ++static void ntlm_print_authenticate_message(const SecBuffer* AuthenticateMessage, ++ const NTLM_AUTHENTICATE_MESSAGE* message, UINT32 flags, ++ const SecBuffer* AuthenticateTargetInfo) ++{ ++ WINPR_ASSERT(AuthenticateMessage); ++ WINPR_ASSERT(message); ++ ++ WLog_VRB(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")", AuthenticateMessage->cbBuffer); ++ winpr_HexDump(TAG, WLOG_TRACE, AuthenticateMessage->pvBuffer, AuthenticateMessage->cbBuffer); ++ ntlm_print_negotiate_flags(message->NegotiateFlags); ++ ++ if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) ++ ntlm_print_version_info(&(message->Version)); ++ ++ if (AuthenticateTargetInfo && (AuthenticateTargetInfo->cbBuffer > 0)) ++ { ++ WLog_VRB(TAG, "AuthenticateTargetInfo (%" PRIu32 "):", AuthenticateTargetInfo->cbBuffer); ++ ntlm_print_av_pair_list(AuthenticateTargetInfo->pvBuffer, AuthenticateTargetInfo->cbBuffer); ++ } ++ ++ ntlm_print_message_fields(&(message->DomainName), "DomainName"); ++ ntlm_print_message_fields(&(message->UserName), "UserName"); ++ ntlm_print_message_fields(&(message->Workstation), "Workstation"); ++ ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); ++ ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); ++ ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); ++ ++ if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) ++ { ++ WLog_VRB(TAG, "MessageIntegrityCheck (length = 16)"); ++ winpr_HexDump(TAG, WLOG_TRACE, message->MessageIntegrityCheck, ++ sizeof(message->MessageIntegrityCheck)); ++ } ++} ++ ++static void ntlm_print_authentication_complete(const NTLM_CONTEXT* context) ++{ ++ WINPR_ASSERT(context); ++ ++ WLog_VRB(TAG, "ClientChallenge"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->ClientChallenge, 8); ++ WLog_VRB(TAG, "ServerChallenge"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->ServerChallenge, 8); ++ WLog_VRB(TAG, "SessionBaseKey"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->SessionBaseKey, 16); ++ WLog_VRB(TAG, "KeyExchangeKey"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->KeyExchangeKey, 16); ++ WLog_VRB(TAG, "ExportedSessionKey"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->ExportedSessionKey, 16); ++ WLog_VRB(TAG, "RandomSessionKey"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->RandomSessionKey, 16); ++ WLog_VRB(TAG, "ClientSigningKey"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->ClientSigningKey, 16); ++ WLog_VRB(TAG, "ClientSealingKey"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->ClientSealingKey, 16); ++ WLog_VRB(TAG, "ServerSigningKey"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->ServerSigningKey, 16); ++ WLog_VRB(TAG, "ServerSealingKey"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->ServerSealingKey, 16); ++ WLog_VRB(TAG, "Timestamp"); ++ winpr_HexDump(TAG, WLOG_TRACE, context->Timestamp, 8); ++} + #endif + +-static int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) ++static BOOL ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header, UINT32 expected) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(header); ++ + if (Stream_GetRemainingLength(s) < 12) +- return -1; ++ { ++ WLog_ERR(TAG, "Short NTLM_MESSAGE_HEADER::header %" PRIuz ", expected 12", ++ Stream_GetRemainingLength(s)); ++ return FALSE; ++ } + + Stream_Read(s, header->Signature, 8); + Stream_Read_UINT32(s, header->MessageType); + + if (strncmp((char*)header->Signature, NTLM_SIGNATURE, 8) != 0) +- return -1; ++ { ++ WLog_ERR(TAG, "NTLM_MESSAGE_HEADER Invalid signature, got %s, expected %s", ++ header->Signature, NTLM_SIGNATURE); ++ return FALSE; ++ } + +- return 1; ++ if (header->MessageType != expected) ++ { ++ WLog_ERR(TAG, "NTLM_MESSAGE_HEADER Invalid message tyep, got %s, expected %s", ++ ntlm_message_type_string(header->MessageType), ntlm_message_type_string(expected)); ++ return FALSE; ++ } ++ ++ return TRUE; + } + +-static void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) ++static BOOL ntlm_write_message_header(wStream* s, const NTLM_MESSAGE_HEADER* header) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(header); ++ ++ if (Stream_GetRemainingCapacity(s) < sizeof(NTLM_SIGNATURE) + 4) ++ { ++ WLog_ERR(TAG, "Short NTLM_MESSAGE_HEADER::header %" PRIuz ", expected 12", ++ Stream_GetRemainingCapacity(s)); ++ return FALSE; ++ } ++ + Stream_Write(s, header->Signature, sizeof(NTLM_SIGNATURE)); + Stream_Write_UINT32(s, header->MessageType); ++ ++ return TRUE; + } + +-static void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) ++static BOOL ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) + { ++ WINPR_ASSERT(header); ++ + CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); + header->MessageType = MessageType; ++ return TRUE; + } + +-static int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) ++static BOOL ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(fields); ++ + if (Stream_GetRemainingLength(s) < 8) +- return -1; ++ { ++ WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::header %" PRIuz ", expected %" PRIuz, ++ Stream_GetRemainingLength(s), 8); ++ return FALSE; ++ } + + Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */ + Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ + Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ +- return 1; ++ return TRUE; + } + +-static void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) ++static BOOL ntlm_write_message_fields(wStream* s, const NTLM_MESSAGE_FIELDS* fields) + { ++ UINT16 MaxLen; ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(fields); ++ ++ MaxLen = fields->MaxLen; + if (fields->MaxLen < 1) +- fields->MaxLen = fields->Len; ++ MaxLen = fields->Len; + ++ if (Stream_GetRemainingCapacity(s) < 8) ++ { ++ WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::header %" PRIuz ", expected %" PRIuz, ++ Stream_GetRemainingCapacity(s), 8); ++ return FALSE; ++ } + Stream_Write_UINT16(s, fields->Len); /* Len (2 bytes) */ +- Stream_Write_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ ++ Stream_Write_UINT16(s, MaxLen); /* MaxLen (2 bytes) */ + Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ ++ return TRUE; + } + +-static int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) ++static BOOL ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(fields); ++ + if (fields->Len > 0) + { + const UINT32 offset = fields->BufferOffset + fields->Len; + + if (fields->BufferOffset > UINT32_MAX - fields->Len) +- return -1; ++ { ++ WLog_ERR(TAG, ++ "NTLM_MESSAGE_FIELDS::BufferOffset %" PRIu32 ++ " too large, maximum allowed is %" PRIu32, ++ fields->BufferOffset, UINT32_MAX - fields->Len); ++ return FALSE; ++ } + + if (offset > Stream_Length(s)) +- return -1; ++ { ++ WLog_ERR(TAG, ++ "NTLM_MESSAGE_FIELDS::Buffer offset %" PRIu32 " beyond received data %" PRIuz, ++ offset, Stream_Length(s)); ++ return FALSE; ++ } + + fields->Buffer = (PBYTE)malloc(fields->Len); + + if (!fields->Buffer) +- return -1; ++ { ++ WLog_ERR(TAG, "NTLM_MESSAGE_FIELDS::Buffer allocation of %" PRIu16 "bytes failed", ++ fields->Len); ++ return FALSE; ++ } + + Stream_SetPosition(s, fields->BufferOffset); + Stream_Read(s, fields->Buffer, fields->Len); + } + +- return 1; ++ return TRUE; + } + +-static void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) ++static BOOL ntlm_write_message_fields_buffer(wStream* s, const NTLM_MESSAGE_FIELDS* fields) + { ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(fields); ++ + if (fields->Len > 0) + { + Stream_SetPosition(s, fields->BufferOffset); ++ if (Stream_GetRemainingCapacity(s) < fields->Len) ++ { ++ WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::Len %" PRIuz ", expected %" PRIu16, ++ Stream_GetRemainingCapacity(s), fields->Len); ++ return FALSE; ++ } + Stream_Write(s, fields->Buffer, fields->Len); + } ++ return TRUE; + } + + static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) +@@ -184,122 +414,196 @@ static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) + } + } + +-#ifdef WITH_DEBUG_NTLM +-static void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name) ++static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required, const char* name) + { +- WLog_DBG(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name, +- fields->Len, fields->MaxLen, fields->BufferOffset); ++ UINT32 NegotiateFlags = 0; ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(flags); ++ WINPR_ASSERT(name); + +- if (fields->Len > 0) +- winpr_HexDump(TAG, WLOG_DEBUG, fields->Buffer, fields->Len); ++ if (Stream_GetRemainingLength(s) < 4) ++ { ++ WLog_ERR(TAG, "%s::NegotiateFlags expected 4bytes, have %" PRIuz "bytes", name, ++ Stream_GetRemainingLength(s)); ++ return FALSE; ++ } ++ ++ Stream_Read_UINT32(s, NegotiateFlags); /* NegotiateFlags (4 bytes) */ ++ ++ if ((NegotiateFlags & required) != required) ++ { ++ WLog_ERR(TAG, "%s::NegotiateFlags invalid flags 0x08%" PRIx32 ", 0x%08" PRIx32 " required", ++ name, NegotiateFlags, required); ++ return FALSE; ++ } ++ *flags = NegotiateFlags; ++ return TRUE; ++} ++ ++static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* name) ++{ ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(name); ++ ++ if (Stream_GetRemainingCapacity(s) < 4) ++ { ++ WLog_ERR(TAG, "%s::NegotiateFlags expected 4bytes, have %" PRIuz "bytes", name, ++ Stream_GetRemainingCapacity(s)); ++ return FALSE; ++ } ++ ++ Stream_Write_UINT32(s, flags); /* NegotiateFlags (4 bytes) */ ++ return TRUE; ++} ++ ++static BOOL ntlm_read_message_integrity_check(wStream* s, size_t* offset, BYTE* data, size_t size, ++ const char* name) ++{ ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(offset); ++ WINPR_ASSERT(data); ++ WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH); ++ WINPR_ASSERT(name); ++ ++ *offset = Stream_GetPosition(s); ++ ++ if (Stream_GetRemainingLength(s) < size) ++ { ++ WLog_ERR(TAG, ++ "%s::MessageIntegrityCheckOffset expected %" PRIuz "bytes, got " ++ "%" PRIuz "byets", ++ name, size, Stream_GetRemainingLength(s)); ++ return FALSE; ++ } ++ ++ Stream_Read(s, data, size); ++ return TRUE; ++} ++ ++static BOOL ntlm_write_message_integrity_check(wStream* s, size_t offset, const BYTE* data, ++ size_t size, const char* name) ++{ ++ size_t pos; ++ ++ WINPR_ASSERT(s); ++ WINPR_ASSERT(data); ++ WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH); ++ WINPR_ASSERT(name); ++ ++ pos = Stream_GetPosition(s); ++ ++ if (offset + size > Stream_Capacity(s)) ++ { ++ WLog_ERR(TAG, ++ "%s::MessageIntegrityCheck invalid offset[length] %" PRIuz "[%" PRIuz ++ "], got %" PRIuz, ++ name, offset, size, Stream_GetRemainingCapacity(s)); ++ return FALSE; ++ } ++ Stream_SetPosition(s, offset); ++ if (Stream_GetRemainingCapacity(s) < size) ++ { ++ WLog_ERR(TAG, "%s::MessageIntegrityCheck expected %" PRIuz "bytes, got %" PRIuz "bytes", ++ name, size, Stream_GetRemainingCapacity(s)); ++ return FALSE; ++ } ++ ++ Stream_Write(s, data, size); ++ Stream_SetPosition(s, pos); ++ return TRUE; + } +-#endif + + SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) + { ++ wStream sbuffer; + wStream* s; + size_t length; ++ const NTLM_NEGOTIATE_MESSAGE empty = { 0 }; + NTLM_NEGOTIATE_MESSAGE* message; ++ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(buffer); ++ + message = &context->NEGOTIATE_MESSAGE; +- ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE)); +- s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); ++ WINPR_ASSERT(message); ++ ++ *message = empty; ++ ++ s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; + +- if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) +- { +- Stream_Free(s, FALSE); ++ if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_NEGOTIATE)) + return SEC_E_INVALID_TOKEN; +- } + +- if (message->MessageType != MESSAGE_TYPE_NEGOTIATE) +- { +- Stream_Free(s, FALSE); ++ if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, ++ NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | ++ NTLMSSP_NEGOTIATE_UNICODE, ++ "NTLM_NEGOTIATE_MESSAGE")) + return SEC_E_INVALID_TOKEN; +- } +- +- if (Stream_GetRemainingLength(s) < 4) +- { +- Stream_Free(s, FALSE); +- return SEC_E_INVALID_TOKEN; +- } +- Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ +- +- if (!((message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) && +- (message->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) && +- (message->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE))) +- { +- Stream_Free(s, FALSE); +- return SEC_E_INVALID_TOKEN; +- } + + context->NegotiateFlags = message->NegotiateFlags; + + /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ +- +- if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */ ++ // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) + { +- Stream_Free(s, FALSE); +- return SEC_E_INVALID_TOKEN; ++ if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ ++ return SEC_E_INVALID_TOKEN; + } + + /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ +- +- if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */ ++ // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) + { +- Stream_Free(s, FALSE); +- return SEC_E_INVALID_TOKEN; ++ if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ ++ return SEC_E_INVALID_TOKEN; + } + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + { +- if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ +- { +- Stream_Free(s, FALSE); ++ if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ + return SEC_E_INVALID_TOKEN; +- } + } + + length = Stream_GetPosition(s); +- buffer->cbBuffer = length; ++ WINPR_ASSERT(length <= ULONG_MAX); ++ buffer->cbBuffer = (ULONG)length; + +- if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length)) +- { +- Stream_Free(s, FALSE); ++ if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length)) + return SEC_E_INTERNAL_ERROR; +- } + + CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); + context->NegotiateMessage.BufferType = buffer->BufferType; +-#ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", context->NegotiateMessage.cbBuffer); +- winpr_HexDump(TAG, WLOG_DEBUG, context->NegotiateMessage.pvBuffer, +- context->NegotiateMessage.cbBuffer); +- ntlm_print_negotiate_flags(message->NegotiateFlags); +- +- if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_print_version_info(&(message->Version)); +- ++#if defined(WITH_DEBUG_NTLM) ++ ntlm_print_negotiate_message(&context->NegotiateMessage, message); + #endif +- context->state = NTLM_STATE_CHALLENGE; +- Stream_Free(s, FALSE); ++ ntlm_change_state(context, NTLM_STATE_CHALLENGE); + return SEC_I_CONTINUE_NEEDED; + } + + SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) + { ++ wStream sbuffer; + wStream* s; + size_t length; ++ const NTLM_NEGOTIATE_MESSAGE empty = { 0 }; + NTLM_NEGOTIATE_MESSAGE* message; ++ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(buffer); ++ + message = &context->NEGOTIATE_MESSAGE; +- ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE)); +- s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); ++ WINPR_ASSERT(message); ++ ++ *message = empty; ++ ++ s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; + +- ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_NEGOTIATE); ++ if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_NEGOTIATE)) ++ return SEC_E_INTERNAL_ERROR; + + if (context->NTLMv2) + { +@@ -329,96 +633,101 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu + + context->NegotiateFlags = message->NegotiateFlags; + /* Message Header (12 bytes) */ +- ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); +- Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ ++ if (!ntlm_write_message_header(s, &message->header)) ++ return SEC_E_INTERNAL_ERROR; ++ ++ if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_NEGOTIATE_MESSAGE")) ++ return SEC_E_INTERNAL_ERROR; ++ + /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ + /* DomainNameFields (8 bytes) */ +- ntlm_write_message_fields(s, &(message->DomainName)); ++ if (!ntlm_write_message_fields(s, &(message->DomainName))) ++ return SEC_E_INTERNAL_ERROR; ++ + /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ + /* WorkstationFields (8 bytes) */ +- ntlm_write_message_fields(s, &(message->Workstation)); ++ if (!ntlm_write_message_fields(s, &(message->Workstation))) ++ return SEC_E_INTERNAL_ERROR; + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_write_version_info(s, &(message->Version)); ++ { ++ if (!ntlm_write_version_info(s, &(message->Version))) ++ return SEC_E_INTERNAL_ERROR; ++ } + + length = Stream_GetPosition(s); +- buffer->cbBuffer = length; ++ WINPR_ASSERT(length <= ULONG_MAX); ++ buffer->cbBuffer = (ULONG)length; + +- if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length)) +- { +- Stream_Free(s, FALSE); ++ if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length)) + return SEC_E_INTERNAL_ERROR; +- } + + CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); + context->NegotiateMessage.BufferType = buffer->BufferType; +-#ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %d)", length); +- winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); +- +- if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_print_version_info(&(message->Version)); +- ++#if defined(WITH_DEBUG_NTLM) ++ ntlm_print_negotiate_message(&context->NegotiateMessage, message); + #endif +- context->state = NTLM_STATE_CHALLENGE; +- Stream_Free(s, FALSE); ++ ntlm_change_state(context, NTLM_STATE_CHALLENGE); + return SEC_I_CONTINUE_NEEDED; + } + + SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer) + { + SECURITY_STATUS status = SEC_E_INVALID_TOKEN; ++ wStream sbuffer; + wStream* s; + size_t length; + size_t StartOffset; + size_t PayloadOffset; + NTLM_AV_PAIR* AvTimestamp; ++ const NTLM_CHALLENGE_MESSAGE empty = { 0 }; + NTLM_CHALLENGE_MESSAGE* message; ++ + if (!context || !buffer) + return SEC_E_INTERNAL_ERROR; + + ntlm_generate_client_challenge(context); + message = &context->CHALLENGE_MESSAGE; +- ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE)); +- s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); ++ WINPR_ASSERT(message); ++ ++ *message = empty; ++ ++ s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; + + StartOffset = Stream_GetPosition(s); + +- if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) ++ if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_CHALLENGE)) + goto fail; + +- if (message->MessageType != MESSAGE_TYPE_CHALLENGE) ++ if (!ntlm_read_message_fields(s, &(message->TargetName))) /* TargetNameFields (8 bytes) */ + goto fail; + +- if (ntlm_read_message_fields(s, &(message->TargetName)) < 0) /* TargetNameFields (8 bytes) */ +- goto fail; +- +- if (Stream_GetRemainingLength(s) < 4) ++ if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_CHALLENGE_MESSAGE")) + goto fail; + +- Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + context->NegotiateFlags = message->NegotiateFlags; + +- if (Stream_GetRemainingLength(s) < 8) ++ if (Stream_GetRemainingLength(s) < 16) ++ { ++ WLog_ERR(TAG, ++ "NTLM_CHALLENGE_MESSAGE::ServerChallenge expected 16bytes, got %" PRIuz "bytes", ++ Stream_GetRemainingLength(s)); + goto fail; ++ } + + Stream_Read(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ + CopyMemory(context->ServerChallenge, message->ServerChallenge, 8); +- +- if (Stream_GetRemainingLength(s) < 8) +- goto fail; +- + Stream_Read(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */ + +- if (ntlm_read_message_fields(s, &(message->TargetInfo)) < 0) /* TargetInfoFields (8 bytes) */ ++ if (!ntlm_read_message_fields(s, &(message->TargetInfo))) /* TargetInfoFields (8 bytes) */ + goto fail; + + if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + { +- if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ ++ if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ + goto fail; + } + +@@ -428,7 +737,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf + status = SEC_E_INTERNAL_ERROR; + if (message->TargetName.Len > 0) + { +- if (ntlm_read_message_fields_buffer(s, &(message->TargetName)) < 0) ++ if (!ntlm_read_message_fields_buffer(s, &(message->TargetName))) + goto fail; + } + +@@ -436,7 +745,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf + { + size_t cbAvTimestamp; + +- if (ntlm_read_message_fields_buffer(s, &(message->TargetInfo)) < 0) ++ if (!ntlm_read_message_fields_buffer(s, &(message->TargetInfo))) + goto fail; + + context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer; +@@ -462,36 +771,19 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf + if (length > buffer->cbBuffer) + goto fail; + +- if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length)) ++ if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length)) + goto fail; + + if (context->ChallengeMessage.pvBuffer) + CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s) + StartOffset, length); +-#ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer, +- context->ChallengeMessage.cbBuffer); +- ntlm_print_negotiate_flags(context->NegotiateFlags); +- +- if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_print_version_info(&(message->Version)); +- +- ntlm_print_message_fields(&(message->TargetName), "TargetName"); +- ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); +- +- if (context->ChallengeTargetInfo.cbBuffer > 0) +- { +- WLog_DBG(TAG, "ChallengeTargetInfo (%" PRIu32 "):", context->ChallengeTargetInfo.cbBuffer); +- ntlm_print_av_pair_list(context->ChallengeTargetInfo.pvBuffer, +- context->ChallengeTargetInfo.cbBuffer); +- } +- ++#if defined(WITH_DEBUG_NTLM) ++ ntlm_print_challenge_message(&context->ChallengeMessage, message, NULL); + #endif + /* AV_PAIRs */ + + if (context->NTLMv2) + { +- if (ntlm_construct_authenticate_target_info(context) < 0) ++ if (!ntlm_construct_authenticate_target_info(context)) + goto fail; + + sspi_SecBufferFree(&context->ChallengeTargetInfo); +@@ -501,10 +793,10 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf + + ntlm_generate_timestamp(context); /* Timestamp */ + +- if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */ ++ if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ + goto fail; + +- if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */ ++ if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */ + goto fail; + + ntlm_generate_key_exchange_key(context); /* KeyExchangeKey */ +@@ -512,54 +804,45 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf + ntlm_generate_exported_session_key(context); /* ExportedSessionKey */ + ntlm_encrypt_random_session_key(context); /* EncryptedRandomSessionKey */ + /* Generate signing keys */ +- ntlm_generate_client_signing_key(context); +- ntlm_generate_server_signing_key(context); ++ if (!ntlm_generate_client_signing_key(context)) ++ goto fail; ++ if (!ntlm_generate_server_signing_key(context)) ++ goto fail; + /* Generate sealing keys */ +- ntlm_generate_client_sealing_key(context); +- ntlm_generate_server_sealing_key(context); ++ if (!ntlm_generate_client_sealing_key(context)) ++ goto fail; ++ if (!ntlm_generate_server_sealing_key(context)) ++ goto fail; + /* Initialize RC4 seal state using client sealing key */ + ntlm_init_rc4_seal_states(context); +-#ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "ClientChallenge"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8); +- WLog_DBG(TAG, "ServerChallenge"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8); +- WLog_DBG(TAG, "SessionBaseKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16); +- WLog_DBG(TAG, "KeyExchangeKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16); +- WLog_DBG(TAG, "ExportedSessionKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16); +- WLog_DBG(TAG, "RandomSessionKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16); +- WLog_DBG(TAG, "ClientSigningKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16); +- WLog_DBG(TAG, "ClientSealingKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16); +- WLog_DBG(TAG, "ServerSigningKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16); +- WLog_DBG(TAG, "ServerSealingKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16); +- WLog_DBG(TAG, "Timestamp"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8); ++#if defined(WITH_DEBUG_NTLM) ++ ntlm_print_authentication_complete(context); + #endif +- context->state = NTLM_STATE_AUTHENTICATE; ++ ntlm_change_state(context, NTLM_STATE_AUTHENTICATE); + status = SEC_I_CONTINUE_NEEDED; + fail: + ntlm_free_message_fields_buffer(&(message->TargetName)); +- Stream_Free(s, FALSE); + return status; + } + + SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer) + { ++ wStream sbuffer; + wStream* s; + size_t length; + UINT32 PayloadOffset; ++ const NTLM_CHALLENGE_MESSAGE empty = { 0 }; + NTLM_CHALLENGE_MESSAGE* message; ++ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(buffer); ++ + message = &context->CHALLENGE_MESSAGE; +- ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE)); +- s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); ++ WINPR_ASSERT(message); ++ ++ *message = empty; ++ ++ s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; +@@ -568,17 +851,17 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu + ntlm_generate_server_challenge(context); /* Server Challenge */ + ntlm_generate_timestamp(context); /* Timestamp */ + +- if (ntlm_construct_challenge_target_info(context) < 0) /* TargetInfo */ +- { +- Stream_Free(s, FALSE); ++ if (!ntlm_construct_challenge_target_info(context)) /* TargetInfo */ + return SEC_E_INTERNAL_ERROR; +- } + + CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */ + message->NegotiateFlags = context->NegotiateFlags; +- ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_CHALLENGE); ++ if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_CHALLENGE)) ++ return SEC_E_INTERNAL_ERROR; ++ + /* Message Header (12 bytes) */ +- ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); ++ if (!ntlm_write_message_header(s, &message->header)) ++ return SEC_E_INTERNAL_ERROR; + + if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) + { +@@ -602,99 +885,119 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu + message->TargetName.BufferOffset = PayloadOffset; + message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len; + /* TargetNameFields (8 bytes) */ +- ntlm_write_message_fields(s, &(message->TargetName)); +- Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ ++ if (!ntlm_write_message_fields(s, &(message->TargetName))) ++ return SEC_E_INTERNAL_ERROR; ++ ++ if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_CHALLENGE_MESSAGE")) ++ return SEC_E_INTERNAL_ERROR; ++ ++ if (Stream_GetRemainingCapacity(s) < 16) ++ { ++ WLog_ERR(TAG, ++ "NTLM_CHALLENGE_MESSAGE::ServerChallenge expected 16bytes, got %" PRIuz "bytes", ++ Stream_GetRemainingCapacity(s)); ++ return SEC_E_INTERNAL_ERROR; ++ } ++ + Stream_Write(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ + Stream_Write(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */ ++ + /* TargetInfoFields (8 bytes) */ +- ntlm_write_message_fields(s, &(message->TargetInfo)); ++ if (!ntlm_write_message_fields(s, &(message->TargetInfo))) ++ return SEC_E_INTERNAL_ERROR; + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */ ++ { ++ if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ } + + /* Payload (variable) */ +- + if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) +- ntlm_write_message_fields_buffer(s, &(message->TargetName)); ++ { ++ if (!ntlm_write_message_fields_buffer(s, &(message->TargetName))) ++ return SEC_E_INTERNAL_ERROR; ++ } + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO) +- ntlm_write_message_fields_buffer(s, &(message->TargetInfo)); ++ { ++ if (!ntlm_write_message_fields_buffer(s, &(message->TargetInfo))) ++ return SEC_E_INTERNAL_ERROR; ++ } + + length = Stream_GetPosition(s); +- buffer->cbBuffer = length; ++ WINPR_ASSERT(length <= ULONG_MAX); ++ buffer->cbBuffer = (ULONG)length; + +- if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length)) +- { +- Stream_Free(s, FALSE); ++ if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length)) + return SEC_E_INTERNAL_ERROR; +- } + + CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length); +-#ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer, +- context->ChallengeMessage.cbBuffer); +- ntlm_print_negotiate_flags(message->NegotiateFlags); +- +- if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_print_version_info(&(message->Version)); +- +- ntlm_print_message_fields(&(message->TargetName), "TargetName"); +- ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); ++#if defined(WITH_DEBUG_NTLM) ++ ntlm_print_challenge_message(&context->ChallengeMessage, message, ++ &context->ChallengeTargetInfo); + #endif +- context->state = NTLM_STATE_AUTHENTICATE; +- Stream_Free(s, FALSE); ++ ntlm_change_state(context, NTLM_STATE_AUTHENTICATE); + return SEC_I_CONTINUE_NEEDED; + } + + SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) + { + SECURITY_STATUS status = SEC_E_INVALID_TOKEN; ++ wStream sbuffer; + wStream* s; + size_t length; + UINT32 flags = 0; + NTLM_AV_PAIR* AvFlags = NULL; +- UINT32 PayloadBufferOffset; ++ size_t PayloadBufferOffset; ++ const NTLM_AUTHENTICATE_MESSAGE empty = { 0 }; + NTLM_AUTHENTICATE_MESSAGE* message; +- SSPI_CREDENTIALS* credentials = context->credentials; ++ SSPI_CREDENTIALS* credentials; ++ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(buffer); ++ ++ credentials = context->credentials; ++ WINPR_ASSERT(credentials); + + message = &context->AUTHENTICATE_MESSAGE; +- ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE)); +- s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); ++ WINPR_ASSERT(message); ++ ++ *message = empty; ++ ++ s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; + +- if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) ++ if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_AUTHENTICATE)) + goto fail; + +- if (message->MessageType != MESSAGE_TYPE_AUTHENTICATE) ++ if (!ntlm_read_message_fields( ++ s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */ + goto fail; + +- if (ntlm_read_message_fields(s, &(message->LmChallengeResponse)) < +- 0) /* LmChallengeResponseFields (8 bytes) */ ++ if (!ntlm_read_message_fields( ++ s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */ + goto fail; + +- if (ntlm_read_message_fields(s, &(message->NtChallengeResponse)) < +- 0) /* NtChallengeResponseFields (8 bytes) */ ++ if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ + goto fail; + +- if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */ ++ if (!ntlm_read_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */ + goto fail; + +- if (ntlm_read_message_fields(s, &(message->UserName)) < 0) /* UserNameFields (8 bytes) */ ++ if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ + goto fail; + +- if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */ ++ if (!ntlm_read_message_fields( ++ s, ++ &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */ + goto fail; + +- if (ntlm_read_message_fields(s, &(message->EncryptedRandomSessionKey)) < +- 0) /* EncryptedRandomSessionKeyFields (8 bytes) */ ++ if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_AUTHENTICATE_MESSAGE")) + goto fail; + +- if (Stream_GetRemainingLength(s) < 4) +- goto fail; +- Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + context->NegotiateKeyExchange = + (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE; + +@@ -704,44 +1007,48 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + { +- if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ ++ if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ + goto fail; + } + + PayloadBufferOffset = Stream_GetPosition(s); + + status = SEC_E_INTERNAL_ERROR; +- if (ntlm_read_message_fields_buffer(s, &(message->DomainName)) < 0) /* DomainName */ ++ if (!ntlm_read_message_fields_buffer(s, &(message->DomainName))) /* DomainName */ + goto fail; + +- if (ntlm_read_message_fields_buffer(s, &(message->UserName)) < 0) /* UserName */ ++ if (!ntlm_read_message_fields_buffer(s, &(message->UserName))) /* UserName */ + goto fail; + +- if (ntlm_read_message_fields_buffer(s, &(message->Workstation)) < 0) /* Workstation */ +- goto fail; ++ if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) ++ { ++ if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ ++ goto fail; ++ } + +- if (ntlm_read_message_fields_buffer(s, &(message->LmChallengeResponse)) < +- 0) /* LmChallengeResponse */ +- goto fail; ++ if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) ++ { ++ if (!ntlm_read_message_fields_buffer( ++ s, &(message->LmChallengeResponse))) /* LmChallengeResponse */ ++ goto fail; ++ } + +- if (ntlm_read_message_fields_buffer(s, &(message->NtChallengeResponse)) < +- 0) /* NtChallengeResponse */ ++ if (!ntlm_read_message_fields_buffer(s, ++ &(message->NtChallengeResponse))) /* NtChallengeResponse */ + goto fail; + + if (message->NtChallengeResponse.Len > 0) + { +- int rc; + size_t cbAvFlags; +- wStream* snt = +- Stream_New(message->NtChallengeResponse.Buffer, message->NtChallengeResponse.Len); ++ wStream ssbuffer; ++ wStream* snt = Stream_StaticConstInit(&ssbuffer, message->NtChallengeResponse.Buffer, ++ message->NtChallengeResponse.Len); + + if (!snt) + goto fail; + + status = SEC_E_INVALID_TOKEN; +- rc = ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response)); +- Stream_Free(snt, FALSE); +- if (rc < 0) ++ if (!ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response))) + goto fail; + status = SEC_E_INTERNAL_ERROR; + +@@ -759,8 +1066,8 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer + Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); + } + +- if (ntlm_read_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)) < +- 0) /* EncryptedRandomSessionKey */ ++ if (!ntlm_read_message_fields_buffer( ++ s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */ + goto fail; + + if (message->EncryptedRandomSessionKey.Len > 0) +@@ -773,51 +1080,28 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer + } + + length = Stream_GetPosition(s); ++ WINPR_ASSERT(length <= ULONG_MAX); + +- if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length)) ++ if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length)) + goto fail; + + CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length); +- buffer->cbBuffer = length; ++ buffer->cbBuffer = (ULONG)length; + Stream_SetPosition(s, PayloadBufferOffset); + + if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) + { +- context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s); +- + status = SEC_E_INVALID_TOKEN; +- if (Stream_GetRemainingLength(s) < 16) ++ if (!ntlm_read_message_integrity_check( ++ s, &context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck, ++ sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE")) + goto fail; +- +- Stream_Read(s, message->MessageIntegrityCheck, 16); + } + + status = SEC_E_INTERNAL_ERROR; + +-#ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")", +- context->AuthenticateMessage.cbBuffer); +- winpr_HexDump(TAG, WLOG_DEBUG, context->AuthenticateMessage.pvBuffer, +- context->AuthenticateMessage.cbBuffer); +- +- if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_print_version_info(&(message->Version)); +- +- ntlm_print_message_fields(&(message->DomainName), "DomainName"); +- ntlm_print_message_fields(&(message->UserName), "UserName"); +- ntlm_print_message_fields(&(message->Workstation), "Workstation"); +- ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); +- ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); +- ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); +- ntlm_print_av_pair_list(context->NTLMv2Response.Challenge.AvPairs, +- context->NTLMv2Response.Challenge.cbAvPairs); +- +- if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) +- { +- WLog_DBG(TAG, "MessageIntegrityCheck:"); +- winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16); +- } +- ++#if defined(WITH_DEBUG_NTLM) ++ ntlm_print_authenticate_message(&context->AuthenticateMessage, message, flags, NULL); + #endif + + if (message->UserName.Len > 0) +@@ -843,13 +1127,11 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer + credentials->identity.DomainLength = message->DomainName.Len / 2; + } + +- Stream_Free(s, FALSE); + /* Computations beyond this point require the NTLM hash of the password */ +- context->state = NTLM_STATE_COMPLETION; ++ ntlm_change_state(context, NTLM_STATE_COMPLETION); + return SEC_I_COMPLETE_NEEDED; + + fail: +- Stream_Free(s, FALSE); + return status; + } + +@@ -862,14 +1144,26 @@ fail: + + SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) + { ++ wStream sbuffer; + wStream* s; + size_t length; + UINT32 PayloadBufferOffset; ++ const NTLM_AUTHENTICATE_MESSAGE empty = { 0 }; + NTLM_AUTHENTICATE_MESSAGE* message; +- SSPI_CREDENTIALS* credentials = context->credentials; ++ SSPI_CREDENTIALS* credentials; ++ ++ WINPR_ASSERT(context); ++ WINPR_ASSERT(buffer); ++ ++ credentials = context->credentials; ++ WINPR_ASSERT(credentials); ++ + message = &context->AUTHENTICATE_MESSAGE; +- ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE)); +- s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); ++ WINPR_ASSERT(message); ++ ++ *message = empty; ++ ++ s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; +@@ -948,95 +1242,103 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer + message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len; + message->EncryptedRandomSessionKey.BufferOffset = + message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len; +- ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_AUTHENTICATE); +- ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); /* Message Header (12 bytes) */ +- ntlm_write_message_fields( +- s, &(message->LmChallengeResponse)); /* LmChallengeResponseFields (8 bytes) */ +- ntlm_write_message_fields( +- s, &(message->NtChallengeResponse)); /* NtChallengeResponseFields (8 bytes) */ +- ntlm_write_message_fields(s, &(message->DomainName)); /* DomainNameFields (8 bytes) */ +- ntlm_write_message_fields(s, &(message->UserName)); /* UserNameFields (8 bytes) */ +- ntlm_write_message_fields(s, &(message->Workstation)); /* WorkstationFields (8 bytes) */ +- ntlm_write_message_fields( +- s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKeyFields (8 bytes) */ +- Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ ++ if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_AUTHENTICATE)) ++ return SEC_E_INVALID_TOKEN; ++ if (!ntlm_write_message_header(s, &message->header)) /* Message Header (12 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_write_message_fields( ++ s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_write_message_fields( ++ s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_write_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_write_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_write_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_write_message_fields( ++ s, ++ &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_AUTHENTICATE_MESSAGE")) ++ return SEC_E_INTERNAL_ERROR; + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */ ++ { ++ if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */ ++ return SEC_E_INTERNAL_ERROR; ++ } + + if (context->UseMIC) + { +- context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s); +- Stream_Zero(s, 16); /* Message Integrity Check (16 bytes) */ ++ const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 }; ++ ++ context->MessageIntegrityCheckOffset = Stream_GetPosition(s); ++ if (!ntlm_write_message_integrity_check(s, Stream_GetPosition(s), data, sizeof(data), ++ "NTLM_AUTHENTICATE_MESSAGE")) ++ return SEC_E_INTERNAL_ERROR; + } + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) +- ntlm_write_message_fields_buffer(s, &(message->DomainName)); /* DomainName */ ++ { ++ if (!ntlm_write_message_fields_buffer(s, &(message->DomainName))) /* DomainName */ ++ return SEC_E_INTERNAL_ERROR; ++ } + +- ntlm_write_message_fields_buffer(s, &(message->UserName)); /* UserName */ ++ if (!ntlm_write_message_fields_buffer(s, &(message->UserName))) /* UserName */ ++ return SEC_E_INTERNAL_ERROR; + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) +- ntlm_write_message_fields_buffer(s, &(message->Workstation)); /* Workstation */ ++ { ++ if (!ntlm_write_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ ++ return SEC_E_INTERNAL_ERROR; ++ } + +- ntlm_write_message_fields_buffer(s, &(message->LmChallengeResponse)); /* LmChallengeResponse */ +- ntlm_write_message_fields_buffer(s, &(message->NtChallengeResponse)); /* NtChallengeResponse */ ++ if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) ++ { ++ if (!ntlm_write_message_fields_buffer( ++ s, &(message->LmChallengeResponse))) /* LmChallengeResponse */ ++ return SEC_E_INTERNAL_ERROR; ++ } ++ if (!ntlm_write_message_fields_buffer( ++ s, &(message->NtChallengeResponse))) /* NtChallengeResponse */ ++ return SEC_E_INTERNAL_ERROR; + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) +- ntlm_write_message_fields_buffer( +- s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKey */ ++ { ++ if (!ntlm_write_message_fields_buffer( ++ s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */ ++ return SEC_E_INTERNAL_ERROR; ++ } + + length = Stream_GetPosition(s); ++ WINPR_ASSERT(length <= ULONG_MAX); + +- if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length)) +- { +- Stream_Free(s, FALSE); ++ if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length)) + return SEC_E_INTERNAL_ERROR; +- } + + CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length); +- buffer->cbBuffer = length; ++ buffer->cbBuffer = (ULONG)length; + + if (context->UseMIC) + { + /* Message Integrity Check */ +- ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck, 16); +- Stream_SetPosition(s, context->MessageIntegrityCheckOffset); +- Stream_Write(s, message->MessageIntegrityCheck, 16); +- Stream_SetPosition(s, length); +- } +- +-#ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %d)", length); +- winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); +- ntlm_print_negotiate_flags(message->NegotiateFlags); +- +- if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) +- ntlm_print_version_info(&(message->Version)); +- +- if (context->AuthenticateTargetInfo.cbBuffer > 0) +- { +- WLog_DBG(TAG, +- "AuthenticateTargetInfo (%" PRIu32 "):", context->AuthenticateTargetInfo.cbBuffer); +- ntlm_print_av_pair_list(context->AuthenticateTargetInfo.pvBuffer, +- context->AuthenticateTargetInfo.cbBuffer); +- } +- +- ntlm_print_message_fields(&(message->DomainName), "DomainName"); +- ntlm_print_message_fields(&(message->UserName), "UserName"); +- ntlm_print_message_fields(&(message->Workstation), "Workstation"); +- ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); +- ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); +- ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); +- +- if (context->UseMIC) +- { +- WLog_DBG(TAG, "MessageIntegrityCheck (length = 16)"); +- winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16); ++ ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck, ++ sizeof(message->MessageIntegrityCheck)); ++ if (!ntlm_write_message_integrity_check( ++ s, context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck, ++ sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE")) ++ return SEC_E_INTERNAL_ERROR; + } + ++#if defined(WITH_DEBUG_NTLM) ++ ntlm_print_authenticate_message(&context->AuthenticateMessage, message, ++ context->UseMIC ? MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK : 0, ++ &context->AuthenticateTargetInfo); + #endif +- context->state = NTLM_STATE_FINAL; +- Stream_Free(s, FALSE); ++ ntlm_change_state(context, NTLM_STATE_FINAL); + return SEC_E_OK; + } + +@@ -1046,25 +1348,26 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) + size_t cbAvFlags; + NTLM_AV_PAIR* AvFlags = NULL; + NTLM_AUTHENTICATE_MESSAGE* message; +- BYTE messageIntegrityCheck[16]; + + if (!context) + return SEC_E_INVALID_PARAMETER; + +- if (context->state != NTLM_STATE_COMPLETION) ++ if (ntlm_get_state(context) != NTLM_STATE_COMPLETION) + return SEC_E_OUT_OF_SEQUENCE; + + message = &context->AUTHENTICATE_MESSAGE; ++ WINPR_ASSERT(message); ++ + AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, + context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags); + + if (AvFlags) + Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); + +- if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */ ++ if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ + return SEC_E_INTERNAL_ERROR; + +- if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */ ++ if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */ + return SEC_E_INTERNAL_ERROR; + + /* KeyExchangeKey */ +@@ -1076,16 +1379,16 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) + + if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) + { +- ZeroMemory( +- &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset], +- 16); ++ BYTE messageIntegrityCheck[16] = { 0 }; ++ + ntlm_compute_message_integrity_check(context, messageIntegrityCheck, + sizeof(messageIntegrityCheck)); + CopyMemory( + &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset], +- message->MessageIntegrityCheck, 16); ++ message->MessageIntegrityCheck, sizeof(message->MessageIntegrityCheck)); + +- if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck, 16) != 0) ++ if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck, ++ sizeof(message->MessageIntegrityCheck)) != 0) + { + WLog_ERR(TAG, "Message Integrity Check (MIC) verification failed!"); + #ifdef WITH_DEBUG_NTLM +@@ -1111,7 +1414,7 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) + */ + + #ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "No MIC present, using NtProofString for verification."); ++ WLog_VRB(TAG, "No MIC present, using NtProofString for verification."); + #endif + + if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0) +@@ -1129,38 +1432,21 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) + } + + /* Generate signing keys */ +- ntlm_generate_client_signing_key(context); +- ntlm_generate_server_signing_key(context); ++ if (!ntlm_generate_client_signing_key(context)) ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_generate_server_signing_key(context)) ++ return SEC_E_INTERNAL_ERROR; + /* Generate sealing keys */ +- ntlm_generate_client_sealing_key(context); +- ntlm_generate_server_sealing_key(context); ++ if (!ntlm_generate_client_sealing_key(context)) ++ return SEC_E_INTERNAL_ERROR; ++ if (!ntlm_generate_server_sealing_key(context)) ++ return SEC_E_INTERNAL_ERROR; + /* Initialize RC4 seal state */ + ntlm_init_rc4_seal_states(context); +-#ifdef WITH_DEBUG_NTLM +- WLog_DBG(TAG, "ClientChallenge"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8); +- WLog_DBG(TAG, "ServerChallenge"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8); +- WLog_DBG(TAG, "SessionBaseKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16); +- WLog_DBG(TAG, "KeyExchangeKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16); +- WLog_DBG(TAG, "ExportedSessionKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16); +- WLog_DBG(TAG, "RandomSessionKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16); +- WLog_DBG(TAG, "ClientSigningKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16); +- WLog_DBG(TAG, "ClientSealingKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16); +- WLog_DBG(TAG, "ServerSigningKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16); +- WLog_DBG(TAG, "ServerSealingKey"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16); +- WLog_DBG(TAG, "Timestamp"); +- winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8); ++#if defined(WITH_DEBUG_NTLM) ++ ntlm_print_authentication_complete(context); + #endif +- context->state = NTLM_STATE_FINAL; ++ ntlm_change_state(context, NTLM_STATE_FINAL); + ntlm_free_message_fields_buffer(&(message->DomainName)); + ntlm_free_message_fields_buffer(&(message->UserName)); + ntlm_free_message_fields_buffer(&(message->Workstation)); +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.h b/winpr/libwinpr/sspi/NTLM/ntlm_message.h +index 100d95a..58ff35d 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_message.h ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.h +@@ -23,12 +23,14 @@ + #include "ntlm.h" + + SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +-SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); ++SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); + SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +-SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer); ++SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); + SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +-SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); ++SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); + + SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context); + ++const char* ntlm_get_negotiate_string(UINT32 flag); ++ + #endif /* WINPR_SSPI_NTLM_MESSAGE_H */ +diff --git a/winpr/libwinpr/sspi/test/TestNTLM.c b/winpr/libwinpr/sspi/test/TestNTLM.c +index 82d266f..9260bf0 100644 +--- a/winpr/libwinpr/sspi/test/TestNTLM.c ++++ b/winpr/libwinpr/sspi/test/TestNTLM.c +@@ -467,18 +467,15 @@ void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm) + free(ntlm); + } + +-int TestNTLM(int argc, char* argv[]) ++static BOOL test_default(void) + { + int status; +- int rc = -1; ++ BOOL rc = FALSE; + PSecBuffer pSecBuffer; + TEST_NTLM_CLIENT* client = NULL; + TEST_NTLM_SERVER* server = NULL; + BOOL DynamicTest = TRUE; + +- WINPR_UNUSED(argc); +- WINPR_UNUSED(argv); +- + /** + * Client Initialization + */ +@@ -684,7 +681,7 @@ int TestNTLM(int argc, char* argv[]) + goto fail; + } + +- rc = 0; ++ rc = TRUE; + + fail: + /** +@@ -694,3 +691,13 @@ fail: + test_ntlm_server_free(server); + return rc; + } ++ ++int TestNTLM(int argc, char* argv[]) ++{ ++ WINPR_UNUSED(argc); ++ WINPR_UNUSED(argv); ++ ++ if (!test_default()) ++ return -1; ++ return 0; ++} diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1016-Removed-unnecessary-assert.patch freerdp2-2.6.1+dfsg1/debian/patches/1016-Removed-unnecessary-assert.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1016-Removed-unnecessary-assert.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1016-Removed-unnecessary-assert.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,22 @@ +From: Armin Novak +Date: Tue, 22 Mar 2022 09:51:08 +0100 +Subject: Removed unnecessary assert + +(cherry picked from commit 4b1427639a9e29f911d92c0f33175e191cd5a503) +(cherry picked from commit 34e851209a742a67604191759730bef3c332ebcd) +--- + winpr/libwinpr/sspi/NTLM/ntlm_compute.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +index 5360a2c..202240b 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +@@ -656,7 +656,6 @@ void ntlm_generate_random_session_key(NTLM_CONTEXT* context) + void ntlm_generate_exported_session_key(NTLM_CONTEXT* context) + { + WINPR_ASSERT(context); +- WINPR_ASSERT(sizeof(context->ExportedSessionKey) == sizeof(context->RandomSessionKey)); + + CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, + sizeof(context->ExportedSessionKey)); diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1017-Fixed-NTLM-flag-handling.patch freerdp2-2.6.1+dfsg1/debian/patches/1017-Fixed-NTLM-flag-handling.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1017-Fixed-NTLM-flag-handling.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1017-Fixed-NTLM-flag-handling.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,144 @@ +From: Armin Novak +Date: Mon, 28 Mar 2022 10:32:08 +0200 +Subject: Fixed NTLM flag handling + +* NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED and NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED +* Problem with clients not supporting NTLMSSP_NEGOTIATE_LM_KEY +* Improve logging + +(cherry picked from commit 3c657d58cd0e7c2398b5488902ecf77bdb2eb8d8) +(cherry picked from commit 269ebb8cada3fef6b6cabfa5a1ea98ff4abbb99e) +--- + winpr/libwinpr/sspi/NTLM/ntlm.c | 35 +++++++++++++++++++-------------- + winpr/libwinpr/sspi/NTLM/ntlm_message.c | 26 +++++++++++++++++------- + 2 files changed, 39 insertions(+), 22 deletions(-) + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c +index c0af65b..e18fea2 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm.c +@@ -1289,26 +1289,31 @@ char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags) + if (!buffer || (size == 0)) + return buffer; + +- for (x = 0; x < 31; x++) +- { +- size_t len = strnlen(buffer, size); +- if (flags & x) ++ snprintf(buffer, size, "[0x%08" PRIx32 "] ", flags); ++ ++ for (x = 0; x < 31; x++) + { +- const char* str = ntlm_get_negotiate_string(1 << x); +- size_t flen = strlen(str); +- if (len > 0) ++ const UINT32 mask = 1 << x; ++ size_t len = strnlen(buffer, size); ++ if (flags & mask) + { +- if (size - len < 1) ++ const char* str = ntlm_get_negotiate_string(mask); ++ const size_t flen = strlen(str); ++ ++ if ((len > 0) && (buffer[len - 1] != ' ')) ++ { ++ if (size - len < 1) ++ break; ++ strcat(buffer, "|"); ++ len++; ++ } ++ ++ if (size - len < flen) + break; +- strcat(buffer, "|"); +- len++; ++ strcat(buffer, str); + } +- +- if (size - len < flen) +- break; +- strcat(buffer, str); + } +- } ++ + return buffer; + } + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c +index 7f3779d..442b9fe 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c +@@ -417,6 +417,7 @@ static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) + static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required, const char* name) + { + UINT32 NegotiateFlags = 0; ++ char buffer[1024] = { 0 }; + WINPR_ASSERT(s); + WINPR_ASSERT(flags); + WINPR_ASSERT(name); +@@ -436,12 +437,16 @@ static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required + name, NegotiateFlags, required); + return FALSE; + } ++ ++ WLog_DBG(TAG, "Read flags %s", ++ ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), NegotiateFlags)); + *flags = NegotiateFlags; + return TRUE; + } + + static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* name) + { ++ char buffer[1024] = { 0 }; + WINPR_ASSERT(s); + WINPR_ASSERT(name); + +@@ -452,6 +457,7 @@ static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* nam + return FALSE; + } + ++ WLog_DBG(TAG, "Write flags %s", ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), flags)); + Stream_Write_UINT32(s, flags); /* NegotiateFlags (4 bytes) */ + return TRUE; + } +@@ -565,6 +571,12 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf + return SEC_E_INVALID_TOKEN; + } + ++ if (!ntlm_read_message_fields_buffer(s, &message->DomainName)) ++ return SEC_E_INVALID_TOKEN; ++ ++ if (!ntlm_read_message_fields_buffer(s, &message->Workstation)) ++ return SEC_E_INVALID_TOKEN; ++ + length = Stream_GetPosition(s); + WINPR_ASSERT(length <= ULONG_MAX); + buffer->cbBuffer = (ULONG)length; +@@ -1020,11 +1032,8 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer + if (!ntlm_read_message_fields_buffer(s, &(message->UserName))) /* UserName */ + goto fail; + +- if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) +- { +- if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ +- goto fail; +- } ++ if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ ++ goto fail; + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) + { +@@ -1364,8 +1373,11 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) + if (AvFlags) + Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); + +- if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ +- return SEC_E_INTERNAL_ERROR; ++ if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) ++ { ++ if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ ++ return SEC_E_INTERNAL_ERROR; ++ } + + if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */ + return SEC_E_INTERNAL_ERROR; diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1018-Fixed-backport-compile-problems.patch freerdp2-2.6.1+dfsg1/debian/patches/1018-Fixed-backport-compile-problems.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1018-Fixed-backport-compile-problems.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1018-Fixed-backport-compile-problems.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,109 @@ +From: Armin Novak +Date: Mon, 28 Mar 2022 12:08:59 +0200 +Subject: Fixed backport compile problems + +(cherry picked from commit 061edc109fb1a4e161094adc6915eae84801611c) +--- + libfreerdp/core/settings.c | 10 ++-------- + winpr/libwinpr/sspi/NTLM/ntlm.c | 1 + + winpr/libwinpr/sspi/NTLM/ntlm.h | 2 +- + winpr/libwinpr/sspi/NTLM/ntlm_message.c | 18 +++++++++++++++--- + 4 files changed, 19 insertions(+), 12 deletions(-) + +diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c +index bd259d6..f4b5878 100644 +--- a/libfreerdp/core/settings.c ++++ b/libfreerdp/core/settings.c +@@ -401,15 +401,9 @@ rdpSettings* freerdp_settings_new(DWORD flags) + if (!settings->ClientProductId) + goto out_fail; + +- settings->ClientHostname = calloc(1, 32); +- +- if (!settings->ClientHostname) +- goto out_fail; +- DWORD size = 31; +- GetComputerNameA(ClientHostname, &size); +- if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, ClientHostname)) ++ if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, settings->ComputerName)) + goto out_fail; +- settings->ClientHostname[31] = 0; ++ + settings->ColorPointerFlag = TRUE; + settings->LargePointerFlag = (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384); + settings->PointerCacheSize = 20; +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c +index e18fea2..22c8af9 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm.c +@@ -22,6 +22,7 @@ + #endif + + #include ++#include + #include + #include + #include +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.h b/winpr/libwinpr/sspi/NTLM/ntlm.h +index d4db9eb..a9fe5c2 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm.h ++++ b/winpr/libwinpr/sspi/NTLM/ntlm.h +@@ -89,7 +89,7 @@ enum _NTLM_AV_ID + MsvAvTimestamp, + MsvAvSingleHost, + MsvAvTargetName, +- MsvChannelBindings ++ MsvAvChannelBindings + }; + typedef enum _NTLM_AV_ID NTLM_AV_ID; + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c +index 442b9fe..0a546d4 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c +@@ -37,6 +37,18 @@ + #include "../../log.h" + #define TAG WINPR_TAG("sspi.NTLM") + ++static wStream* Stream_StaticConstInit(wStream* buffer, const BYTE* data, size_t size) ++{ ++ Stream_StaticInit(buffer, data, size); ++ return buffer; ++} ++ ++static wStream* Stream_StaticInit2(wStream* buffer, BYTE* data, size_t size) ++{ ++ Stream_StaticInit(buffer, data, size); ++ return buffer; ++} ++ + static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' }; + + const char* ntlm_get_negotiate_string(UINT32 flag) +@@ -609,7 +621,7 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu + + *message = empty; + +- s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); ++ s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; +@@ -854,7 +866,7 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu + + *message = empty; + +- s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); ++ s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; +@@ -1172,7 +1184,7 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer + + *message = empty; + +- s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); ++ s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + + if (!s) + return SEC_E_INTERNAL_ERROR; diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1019-Updated-changelog.patch freerdp2-2.6.1+dfsg1/debian/patches/1019-Updated-changelog.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1019-Updated-changelog.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1019-Updated-changelog.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,21 @@ +From: Armin Novak +Date: Mon, 28 Mar 2022 12:09:24 +0200 +Subject: Updated changelog + +(cherry picked from commit 49780f6306da7f0dec670c125679a15dbc368d7b) +--- + ChangeLog | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ChangeLog b/ChangeLog +index 3e41b9f..14c8bd5 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,6 +1,7 @@ + # 2022-XX-YY Version 2.X.Y + + Noteworthy changes: ++* Backported various NTLM fixes + * Backported WINPR_ASSERT to ease future backports + + Fixed issues: diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1020-Fixed-missing-return-check.patch freerdp2-2.6.1+dfsg1/debian/patches/1020-Fixed-missing-return-check.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1020-Fixed-missing-return-check.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1020-Fixed-missing-return-check.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,24 @@ +From: Armin Novak +Date: Tue, 30 Nov 2021 08:52:31 +0100 +Subject: Fixed missing return check + +(cherry picked from commit 46c78cf0f07180258928c16e804aab8bca866a62) +(cherry picked from commit 311558c964626701bd19b2e216cbe85a5df25377) +--- + winpr/libwinpr/sspi/NTLM/ntlm.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c +index 22c8af9..98a130b 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm.c +@@ -604,6 +604,9 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( + { + status = ntlm_read_ChallengeMessage(context, input_buffer); + ++ if (status != SEC_I_CONTINUE_NEEDED) ++ return status; ++ + if (!pOutput) + return SEC_E_INVALID_TOKEN; + diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1021-Fixed-windows-build-_snpnrintf.patch freerdp2-2.6.1+dfsg1/debian/patches/1021-Fixed-windows-build-_snpnrintf.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1021-Fixed-windows-build-_snpnrintf.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1021-Fixed-windows-build-_snpnrintf.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,31 @@ +From: Armin Novak +Date: Mon, 28 Mar 2022 11:52:52 +0200 +Subject: Fixed windows build (_snpnrintf) + +(cherry picked from commit 6cccc95691ae015e9f30121a3d70f9286724413f) +(cherry picked from commit c8dced590560fcf7dda974d4216c48197ad86de2) +--- + winpr/libwinpr/sspi/NTLM/ntlm.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c +index 98a130b..372e6fb 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1293,7 +1294,7 @@ char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags) + if (!buffer || (size == 0)) + return buffer; + +- snprintf(buffer, size, "[0x%08" PRIx32 "] ", flags); ++ _snprintf(buffer, size, "[0x%08" PRIx32 "] ", flags); + + for (x = 0; x < 31; x++) + { diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1022-Fixed-missing-field-read.patch freerdp2-2.6.1+dfsg1/debian/patches/1022-Fixed-missing-field-read.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1022-Fixed-missing-field-read.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1022-Fixed-missing-field-read.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,57 @@ +From: Armin Novak +Date: Mon, 28 Mar 2022 12:58:19 +0200 +Subject: Fixed missing field read. + +(cherry picked from commit cb538114ed0e0739ccc6c65754462265ba1072ed) +(cherry picked from commit 5249f61b7235becd602fd68ef6a2dc8efd21a6f7) +--- + winpr/libwinpr/sspi/NTLM/ntlm_message.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c +index 0a546d4..ccb2e10 100644 +--- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c ++++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c +@@ -51,6 +51,8 @@ static wStream* Stream_StaticInit2(wStream* buffer, BYTE* data, size_t size) + + static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' }; + ++static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields); ++ + const char* ntlm_get_negotiate_string(UINT32 flag) + { + if (flag & NTLMSSP_NEGOTIATE_56) +@@ -322,6 +324,8 @@ static BOOL ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) + return FALSE; + } + ++ ntlm_free_message_fields_buffer(fields); ++ + Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */ + Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ + Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ +@@ -411,7 +415,7 @@ static BOOL ntlm_write_message_fields_buffer(wStream* s, const NTLM_MESSAGE_FIEL + return TRUE; + } + +-static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) ++void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) + { + if (fields) + { +@@ -1047,12 +1051,9 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer + if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ + goto fail; + +- if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) +- { +- if (!ntlm_read_message_fields_buffer( +- s, &(message->LmChallengeResponse))) /* LmChallengeResponse */ +- goto fail; +- } ++ if (!ntlm_read_message_fields_buffer(s, ++ &(message->LmChallengeResponse))) /* LmChallengeResponse */ ++ goto fail; + + if (!ntlm_read_message_fields_buffer(s, + &(message->NtChallengeResponse))) /* NtChallengeResponse */ diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1023-Fixed-7745-Progressive-surface-cleanup.patch freerdp2-2.6.1+dfsg1/debian/patches/1023-Fixed-7745-Progressive-surface-cleanup.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1023-Fixed-7745-Progressive-surface-cleanup.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1023-Fixed-7745-Progressive-surface-cleanup.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,134 @@ +From: Armin Novak +Date: Wed, 6 Apr 2022 10:10:07 +0200 +Subject: Fixed #7745: Progressive surface cleanup + +(cherry picked from commit edcb8284e79e1bf96e6e908f869b2d4985657cfa) +(cherry picked from commit a923f59c2023fcfc84751d836defe4cafbdcaac7) +--- + libfreerdp/codec/progressive.c | 50 ++++++++++++++---------------------------- + 1 file changed, 16 insertions(+), 34 deletions(-) + +diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c +index 5fc98f1..a9e39d2 100644 +--- a/libfreerdp/codec/progressive.c ++++ b/libfreerdp/codec/progressive.c +@@ -368,13 +368,11 @@ static INLINE PROGRESSIVE_SURFACE_CONTEXT* + progressive_get_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId) + { + void* key = (void*)(((ULONG_PTR)surfaceId) + 1); +- void* pData = NULL; + + if (!progressive) + return NULL; + +- pData = HashTable_GetItemValue(progressive->SurfaceContexts, key); +- return pData; ++ return HashTable_GetItemValue(progressive->SurfaceContexts, key); + } + + static void progressive_tile_free(RFX_PROGRESSIVE_TILE* tile) +@@ -387,10 +385,14 @@ static void progressive_tile_free(RFX_PROGRESSIVE_TILE* tile) + } + } + +-static void progressive_surface_context_free(PROGRESSIVE_SURFACE_CONTEXT* surface) ++static void progressive_surface_context_free(void* ptr) + { ++ PROGRESSIVE_SURFACE_CONTEXT* surface = ptr; + UINT32 index; + ++ if (!surface) ++ return; ++ + for (index = 0; index < surface->gridSize; index++) + { + RFX_PROGRESSIVE_TILE* tile = &(surface->tiles[index]); +@@ -610,13 +612,7 @@ INT32 progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT1 + + int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId) + { +- PROGRESSIVE_SURFACE_CONTEXT* surface = progressive_get_surface_data(progressive, surfaceId); +- +- if (surface) +- { +- progressive_set_surface_data(progressive, surfaceId, NULL); +- progressive_surface_context_free(surface); +- } ++ progressive_set_surface_data(progressive, surfaceId, NULL); + + return 1; + } +@@ -1111,7 +1107,7 @@ static INLINE INT16 progressive_rfx_srl_read(RFX_PROGRESSIVE_UPGRADE_STATE* stat + if (k) + { + bs->mask = ((1 << k) - 1); +- state->nz = ((bs->accumulator >> (32 - k)) & bs->mask); ++ state->nz = ((bs->accumulator >> (32u - k)) & bs->mask); + BitStream_Shift(bs, k); + } + +@@ -1663,6 +1659,9 @@ static void CALLBACK progressive_process_tiles_tile_work_callback(PTP_CALLBACK_I + { + PROGRESSIVE_TILE_PROCESS_WORK_PARAM* param = (PROGRESSIVE_TILE_PROCESS_WORK_PARAM*)context; + ++ WINPR_UNUSED(instance); ++ WINPR_UNUSED(work); ++ + switch (param->tile->blockType) + { + case PROGRESSIVE_WBT_TILE_SIMPLE: +@@ -2398,8 +2397,8 @@ INT32 progressive_decompress_ex(PROGRESSIVE_CONTEXT* progressive, const BYTE* pS + { + RECTANGLE_16 clippingRect; + const RFX_RECT* rect = &(region->rects[i]); +- clippingRect.left = nXDst + rect->x; +- clippingRect.top = nYDst + rect->y; ++ clippingRect.left = (UINT16)nXDst + rect->x; ++ clippingRect.top = (UINT16)nYDst + rect->y; + clippingRect.right = clippingRect.left + rect->width; + clippingRect.bottom = clippingRect.top + rect->height; + region16_union_rect(&clippingRects, &clippingRects, &clippingRect); +@@ -2742,6 +2741,8 @@ PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor) + if (!progressive_context_reset(progressive)) + goto fail; + ++ progressive->SurfaceContexts->valueFree = progressive_surface_context_free; ++ + return progressive; + fail: + progressive_context_free(progressive); +@@ -2750,11 +2751,6 @@ fail: + + void progressive_context_free(PROGRESSIVE_CONTEXT* progressive) + { +- int count; +- int index; +- ULONG_PTR* pKeys = NULL; +- PROGRESSIVE_SURFACE_CONTEXT* surface; +- + if (!progressive) + return; + +@@ -2763,21 +2759,7 @@ void progressive_context_free(PROGRESSIVE_CONTEXT* progressive) + rfx_context_free(progressive->rfx_context); + + BufferPool_Free(progressive->bufferPool); +- +- if (progressive->SurfaceContexts) +- { +- count = HashTable_GetKeys(progressive->SurfaceContexts, &pKeys); +- +- for (index = 0; index < count; index++) +- { +- surface = (PROGRESSIVE_SURFACE_CONTEXT*)HashTable_GetItemValue( +- progressive->SurfaceContexts, (void*)pKeys[index]); +- progressive_surface_context_free(surface); +- } +- +- free(pKeys); +- HashTable_Free(progressive->SurfaceContexts); +- } ++ HashTable_Free(progressive->SurfaceContexts); + + free(progressive); + } diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1024-Updated-changelog.patch freerdp2-2.6.1+dfsg1/debian/patches/1024-Updated-changelog.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1024-Updated-changelog.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1024-Updated-changelog.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,21 @@ +From: Armin Novak +Date: Wed, 6 Apr 2022 10:45:06 +0200 +Subject: Updated changelog + +(cherry picked from commit b836f72dedfdfc4d72441a82cb4810418faca83f) +--- + ChangeLog | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ChangeLog b/ChangeLog +index 14c8bd5..f051626 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -7,6 +7,7 @@ Noteworthy changes: + Fixed issues: + * Backported #6786: Use /network:auto by default + * Backported #7714: Workaround for broken surface frame marker ++* Backported #7745: GFX progressive double free + + Important notes: + diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1025-Urbrdc-fix-7417.patch freerdp2-2.6.1+dfsg1/debian/patches/1025-Urbrdc-fix-7417.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1025-Urbrdc-fix-7417.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1025-Urbrdc-fix-7417.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,335 @@ +From: Alexandru Bagu +Date: Wed, 3 Nov 2021 06:11:36 -0400 +Subject: Urbrdc fix (#7417) + +* fix libusb libusb_device usage (manually unref required usb devices, versus freeing all when we still hold references to the ones we want) +* disabled detach_kernel_driver & attach_kernel_driver on win32 since libusb does not support them +* fixed libusb async event handling + +* add log for transfer request error + +* Update libusb_udevice.c + +* refactor code + +(cherry picked from commit ce8616c0dc2773d4f3377a47e599849d1456cf03) +--- + channels/urbdrc/client/data_transfer.c | 7 ++ + channels/urbdrc/client/libusb/libusb_udevice.c | 129 ++++++++++++++----------- + channels/urbdrc/client/libusb/libusb_udevman.c | 10 +- + 3 files changed, 87 insertions(+), 59 deletions(-) + +diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c +index 9a44e6e..6987961 100644 +--- a/channels/urbdrc/client/data_transfer.c ++++ b/channels/urbdrc/client/data_transfer.c +@@ -1749,6 +1749,13 @@ static UINT urbdrc_process_transfer_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLB + break; + } + ++ if (error) ++ { ++ WLog_Print(urbdrc->log, WLOG_WARN, ++ "USB transfer request URB Function %08" PRIx32 " failed with %08" PRIx32, ++ URB_Function, error); ++ } ++ + return error; + } + +diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c +index aa69890..1322a4f 100644 +--- a/channels/urbdrc/client/libusb/libusb_udevice.c ++++ b/channels/urbdrc/client/libusb/libusb_udevice.c +@@ -490,17 +490,19 @@ static LIBUSB_DEVICE* udev_get_libusb_dev(libusb_context* context, uint8_t bus_n + + for (i = 0; i < total_device; i++) + { +- uint8_t cbus = libusb_get_bus_number(libusb_list[i]); +- uint8_t caddr = libusb_get_device_address(libusb_list[i]); +- +- if ((bus_number == cbus) && (dev_number == caddr)) ++ LIBUSB_DEVICE* dev = libusb_list[i]; ++ if ((bus_number == libusb_get_bus_number(dev)) && ++ (dev_number == libusb_get_device_address(dev))) + { +- device = libusb_list[i]; +- break; ++ device = dev; ++ } ++ else ++ { ++ libusb_unref_device(dev); + } + } + +- libusb_free_device_list(libusb_list, 1); ++ libusb_free_device_list(libusb_list, 0); + return device; + } + +@@ -522,7 +524,6 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB + return descriptor; + } + +- + static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting) + { + int error = 0, diff = 0; +@@ -1012,6 +1013,9 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev) + if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc) + return FALSE; + ++#ifdef _WIN32 ++ return TRUE; ++#else + urbdrc = pdev->urbdrc; + + if ((pdev->status & URBDRC_DEVICE_DETACH_KERNEL) == 0) +@@ -1032,6 +1036,7 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev) + } + + return TRUE; ++#endif + } + + static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev) +@@ -1048,12 +1053,14 @@ static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev) + + log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_release_interface", err); + ++#ifndef _WIN32 + if (err != LIBUSB_ERROR_NO_DEVICE) + { + err = libusb_attach_kernel_driver(pdev->libusb_handle, i); + log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_attach_kernel_driver if=%d", + err, i); + } ++#endif + } + + return TRUE; +@@ -1474,6 +1481,7 @@ static void udev_free(IUDEVICE* idev) + ArrayList_Free(udev->request_queue); + /* free the config descriptor that send from windows */ + msusb_msconfig_free(udev->MsConfig); ++ libusb_unref_device(udev->libusb_dev); + libusb_close(udev->libusb_handle); + libusb_close(udev->hub_handle); + free(udev->devDescriptor); +@@ -1522,8 +1530,8 @@ static void udev_load_interface(UDEVICE* pdev) + pdev->iface.free = udev_free; + } + +-static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, +- UINT16 bus_number, UINT16 dev_number) ++static int udev_get_device_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, ++ UINT16 bus_number, UINT16 dev_number) + { + int error; + ssize_t i, total_device; +@@ -1535,21 +1543,19 @@ static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVI + + for (i = 0; i < total_device; i++) + { +- LIBUSB_DEVICE_HANDLE* handle; +- uint8_t cbus = libusb_get_bus_number(libusb_list[i]); +- uint8_t caddr = libusb_get_device_address(libusb_list[i]); ++ LIBUSB_DEVICE* dev = libusb_list[i]; + +- if ((bus_number != cbus) || (dev_number != caddr)) ++ if ((bus_number != libusb_get_bus_number(dev)) || ++ (dev_number != libusb_get_device_address(dev))) + continue; + +- error = libusb_open(libusb_list[i], &handle); ++ error = libusb_open(dev, &pdev->libusb_handle); + + if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) + break; + + /* get port number */ +- error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers)); +- libusb_close(handle); ++ error = libusb_get_port_numbers(dev, port_numbers, sizeof(port_numbers)); + + if (error < 1) + { +@@ -1567,29 +1573,40 @@ static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVI + WLog_Print(urbdrc->log, WLOG_DEBUG, " DevPath: %s", pdev->path); + break; + } ++ libusb_free_device_list(libusb_list, 1); ++ ++ if (error < 0) ++ return -1; ++ return 0; ++} ++ ++static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, ++ UINT16 bus_number, UINT16 dev_number) ++{ ++ int error; ++ ssize_t i, total_device; ++ LIBUSB_DEVICE** libusb_list; ++ LIBUSB_DEVICE_HANDLE* handle; ++ total_device = libusb_get_device_list(ctx, &libusb_list); + + /* Look for device hub. */ +- if (error == 0) +- { +- error = -1; ++ error = -1; + +- for (i = 0; i < total_device; i++) +- { +- LIBUSB_DEVICE_HANDLE* handle; +- uint8_t cbus = libusb_get_bus_number(libusb_list[i]); +- uint8_t caddr = libusb_get_device_address(libusb_list[i]); ++ for (i = 0; i < total_device; i++) ++ { ++ LIBUSB_DEVICE* dev = libusb_list[i]; + +- if ((bus_number != cbus) || (1 != caddr)) /* Root hub allways first on bus. */ +- continue; ++ if ((bus_number != libusb_get_bus_number(dev)) || ++ (1 != libusb_get_device_address(dev))) /* Root hub allways first on bus. */ ++ continue; + +- WLog_Print(urbdrc->log, WLOG_DEBUG, " Open hub: %" PRIu16 "", bus_number); +- error = libusb_open(libusb_list[i], &handle); ++ WLog_Print(urbdrc->log, WLOG_DEBUG, " Open hub: %" PRIu16 "", bus_number); ++ error = libusb_open(dev, &handle); + +- if (!log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) +- pdev->hub_handle = handle; ++ if (!log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) ++ pdev->hub_handle = handle; + +- break; +- } ++ break; + } + + libusb_free_device_list(libusb_list, 1); +@@ -1640,30 +1657,26 @@ static IUDEVICE* udev_init(URBDRC_PLUGIN* urbdrc, libusb_context* context, LIBUS + if (urbdrc->listener_callback) + udev_set_channelManager(&pdev->iface, urbdrc->listener_callback->channel_mgr); + +- /* Get HUB handle */ +- status = udev_get_hub_handle(urbdrc, context, pdev, bus_number, dev_number); +- +- if (status < 0) +- pdev->hub_handle = NULL; +- ++ /* Get DEVICE handle */ ++ status = udev_get_device_handle(urbdrc, context, pdev, bus_number, dev_number); ++ if (status != LIBUSB_SUCCESS) + { + struct libusb_device_descriptor desc; +- const uint8_t bus = libusb_get_bus_number(pdev->libusb_dev); + const uint8_t port = libusb_get_port_number(pdev->libusb_dev); +- const uint8_t addr = libusb_get_device_address(pdev->libusb_dev); + libusb_get_device_descriptor(pdev->libusb_dev, &desc); + +- status = libusb_open(pdev->libusb_dev, &pdev->libusb_handle); +- +- if (status != LIBUSB_SUCCESS) +- { +- log_libusb_result(urbdrc->log, WLOG_ERROR, +- "libusb_open [b=0x%02X,p=0x%02X,a=0x%02X,VID=0x%04X,PID=0x%04X]", +- status, bus, port, addr, desc.idVendor, desc.idProduct); +- goto fail; +- } ++ log_libusb_result(urbdrc->log, WLOG_ERROR, ++ "libusb_open [b=0x%02X,p=0x%02X,a=0x%02X,VID=0x%04X,PID=0x%04X]", status, ++ bus_number, port, dev_number, desc.idVendor, desc.idProduct); ++ goto fail; + } + ++ /* Get HUB handle */ ++ status = udev_get_hub_handle(urbdrc, context, pdev, bus_number, dev_number); ++ ++ if (status < 0) ++ pdev->hub_handle = NULL; ++ + pdev->devDescriptor = udev_new_descript(urbdrc, pdev->libusb_dev); + + if (!pdev->devDescriptor) +@@ -1734,8 +1747,6 @@ size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendo + { + LIBUSB_DEVICE** libusb_list; + UDEVICE** array; +- UINT16 bus_number; +- UINT16 dev_number; + ssize_t i, total_device; + size_t num = 0; + +@@ -1752,23 +1763,27 @@ size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendo + + for (i = 0; i < total_device; i++) + { +- LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, libusb_list[i]); ++ LIBUSB_DEVICE* dev = libusb_list[i]; ++ LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, dev); + + if ((descriptor->idVendor == idVendor) && (descriptor->idProduct == idProduct)) + { +- bus_number = libusb_get_bus_number(libusb_list[i]); +- dev_number = libusb_get_device_address(libusb_list[i]); +- array[num] = (PUDEVICE)udev_init(urbdrc, ctx, libusb_list[i], bus_number, dev_number); ++ array[num] = (PUDEVICE)udev_init(urbdrc, ctx, dev, libusb_get_bus_number(dev), ++ libusb_get_device_address(dev)); + + if (array[num] != NULL) + num++; + } ++ else ++ { ++ libusb_unref_device(dev); ++ } + + free(descriptor); + } + + fail: +- libusb_free_device_list(libusb_list, 1); ++ libusb_free_device_list(libusb_list, 0); + *devArray = (IUDEVICE**)array; + return num; + } +diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c +index 1638b8c..edfe74f 100644 +--- a/channels/urbdrc/client/libusb/libusb_udevman.c ++++ b/channels/urbdrc/client/libusb/libusb_udevman.c +@@ -195,6 +195,12 @@ static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE + /* register all device that match pid vid */ + num = udev_new_by_id(urbdrc, udevman->context, idVendor, idProduct, &devArray); + ++ if (num == 0) ++ { ++ WLog_Print(urbdrc->log, WLOG_WARN, ++ "Could not find or redirect any usb devices by id %04x:%04x", idVendor, idProduct); ++ } ++ + for (i = 0; i < num; i++) + { + UINT32 id; +@@ -834,7 +840,7 @@ static BOOL poll_libusb_events(UDEVMAN* udevman) + { + int rc = LIBUSB_SUCCESS; + struct timeval tv = { 0, 500 }; +- if (libusb_try_lock_events(udevman->context)) ++ if (libusb_try_lock_events(udevman->context) == 0) + { + if (libusb_event_handling_ok(udevman->context)) + { +@@ -921,7 +927,7 @@ UINT freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS + udevman->next_device_id = BASE_USBDEVICE_NUM; + udevman->iface.plugin = pEntryPoints->plugin; + rc = libusb_init(&udevman->context); +- ++ + if (rc != LIBUSB_SUCCESS) + goto fail; + diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1026-Fix-7785-Missed-GatewayHttpUseWebsockets-initializat.patch freerdp2-2.6.1+dfsg1/debian/patches/1026-Fix-7785-Missed-GatewayHttpUseWebsockets-initializat.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1026-Fix-7785-Missed-GatewayHttpUseWebsockets-initializat.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1026-Fix-7785-Missed-GatewayHttpUseWebsockets-initializat.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,23 @@ +From: akallabeth +Date: Thu, 7 Apr 2022 09:50:04 +0200 +Subject: Fix #7785: Missed GatewayHttpUseWebsockets initialization + +In backport #6877 this was missed. + +(cherry picked from commit 9ab0667b5470cd16227a2212b57bfc7a71a31043) +--- + libfreerdp/core/settings.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c +index f4b5878..6a7b990 100644 +--- a/libfreerdp/core/settings.c ++++ b/libfreerdp/core/settings.c +@@ -488,6 +488,7 @@ rdpSettings* freerdp_settings_new(DWORD flags) + settings->GatewayRpcTransport = TRUE; + settings->GatewayHttpTransport = TRUE; + settings->GatewayUdpTransport = TRUE; ++ settings->GatewayHttpUseWebsockets = TRUE; + settings->FastPathInput = TRUE; + settings->FastPathOutput = TRUE; + settings->LongCredentialsSupported = TRUE; diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/1027-Fixed-FFMPEG-detection-without-pkgconfig.patch freerdp2-2.6.1+dfsg1/debian/patches/1027-Fixed-FFMPEG-detection-without-pkgconfig.patch --- freerdp2-2.6.1+dfsg1/debian/patches/1027-Fixed-FFMPEG-detection-without-pkgconfig.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/1027-Fixed-FFMPEG-detection-without-pkgconfig.patch 2022-04-11 14:33:33.000000000 +0000 @@ -0,0 +1,36 @@ +From: Armin Novak +Date: Tue, 20 Jul 2021 10:57:28 +0200 +Subject: Fixed FFMPEG detection without pkgconfig + +(cherry picked from commit 2c31c367598863d73c3c5cc3a8b93bfebe2dfb60) +(cherry picked from commit 2b65b7cb123cc5c9950aa1bf4a136dae63349951) +--- + cmake/FindFFmpeg.cmake | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake +index 78d9bf6..ffa1641 100644 +--- a/cmake/FindFFmpeg.cmake ++++ b/cmake/FindFFmpeg.cmake +@@ -27,12 +27,20 @@ find_library(AVUTIL_LIBRARY avutil PATHS ${AVUTIL_LIBRARY_DIRS}) + + # swresample + find_path(SWRESAMPLE_INCLUDE_DIR libswresample/swresample.h PATHS ${SWRESAMPLE_INCLUDE_DIRS}) +-find_library(SWRESAMPLE_LIBRARY swresample PATHS ${SWRESAMPLE_LIBRARY_DIRS}) ++find_library(SWRESAMPLE_LIBRARY NAMES swresample swresample-3 PATHS ${SWRESAMPLE_LIBRARY_DIRS}) ++ ++if (SWRESAMPLE_INCLUDE_DIR AND SWRESAMPLE_LIBRARY) ++ set(SWRESAMPLE_FOUND ON) ++endif() + + # avresample + find_path(AVRESAMPLE_INCLUDE_DIR libavresample/avresample.h PATHS ${AVRESAMPLE_INCLUDE_DIRS}) + find_library(AVRESAMPLE_LIBRARY avresample PATHS ${AVRESAMPLE_LIBRARY_DIRS}) + ++if (AVRESAMPLE_INCLUDE_DIR AND AVRESAMPLE_LIBRARY) ++ set(AVRESAMPLE_FOUND ON) ++endif() ++ + if (AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY) + set(AVCODEC_FOUND TRUE) + endif(AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY) diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/README freerdp2-2.6.1+dfsg1/debian/patches/README --- freerdp2-2.6.1+dfsg1/debian/patches/README 2022-02-26 20:44:18.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -0xxx: Grabbed from upstream development. -1xxx: Possibly relevant for upstream adoption. -2xxx: Only relevant for official Debian release. diff -Nru freerdp2-2.6.1+dfsg1/debian/patches/series freerdp2-2.6.1+dfsg1/debian/patches/series --- freerdp2-2.6.1+dfsg1/debian/patches/series 2022-03-08 07:24:05.000000000 +0000 +++ freerdp2-2.6.1+dfsg1/debian/patches/series 2022-04-11 14:33:33.000000000 +0000 @@ -1 +1,27 @@ 1001_keep-symbol-DumpThreadHandles-if-debugging-is-disabled.patch +1002-Added-more-log-messages-for-SurfaceCommand-failures.patch +1003-rfx_process_message-verbose-error-log.patch +1004-Implemented-4341-Default-to-network-auto.patch +1005-Workaround-for-MS-RDPBCGR-2.2.9.2.3-Frame-Marker-Com.patch +1006-Changelog.patch +1007-Added-WINPR_ASSERT.patch +1008-Added-option-do-disable-WINPR_ASSERT.patch +1009-Improve-WINPR_ASSERT-log-backtrace.patch +1010-Fixed-warnings-from-WLOG_ASSERT.patch +1011-Removed-cached-wlog-pointer.patch +1012-Replaced-WINPR_ASSERT-defines-use-include.patch +1013-Updated-changelog.patch +1014-Use-GetComputerName-instead-of-gethostname.patch +1015-Refactored-WinPR-NTLM.patch +1016-Removed-unnecessary-assert.patch +1017-Fixed-NTLM-flag-handling.patch +1018-Fixed-backport-compile-problems.patch +1019-Updated-changelog.patch +1020-Fixed-missing-return-check.patch +1021-Fixed-windows-build-_snpnrintf.patch +1022-Fixed-missing-field-read.patch +1023-Fixed-7745-Progressive-surface-cleanup.patch +1024-Updated-changelog.patch +1025-Urbrdc-fix-7417.patch +1026-Fix-7785-Missed-GatewayHttpUseWebsockets-initializat.patch +1027-Fixed-FFMPEG-detection-without-pkgconfig.patch