[arch-commits] Commit in freerdp/repos/community-x86_64 (5 files)

Jan Steffens heftig at gemini.archlinux.org
Fri Apr 22 12:14:11 UTC 2022


    Date: Friday, April 22, 2022 @ 12:14:10
  Author: heftig
Revision: 1187303

archrelease: copy trunk to community-x86_64

Added:
  freerdp/repos/community-x86_64/0001-Merge-stable-2.0.patch
    (from rev 1187302, freerdp/trunk/0001-Merge-stable-2.0.patch)
  freerdp/repos/community-x86_64/PKGBUILD
    (from rev 1187302, freerdp/trunk/PKGBUILD)
  freerdp/repos/community-x86_64/freerdp-2.0.0-manpage_formatting.patch
    (from rev 1187302, freerdp/trunk/freerdp-2.0.0-manpage_formatting.patch)
Deleted:
  freerdp/repos/community-x86_64/PKGBUILD
  freerdp/repos/community-x86_64/freerdp-2.0.0-manpage_formatting.patch

----------------------------------------+
 0001-Merge-stable-2.0.patch            | 5555 +++++++++++++++++++++++++++++++
 PKGBUILD                               |  143 
 freerdp-2.0.0-manpage_formatting.patch |   24 
 3 files changed, 5642 insertions(+), 80 deletions(-)

Copied: freerdp/repos/community-x86_64/0001-Merge-stable-2.0.patch (from rev 1187302, freerdp/trunk/0001-Merge-stable-2.0.patch)
===================================================================
--- 0001-Merge-stable-2.0.patch	                        (rev 0)
+++ 0001-Merge-stable-2.0.patch	2022-04-22 12:14:10 UTC (rev 1187303)
@@ -0,0 +1,5555 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: "Jan Alexander Steffens (heftig)" <heftig at archlinux.org>
+Date: Fri, 22 Apr 2022 12:07:48 +0000
+Subject: [PATCH] Merge stable-2.0
+
+Squashed commit of the following:
+
+commit 70bd7f010f90be41ccadf8c2649536848a0e87e0
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Thu Jul 29 15:20:20 2021 +0200
+
+    Update default android build config
+
+    Remove x86 and x86_64 to bring down pr build times
+
+    (cherry picked from commit 7e7394d905d70b55de7594c01ff110a73a3aae23)
+
+commit e8010231c8e491ea236385a755b7d0607102fe20
+Author: akallabeth <akallabeth at posteo.net>
+Date:   Fri Apr 22 10:17:54 2022 +0200
+
+    Changelog
+
+commit 4308d8e91e77b95c1c7a71edf06382b760936b51
+Author: 2fly2 <wjatchd at 163.com>
+Date:   Fri Apr 22 11:18:26 2022 +0800
+
+    fix x11 black RAIL window when connect to server 2019
+
+    Signed-off-by: 2fly2 <wjatchd at 163.com>
+    (cherry picked from commit cb66a4c0df5f46f7f7d27d1673996dac51edd6e1)
+
+commit 66ff8cf2adc2851a94e7a22f2e40ca30c332d7b1
+Author: Steve Pronovost <spronovo at microsoft.com>
+Date:   Sat Oct 16 11:55:46 2021 -0700
+
+    Added support for AUDIO_PLAYBACK_DVC
+
+    Support audio on dynamic channel. Please refer to MS-RDPEA.
+
+commit f773d9759d6b00af3099f4665253fc6021f8ee41
+Author: Steve Pronovost <spronovo at microsoft.com>
+Date:   Sat Oct 16 11:53:05 2021 -0700
+
+    Update header with missing flag
+
+    Added definition for TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED.
+
+commit 0a6b999c5655d07b5653894b24a840c08838e304
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Apr 19 14:45:59 2022 +0200
+
+    Updated Changelog
+
+commit 0f9efe19720ff8d56589d8ae0b34ba04a07b6d1c
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Apr 19 14:35:50 2022 +0200
+
+    Fixed /gt:xxx settings
+
+    * Disable websocket support with RPC
+    * Use settings getter/setter
+
+    (cherry picked from commit 882b91d98671fd072e96889587f4b98cc2ce4ff5)
+
+commit 62937807eec969e36958bbc5a64534595e9925fd
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Apr 19 08:38:09 2022 +0200
+
+    Changelog
+
+commit 572c63a9f1880bbdff323192eef560bd52d66600
+Author: Kazuki Oikawa <k at oikw.org>
+Date:   Sat Mar 19 21:19:41 2022 +0900
+
+    Supports 10bit X11 color (BGRX32 only)
+
+    (cherry picked from commit 8a86a4e8d98a26b7724640081302c7596e962a6e)
+
+commit 2b65b7cb123cc5c9950aa1bf4a136dae63349951
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Jul 20 10:57:28 2021 +0200
+
+    Fixed FFMPEG detection without pkgconfig
+
+    (cherry picked from commit 2c31c367598863d73c3c5cc3a8b93bfebe2dfb60)
+
+commit 9ab0667b5470cd16227a2212b57bfc7a71a31043
+Author: akallabeth <akallabeth at posteo.net>
+Date:   Thu Apr 7 09:50:04 2022 +0200
+
+    Fix #7785: Missed GatewayHttpUseWebsockets initialization
+
+    In backport #6877 this was missed.
+
+commit ce8616c0dc2773d4f3377a47e599849d1456cf03
+Author: Alexandru Bagu <alexandru.bagu at gmail.com>
+Date:   Wed Nov 3 06:11:36 2021 -0400
+
+    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
+
+commit b836f72dedfdfc4d72441a82cb4810418faca83f
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Wed Apr 6 10:45:06 2022 +0200
+
+    Updated changelog
+
+commit a923f59c2023fcfc84751d836defe4cafbdcaac7
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Wed Apr 6 10:10:07 2022 +0200
+
+    Fixed #7745: Progressive surface cleanup
+
+    (cherry picked from commit edcb8284e79e1bf96e6e908f869b2d4985657cfa)
+
+commit 5249f61b7235becd602fd68ef6a2dc8efd21a6f7
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Mon Mar 28 12:58:19 2022 +0200
+
+    Fixed missing field read.
+
+    (cherry picked from commit cb538114ed0e0739ccc6c65754462265ba1072ed)
+
+commit c8dced590560fcf7dda974d4216c48197ad86de2
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Mon Mar 28 11:52:52 2022 +0200
+
+    Fixed windows build (_snpnrintf)
+
+    (cherry picked from commit 6cccc95691ae015e9f30121a3d70f9286724413f)
+
+commit 311558c964626701bd19b2e216cbe85a5df25377
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Nov 30 08:52:31 2021 +0100
+
+    Fixed missing return check
+
+    (cherry picked from commit 46c78cf0f07180258928c16e804aab8bca866a62)
+
+commit 49780f6306da7f0dec670c125679a15dbc368d7b
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Mon Mar 28 12:09:24 2022 +0200
+
+    Updated changelog
+
+commit 061edc109fb1a4e161094adc6915eae84801611c
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Mon Mar 28 12:08:59 2022 +0200
+
+    Fixed backport compile problems
+
+commit 269ebb8cada3fef6b6cabfa5a1ea98ff4abbb99e
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Mon Mar 28 10:32:08 2022 +0200
+
+    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)
+
+commit 34e851209a742a67604191759730bef3c332ebcd
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Mar 22 09:51:08 2022 +0100
+
+    Removed unnecessary assert
+
+    (cherry picked from commit 4b1427639a9e29f911d92c0f33175e191cd5a503)
+
+commit f1d9faa7fc30ae42f722047550c489690ff87049
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Mon Mar 14 14:50:32 2022 +0100
+
+    Refactored WinPR::NTLM
+
+    * added assertions
+    * added log messages
+    * removed code duplication
+
+    (cherry picked from commit 813966da1a44acff1385de058dd89a8be93d2d1c)
+
+commit c6bd48f9265da174863861a1289aba5ef7d8eb7e
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Mar 15 15:19:41 2022 +0100
+
+    Use GetComputerName instead of gethostname
+
+    (cherry picked from commit 82165d95a925a775f2f895518dba8ff6f1a732d1)
+
+commit 732e94628945c2c218968c80b3a7a041b0b8a6e9
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Mon Mar 28 11:34:24 2022 +0200
+
+    Updated changelog
+
+commit 2008751c04bc7b51c8737f161c09ad17ae56838e
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Mon Mar 28 11:33:38 2022 +0200
+
+    Replaced WINPR_ASSERT defines, use include
+
+commit 0089ce25b48535e081e9680bf4f2bb9d7e0d0534
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Feb 1 11:49:12 2022 +0100
+
+    Removed cached wlog pointer
+
+    (cherry picked from commit 77580466ae31c93af63c55e4cb56b297c01093f3)
+
+commit e675ffcb35e3211b9424c8a067494057b803b935
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Feb 1 08:17:43 2022 +0100
+
+    Fixed warnings from WLOG_ASSERT
+
+    (cherry picked from commit 02896b0656de693a7014cc8ca6ff12de1d9ffabd)
+
+commit 83dffd0009b4d8b7b241c621b6aff4efe12a0380
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Wed Jun 16 13:11:07 2021 +0200
+
+    Improve WINPR_ASSERT, log backtrace
+
+    (cherry picked from commit 9e94f1dace7295e506e01b9ece59d77f62343e3c)
+
+commit f522bcb63a8d2f272b1f50f5ba19617345f55259
+Author: akallabeth <akallabeth at posteo.net>
+Date:   Thu Jun 10 08:57:40 2021 +0200
+
+    Added option do disable WINPR_ASSERT
+
+    (cherry picked from commit 3a75228242401de96eaf66222e77a72a40dc3b40)
+
+commit 76660aab19020f45d398fe42100351960ad40bb2
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Wed Jun 9 13:05:33 2021 +0200
+
+    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)
+
+commit 1c91d66a50b2f3f602765fddd1ed2767c427a8fe
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Wed Mar 9 15:35:47 2022 +0100
+
+    Changelog
+
+commit 6462eca724a886e8c1abb5b41955108023d1c1e6
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Wed Mar 9 09:01:11 2022 +0100
+
+    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)
+
+commit baf35cece9ff369d27deae1fed23d56907d82c31
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Thu Jul 29 13:26:05 2021 +0200
+
+    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)
+
+commit 79207e6700e83ffcbd707985086bb3a6dc06dfb9
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Mar 8 15:21:23 2022 +0100
+
+    rfx_process_message verbose error log
+
+    (cherry picked from commit c194a68b1bb44af3a180d7bdad678655bd673dc9)
+
+commit 631e71bebd041fbac2932555f17de050f6def91f
+Author: Armin Novak <armin.novak at thincast.com>
+Date:   Tue Mar 8 15:01:09 2022 +0100
+
+    Added more log messages for SurfaceCommand failures
+
+    (cherry picked from commit c6f204091291990f85c23450778fcab35571eed5)
+---
+ ChangeLog                                     |   20 +-
+ channels/ainput/client/ainput_main.c          |    4 +-
+ channels/ainput/server/ainput_main.c          |    4 +-
+ channels/rdpdr/client/rdpdr_main.c            |    6 +-
+ channels/rdpgfx/rdpgfx_common.c               |    4 +-
+ channels/rdpsnd/server/rdpsnd_main.c          |   36 +-
+ channels/rdpsnd/server/rdpsnd_main.h          |    1 +
+ channels/urbdrc/client/data_transfer.c        |    7 +
+ .../urbdrc/client/libusb/libusb_udevice.c     |  131 +-
+ .../urbdrc/client/libusb/libusb_udevman.c     |   10 +-
+ client/X11/xf_client.c                        |    5 +-
+ client/X11/xf_graphics.c                      |    2 +
+ client/common/cmdline.c                       |   51 +-
+ cmake/FindFFmpeg.cmake                        |   10 +-
+ include/freerdp/codec/color.h                 |   21 +
+ include/freerdp/rail.h                        |    1 +
+ include/freerdp/server/rdpsnd.h               |    3 +
+ libfreerdp/codec/h264_mediacodec.c            |    4 +-
+ libfreerdp/codec/progressive.c                |   54 +-
+ libfreerdp/codec/rfx.c                        |    7 +
+ libfreerdp/core/settings.c                    |    7 +-
+ libfreerdp/core/surface.c                     |   51 +-
+ libfreerdp/core/utils.c                       |    4 +-
+ scripts/android-build.conf                    |    2 +-
+ winpr/CMakeLists.txt                          |    6 +
+ winpr/include/winpr/assert.h                  |   59 +
+ winpr/libwinpr/registry/registry_reg.c        |    4 +-
+ winpr/libwinpr/sspi/NTLM/ntlm.c               |  256 +++-
+ winpr/libwinpr/sspi/NTLM/ntlm.h               |   20 +-
+ 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       |  469 ++++---
+ winpr/libwinpr/sspi/NTLM/ntlm_compute.h       |   31 +-
+ winpr/libwinpr/sspi/NTLM/ntlm_message.c       | 1169 +++++++++++------
+ winpr/libwinpr/sspi/NTLM/ntlm_message.h       |    8 +-
+ winpr/libwinpr/sspi/test/TestNTLM.c           |   19 +-
+ winpr/libwinpr/sspicli/sspicli.c              |    4 +-
+ 37 files changed, 1682 insertions(+), 877 deletions(-)
+ create mode 100644 winpr/include/winpr/assert.h
+
+diff --git a/ChangeLog b/ChangeLog
+index 5d32697b6b12..073283f413d7 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -1,7 +1,25 @@
++# 2022-XX-YY Version 2.X.Y
++
++Noteworthy changes:
++* Backported various NTLM fixes
++* Backported WINPR_ASSERT to ease future backports
++
++Fixed issues:
++* Backported #6786: Use /network:auto by default
++* Backported #7714: Workaround for broken surface frame marker
++* Backported #7733: Support 10bit X11 color (BGRX32 only)
++* Backported #7745: GFX progressive double free
++* Backported #7808: Disable websockets with /gt:rpc
++* Backported #7815: RAIL expect LOGON_MSG_SESSION_CONTINUE
++
++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 --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c
+index bf4ce2644d1b..d8eb8ec594b6 100644
+--- a/channels/ainput/client/ainput_main.c
++++ b/channels/ainput/client/ainput_main.c
+@@ -26,19 +26,17 @@
+ #include <stdlib.h>
+ 
+ #include <winpr/crt.h>
+-#include <assert.h>
++#include <winpr/assert.h>
+ #include <winpr/stream.h>
+ #include <winpr/sysinfo.h>
+ 
+ #include "ainput_main.h"
+ #include <freerdp/channels/log.h>
+ #include <freerdp/client/ainput.h>
+ #include <freerdp/channels/ainput.h>
+ 
+ #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 670b668726a3..bc1737ee1846 100644
+--- a/channels/ainput/server/ainput_main.c
++++ b/channels/ainput/server/ainput_main.c
+@@ -27,20 +27,18 @@
+ #include <string.h>
+ 
+ #include <winpr/crt.h>
+-#include <assert.h>
++#include <winpr/assert.h>
+ #include <winpr/synch.h>
+ #include <winpr/thread.h>
+ #include <winpr/stream.h>
+ #include <winpr/sysinfo.h>
+ 
+ #include <freerdp/server/ainput.h>
+ #include <freerdp/channels/ainput.h>
+ #include <freerdp/channels/log.h>
+ 
+ #include "../common/ainput_common.h"
+ 
+-#define WINPR_ASSERT(x) assert(x)
+-
+ #define TAG CHANNELS_TAG("ainput.server")
+ 
+ typedef enum
+diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c
+index 309d24c74bc8..681ebced990e 100644
+--- a/channels/rdpdr/client/rdpdr_main.c
++++ b/channels/rdpdr/client/rdpdr_main.c
+@@ -31,6 +31,7 @@
+ #include <string.h>
+ 
+ #include <winpr/crt.h>
++#include <winpr/sysinfo.h>
+ #include <winpr/stream.h>
+ 
+ #include <winpr/sspicli.h>
+@@ -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/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c
+index c0bc0b08f952..03fc97c1226b 100644
+--- a/channels/rdpgfx/rdpgfx_common.c
++++ b/channels/rdpgfx/rdpgfx_common.c
+@@ -24,12 +24,10 @@
+ #endif
+ 
+ #include <winpr/crt.h>
+-#include <assert.h>
++#include <winpr/assert.h>
+ #include <winpr/stream.h>
+ #include <freerdp/channels/log.h>
+ 
+-#define WINPR_ASSERT(x) assert(x)
+-
+ #define TAG CHANNELS_TAG("rdpgfx.common")
+ 
+ #include "rdpgfx_common.h"
+diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c
+index be0ca149f33b..537aef66697f 100644
+--- a/channels/rdpsnd/server/rdpsnd_main.c
++++ b/channels/rdpsnd/server/rdpsnd_main.c
+@@ -673,12 +673,40 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context)
+ 	DWORD bytesReturned;
+ 	RdpsndServerPrivate* priv = context->priv;
+ 	UINT error = ERROR_INTERNAL_ERROR;
+-	priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd");
++	PULONG pSessionId = NULL;
+ 
+-	if (!priv->ChannelHandle)
++	priv->SessionId = WTS_CURRENT_SESSION;
++
++	if (context->use_dynamic_virtual_channel)
+ 	{
+-		WLog_ERR(TAG, "WTSVirtualChannelOpen failed!");
+-		return ERROR_INTERNAL_ERROR;
++		if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
++		                                (LPSTR*)&pSessionId, &bytesReturned))
++		{
++			priv->SessionId = (DWORD)*pSessionId;
++			WTSFreeMemory(pSessionId);
++			priv->ChannelHandle = (HANDLE)WTSVirtualChannelOpenEx(
++			    priv->SessionId, "AUDIO_PLAYBACK_DVC", WTS_CHANNEL_OPTION_DYNAMIC);
++			if (!priv->ChannelHandle)
++			{
++				WLog_ERR(TAG, "Open audio dynamic virtual channel (AUDIO_PLAYBACK_DVC) failed!");
++				return ERROR_INTERNAL_ERROR;
++			}
++		}
++		else
++		{
++			WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
++			return ERROR_INTERNAL_ERROR;
++		}
++	}
++	else
++	{
++		priv->ChannelHandle =
++		    WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd");
++		if (!priv->ChannelHandle)
++		{
++			WLog_ERR(TAG, "Open audio static virtual channel (rdpsnd) failed!");
++			return ERROR_INTERNAL_ERROR;
++		}
+ 	}
+ 
+ 	if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
+diff --git a/channels/rdpsnd/server/rdpsnd_main.h b/channels/rdpsnd/server/rdpsnd_main.h
+index f058abbc71ba..9849273ea4d0 100644
+--- a/channels/rdpsnd/server/rdpsnd_main.h
++++ b/channels/rdpsnd/server/rdpsnd_main.h
+@@ -39,6 +39,7 @@ struct _rdpsnd_server_private
+ 	HANDLE StopEvent;
+ 	HANDLE channelEvent;
+ 	void* ChannelHandle;
++	DWORD SessionId;
+ 
+ 	BOOL waitingHeader;
+ 	DWORD expectedBytes;
+diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c
+index 9a44e6e09116..698796126922 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 aa69890aed8d..1322a4f3902c 100644
+--- a/channels/urbdrc/client/libusb/libusb_udevice.c
++++ b/channels/urbdrc/client/libusb/libusb_udevice.c
+@@ -490,39 +490,40 @@ 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;
+ }
+ 
+ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB_DEVICE* libusb_dev)
+ {
+ 	int ret;
+ 	LIBUSB_DEVICE_DESCRIPTOR* descriptor =
+ 	    (LIBUSB_DEVICE_DESCRIPTOR*)calloc(1, sizeof(LIBUSB_DEVICE_DESCRIPTOR));
+ 	if (!descriptor)
+ 		return NULL;
+ 	ret = libusb_get_device_descriptor(libusb_dev, descriptor);
+ 
+ 	if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_get_device_descriptor", ret))
+ 	{
+ 		free(descriptor);
+ 		return NULL;
+ 	}
+ 
+ 	return descriptor;
+ }
+ 
+-
+ static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting)
+ {
+ 	int error = 0, diff = 0;
+@@ -1012,48 +1013,54 @@ 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)
+ 	{
+ 		for (i = 0; i < pdev->LibusbConfig->bNumInterfaces; i++)
+ 		{
+ 			err = libusb_kernel_driver_active(pdev->libusb_handle, i);
+ 			log_libusb_result(urbdrc->log, WLOG_DEBUG, "libusb_kernel_driver_active", err);
+ 
+ 			if (err)
+ 			{
+ 				err = libusb_detach_kernel_driver(pdev->libusb_handle, i);
+ 				log_libusb_result(urbdrc->log, WLOG_DEBUG, "libusb_detach_kernel_driver", err);
+ 			}
+ 		}
+ 
+ 		pdev->status |= URBDRC_DEVICE_DETACH_KERNEL;
+ 	}
+ 
+ 	return TRUE;
++#endif
+ }
+ 
+ static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev)
+ {
+ 	int i, err = 0;
+ 	UDEVICE* pdev = (UDEVICE*)idev;
+ 
+ 	if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc)
+ 		return FALSE;
+ 
+ 	for (i = 0; i < pdev->LibusbConfig->bNumInterfaces && err != LIBUSB_ERROR_NO_DEVICE; i++)
+ 	{
+ 		err = libusb_release_interface(pdev->libusb_handle, i);
+ 
+ 		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,74 +1530,83 @@ 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;
+ 	uint8_t port_numbers[16];
+ 	LIBUSB_DEVICE** libusb_list;
+ 	total_device = libusb_get_device_list(ctx, &libusb_list);
+ 	/* Look for device. */
+ 	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]);
++		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)
+ 		{
+ 			/* Prevent open hub, treat as error. */
+ 			log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_get_port_numbers", error);
+ 			break;
+ 		}
+ 
+ 		pdev->port_number = port_numbers[(error - 1)];
+ 		error = 0;
+ 		WLog_Print(urbdrc->log, WLOG_DEBUG, "  Port: %d", pdev->port_number);
+ 		/* gen device path */
+ 		sprintf(pdev->path, "%" PRIu16 "-%" PRIu16 "", bus_number, pdev->port_number);
+ 
+ 		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;
++
++	for (i = 0; i < total_device; i++)
+ 	{
+-		error = -1;
++		LIBUSB_DEVICE* dev = libusb_list[i];
+ 
+-		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]);
++		if ((bus_number != libusb_get_bus_number(dev)) ||
++		    (1 != libusb_get_device_address(dev))) /* Root hub allways first on bus. */
++			continue;
+ 
+-			if ((bus_number != cbus) || (1 != caddr)) /* Root hub allways first on bus. */
+-				continue;
++		WLog_Print(urbdrc->log, WLOG_DEBUG, "  Open hub: %" PRIu16 "", bus_number);
++		error = libusb_open(dev, &handle);
+ 
+-			WLog_Print(urbdrc->log, WLOG_DEBUG, "  Open hub: %" PRIu16 "", bus_number);
+-			error = libusb_open(libusb_list[i], &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 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 port = libusb_get_port_number(pdev->libusb_dev);
++		libusb_get_device_descriptor(pdev->libusb_dev, &desc);
++
++		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;
+ 
+-	{
+-		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;
+-		}
+-	}
+-
+ 	pdev->devDescriptor = udev_new_descript(urbdrc, pdev->libusb_dev);
+ 
+ 	if (!pdev->devDescriptor)
+@@ -1734,41 +1747,43 @@ 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;
+ 
+ 	if (!urbdrc || !devArray)
+ 		return 0;
+ 
+ 	WLog_Print(urbdrc->log, WLOG_INFO, "VID: 0x%04" PRIX16 ", PID: 0x%04" PRIX16 "", idVendor,
+ 	           idProduct);
+ 	total_device = libusb_get_device_list(ctx, &libusb_list);
+ 	array = (UDEVICE**)calloc(total_device, sizeof(UDEVICE*));
+ 
+ 	if (!array)
+ 		goto fail;
+ 
+ 	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 1638b8c13f2f..edfe74f415d6 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 --git a/client/X11/xf_client.c b/client/X11/xf_client.c
+index 24a03d488b8d..c2704a4b1291 100644
+--- a/client/X11/xf_client.c
++++ b/client/X11/xf_client.c
+@@ -1384,7 +1384,10 @@ static int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
+ 	const char* str_data = freerdp_get_logon_error_info_data(data);
+ 	const char* str_type = freerdp_get_logon_error_info_type(type);
+ 	WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type);
+-	xf_rail_disable_remoteapp_mode(xfc);
++	if(type != LOGON_MSG_SESSION_CONTINUE)
++	{
++	    xf_rail_disable_remoteapp_mode(xfc);
++	}
+ 	return 1;
+ }
+ 
+diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c
+index 8de32c5572a7..11c6d59b1923 100644
+--- a/client/X11/xf_graphics.c
++++ b/client/X11/xf_graphics.c
+@@ -729,6 +729,8 @@ UINT32 xf_get_local_color_format(xfContext* xfc, BOOL aligned)
+ 
+ 	if (xfc->depth == 32)
+ 		DstFormat = (!invert) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_BGRA32;
++	else if (xfc->depth == 30)
++		DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32_DEPTH30 : PIXEL_FORMAT_BGRX32_DEPTH30;
+ 	else if (xfc->depth == 24)
+ 	{
+ 		if (aligned)
+diff --git a/client/common/cmdline.c b/client/common/cmdline.c
+index 15d4813871f2..77fcf81849d9 100644
+--- a/client/common/cmdline.c
++++ b/client/common/cmdline.c
+@@ -24,28 +24,30 @@
+ #endif
+ 
+ #include <ctype.h>
+-#include <assert.h>
+ #include <errno.h>
+ 
++#include <winpr/assert.h>
++
+ #include <winpr/crt.h>
+ #include <winpr/wlog.h>
+ #include <winpr/path.h>
+ 
+ #include <freerdp/addin.h>
+ #include <freerdp/settings.h>
+ #include <freerdp/client/channels.h>
+ #include <freerdp/crypto/crypto.h>
+ #include <freerdp/locale/keyboard.h>
+ #include <freerdp/utils/passphrase.h>
+ #include <freerdp/channels/urbdrc.h>
+ 
+ #include <freerdp/client/cmdline.h>
+ #include <freerdp/version.h>
+ 
+ #include "compatibility.h"
+ #include "cmdline.h"
+ 
+ #include <freerdp/log.h>
++
+ #define TAG CLIENT_TAG("common.cmdline")
+ 
+ static BOOL freerdp_client_print_codepages(const char* arg)
+@@ -1567,6 +1569,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 +1661,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");
+@@ -2265,31 +2291,36 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
+ 		{
+ 			if (_stricmp(arg->Value, "rpc") == 0)
+ 			{
+-				settings->GatewayRpcTransport = TRUE;
+-				settings->GatewayHttpTransport = FALSE;
++				if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) ||
++				    !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, FALSE) ||
++				    !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE))
++					return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
+ 			}
+ 			else
+ 			{
+ 				char* c = strchr(arg->Value, ',');
+ 				if (c)
+ 				{
+ 					*c++ = '\0';
+ 					if (_stricmp(c, "no-websockets") != 0)
+-					{
+ 						return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
+-					}
+-					freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE);
++
++					if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets,
++					                               FALSE))
++						return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
+ 				}
+ 
+ 				if (_stricmp(arg->Value, "http") == 0)
+ 				{
+-					settings->GatewayRpcTransport = FALSE;
+-					settings->GatewayHttpTransport = TRUE;
++					if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, FALSE) ||
++					    !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE))
++						return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
+ 				}
+ 				else if (_stricmp(arg->Value, "auto") == 0)
+ 				{
+-					settings->GatewayRpcTransport = TRUE;
+-					settings->GatewayHttpTransport = TRUE;
++					if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) ||
++					    !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE))
++						return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
+ 				}
+ 			}
+ 		}
+diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake
+index 78d9bf6ab1e2..ffa16412accd 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 --git a/include/freerdp/codec/color.h b/include/freerdp/codec/color.h
+index 42cb104d1c61..5d3e27904780 100644
+--- a/include/freerdp/codec/color.h
++++ b/include/freerdp/codec/color.h
+@@ -68,6 +68,8 @@
+ #define PIXEL_FORMAT_BGRX32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_BGRA, 0, 8, 8, 8)
+ #define PIXEL_FORMAT_RGBA32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 8, 8, 8, 8)
+ #define PIXEL_FORMAT_RGBX32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 0, 8, 8, 8)
++#define PIXEL_FORMAT_BGRX32_DEPTH30 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_BGRA, 0, 10, 10, 10)
++#define PIXEL_FORMAT_RGBX32_DEPTH30 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 0, 10, 10, 10)
+ 
+ /* 24bpp formats */
+ #define PIXEL_FORMAT_RGB24 FREERDP_PIXEL_FORMAT(24, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 8, 8, 8)
+@@ -149,6 +151,12 @@ extern "C"
+ 			case PIXEL_FORMAT_RGBX32:
+ 				return "PIXEL_FORMAT_RGBX32";
+ 
++			case PIXEL_FORMAT_BGRX32_DEPTH30:
++				return "PIXEL_FORMAT_BGRX32_DEPTH30";
++
++			case PIXEL_FORMAT_RGBX32_DEPTH30:
++				return "PIXEL_FORMAT_RGBX32_DEPTH30";
++
+ 			/* 24bpp formats */
+ 			case PIXEL_FORMAT_RGB24:
+ 				return "PIXEL_FORMAT_RGB24";
+@@ -607,6 +615,7 @@ extern "C"
+ 		UINT32 _g = g;
+ 		UINT32 _b = b;
+ 		UINT32 _a = a;
++		UINT32 t;
+ 
+ 		switch (format)
+ 		{
+@@ -635,6 +644,18 @@ extern "C"
+ 			case PIXEL_FORMAT_BGRX32:
+ 				return (_b << 24) | (_g << 16) | (_r << 8) | _a;
+ 
++			case PIXEL_FORMAT_RGBX32_DEPTH30:
++				// TODO: Not tested
++				t = (_r << 22) | (_g << 12) | (_b << 2);
++				// NOTE: Swapping byte-order because WriteColor written UINT32 in big-endian
++				return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) | (t >> 24);
++
++			case PIXEL_FORMAT_BGRX32_DEPTH30:
++				// NOTE: Swapping b and r channel (unknown reason)
++				t = (_r << 22) | (_g << 12) | (_b << 2);
++				// NOTE: Swapping byte-order because WriteColor written UINT32 in big-endian
++				return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) | (t >> 24);
++
+ 			/* 24bpp formats */
+ 			case PIXEL_FORMAT_RGB24:
+ 				return (_r << 16) | (_g << 8) | _b;
+diff --git a/include/freerdp/rail.h b/include/freerdp/rail.h
+index 019aff89a11a..e532082bed05 100644
+--- a/include/freerdp/rail.h
++++ b/include/freerdp/rail.h
+@@ -142,6 +142,7 @@ enum SPI_MASK
+ #define TS_RAIL_CLIENTSTATUS_HIGH_DPI_ICONS_SUPPORTED 0x00000020
+ #define TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED 0x00000040
+ #define TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED 0x00000080
++#define TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED 0x00000100
+ #define TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED 0x00000200
+ 
+ /* Server Move/Size Start PDU */
+diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h
+index fa83473596b4..b83a63610f74 100644
+--- a/include/freerdp/server/rdpsnd.h
++++ b/include/freerdp/server/rdpsnd.h
+@@ -119,6 +119,9 @@ struct _rdpsnd_server_context
+ 	UINT16 clientVersion;
+ 
+ 	rdpContext* rdpcontext;
++
++	/* Server to request to use dynamic virtual channel. */
++	BOOL use_dynamic_virtual_channel;
+ };
+ 
+ #ifdef __cplusplus
+diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c
+index ba207e5e56df..9caec04b4a27 100644
+--- a/libfreerdp/codec/h264_mediacodec.c
++++ b/libfreerdp/codec/h264_mediacodec.c
+@@ -18,19 +18,17 @@
+  */
+ 
+ #include <winpr/wlog.h>
+-#include <assert.h>
++#include <winpr/assert.h>
+ #include <winpr/library.h>
+ 
+ #include <freerdp/log.h>
+ #include <freerdp/codec/h264.h>
+ 
+ #include <media/NdkMediaCodec.h>
+ #include <media/NdkMediaFormat.h>
+ 
+ #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 60343b881a93..a9e39d2c824e 100644
+--- a/libfreerdp/codec/progressive.c
++++ b/libfreerdp/codec/progressive.c
+@@ -23,26 +23,24 @@
+ #include "config.h"
+ #endif
+ 
+-#include <assert.h>
++#include <winpr/assert.h>
+ #include <winpr/crt.h>
+ #include <winpr/print.h>
+ #include <winpr/bitstream.h>
+ 
+ #include <freerdp/primitives.h>
+ #include <freerdp/codec/color.h>
+ #include <freerdp/codec/progressive.h>
+ #include <freerdp/codec/region.h>
+ #include <freerdp/log.h>
+ 
+ #include "rfx_differential.h"
+ #include "rfx_quantization.h"
+ #include "rfx_dwt.h"
+ #include "rfx_rlgr.h"
+ #include "rfx_types.h"
+ #include "progressive.h"
+ 
+-#define WINPR_ASSERT(x) assert(x)
+-
+ #define TAG FREERDP_TAG("codec.progressive")
+ 
+ struct _RFX_PROGRESSIVE_UPGRADE_STATE
+@@ -370,29 +368,31 @@ 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)
+ {
+ 	if (tile)
+ 	{
+ 		_aligned_free(tile->sign);
+ 		_aligned_free(tile->current);
+ 		_aligned_free(tile->data);
+ 	}
+ }
+ 
+-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]);
+@@ -612,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;
+ }
+@@ -1113,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);
+ 			}
+ 
+@@ -1665,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:
+@@ -2400,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);
+@@ -2744,42 +2741,25 @@ 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);
+ 	return NULL;
+ }
+ 
+ void progressive_context_free(PROGRESSIVE_CONTEXT* progressive)
+ {
+-	int count;
+-	int index;
+-	ULONG_PTR* pKeys = NULL;
+-	PROGRESSIVE_SURFACE_CONTEXT* surface;
+-
+ 	if (!progressive)
+ 		return;
+ 
+ 	Stream_Free(progressive->buffer, TRUE);
+ 	Stream_Free(progressive->rects, TRUE);
+ 	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 --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c
+index 8c65e7508370..b41c15794daa 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,20 +1215,24 @@ 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;
+ 				}
+ 
+ 				if (invalidRegion)
+ 					region16_union_rect(invalidRegion, invalidRegion, &updateRects[j]);
+ 			}
+ 
+ 			region16_uninit(&updateRegion);
+ 		}
+ 
+ 		region16_uninit(&clippingRects);
+ 		return TRUE;
+ 	}
+ 
++	WLog_ERR(TAG, "%s failed", __FUNCTION__);
+ 	return FALSE;
+ }
+ 
+diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c
+index d0c2b56f3303..6a7b9900c48c 100644
+--- a/libfreerdp/core/settings.c
++++ b/libfreerdp/core/settings.c
+@@ -401,13 +401,9 @@ rdpSettings* freerdp_settings_new(DWORD flags)
+ 	if (!settings->ClientProductId)
+ 		goto out_fail;
+ 
+-	settings->ClientHostname = calloc(1, 32);
+-
+-	if (!settings->ClientHostname)
++	if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, settings->ComputerName))
+ 		goto out_fail;
+ 
+-	gethostname(settings->ClientHostname, 31);
+-	settings->ClientHostname[31] = 0;
+ 	settings->ColorPointerFlag = TRUE;
+ 	settings->LargePointerFlag = (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
+ 	settings->PointerCacheSize = 20;
+@@ -492,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 --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c
+index ca89d230cf44..e288799f1602 100644
+--- a/libfreerdp/core/surface.c
++++ b/libfreerdp/core/surface.c
+@@ -37,24 +37,32 @@ 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);
+ 	Stream_Read_UINT64(s, header->tmMilliseconds);
+ 	Stream_Read_UINT64(s, header->tmSeconds);
+ 	return TRUE;
+ }
+ 
+ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp)
+ {
+ 	size_t pos;
+ 
+ 	if (!s || !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,51 +144,75 @@ 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);
+ 	Stream_Read_UINT16(s, cmd.destTop);
+ 	Stream_Read_UINT16(s, cmd.destRight);
+ 	Stream_Read_UINT16(s, cmd.destBottom);
+ 
+ 	if (!update_recv_surfcmd_is_rect_valid(update->context, &cmd))
+ 		goto fail;
+ 
+ 	if (!update_recv_surfcmd_bitmap_ex(s, &cmd.bmp))
+ 		goto fail;
+ 
+ 	if (!update->SurfaceBits)
+ 	{
+ 		WLog_ERR(TAG, "Missing callback update->SurfaceBits");
+ 		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;
+ }
+ 
+ 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);
+ 
+ 	if (!update->SurfaceFrameMarker)
+ 	{
+ 		WLog_ERR(TAG, "Missing callback update->SurfaceFrameMarker");
+ 		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 +282,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 --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c
+index 6b6770ba5dbd..72432a2b9fff 100644
+--- a/libfreerdp/core/utils.c
++++ b/libfreerdp/core/utils.c
+@@ -22,17 +22,15 @@
+ #include "config.h"
+ #endif
+ 
+-#include <assert.h>
++#include <winpr/assert.h>
+ 
+ #include <freerdp/freerdp.h>
+ 
+ #include <freerdp/log.h>
+ #define TAG FREERDP_TAG("core.gateway.utils")
+ 
+ #include "utils.h"
+ 
+-#define WINPR_ASSERT(x) assert(x)
+-
+ BOOL utils_abort_connect(rdpContext* context)
+ {
+ 	WINPR_ASSERT(context);
+diff --git a/scripts/android-build.conf b/scripts/android-build.conf
+index 9ef3eec56784..5f470a5e37f6 100644
+--- a/scripts/android-build.conf
++++ b/scripts/android-build.conf
+@@ -28,4 +28,4 @@ BUILD_SRC=$SRC_DIR/build
+ 
+ CMAKE_BUILD_TYPE=Debug
+ 
+-BUILD_ARCH="armeabi-v7a x86 arm64-v8a x86_64"
++BUILD_ARCH="armeabi-v7a arm64-v8a"
+diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt
+index 7e5860d8c54a..1827a0aafd83 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
+new file mode 100644
+index 000000000000..0cef84132892
+--- /dev/null
++++ b/winpr/include/winpr/assert.h
+@@ -0,0 +1,59 @@
++/**
++ * WinPR: Windows Portable Runtime
++ * Runtime ASSERT macros
++ *
++ * Copyright 2021 Armin Novak <armin.novak at thincast.com>
++ * 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 <stdlib.h>
++#include <winpr/winpr.h>
++#include <winpr/wtypes.h>
++#include <winpr/wlog.h>
++#include <winpr/debug.h>
++
++#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0)
++#define WINPR_ASSERT(cond)                                                                    \
++	do                                                                                        \
++	{                                                                                         \
++		if (!(cond))                                                                          \
++		{                                                                                     \
++			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);                          \
++			abort();                                                                          \
++		}                                                                                     \
++	} while (0)
++#else
++#define WINPR_ASSERT(cond) \
++	do                     \
++	{                      \
++	} while (0)
++#endif
++
++#ifdef __cplusplus
++extern "C"
++{
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* WINPR_ERROR_H */
+diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c
+index 511d92790705..3867b066fecc 100644
+--- a/winpr/libwinpr/registry/registry_reg.c
++++ b/winpr/libwinpr/registry/registry_reg.c
+@@ -27,17 +27,15 @@
+ #include <string.h>
+ 
+ #include <winpr/wtypes.h>
+-#include <assert.h>
++#include <winpr/assert.h>
+ #include <winpr/crt.h>
+ #include <winpr/file.h>
+ 
+ #include "registry_reg.h"
+ 
+ #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/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c
+index 95603718dee7..372e6fb9957e 100644
+--- a/winpr/libwinpr/sspi/NTLM/ntlm.c
++++ b/winpr/libwinpr/sspi/NTLM/ntlm.c
+@@ -22,33 +22,37 @@
+ #endif
+ 
+ #include <winpr/crt.h>
++#include <winpr/assert.h>
+ #include <winpr/sspi.h>
+ #include <winpr/print.h>
++#include <winpr/string.h>
+ #include <winpr/tchar.h>
+ #include <winpr/sysinfo.h>
+ #include <winpr/registry.h>
+ #include <winpr/endian.h>
+ #include <freerdp/build-config.h>
+ 
+ #include "ntlm.h"
+ #include "../sspi.h"
+ 
+ #include "ntlm_message.h"
+ 
+ #include "../../log.h"
+ #define TAG WINPR_TAG("sspi.NTLM")
+ 
+ #define WINPR_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\WinPR\\NTLM"
+ 
+ static const char* NTLM_PACKAGE_NAME = "NTLM";
+ 
+ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
+ {
+ 	int status;
+ 	char* ws = Workstation;
+ 	DWORD nSize = 0;
+ 	CHAR* computerName;
+ 
++	WINPR_ASSERT(context);
++
+ 	if (!Workstation)
+ 	{
+ 		if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
+@@ -91,31 +95,35 @@ 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;
+ 		context->ServicePrincipalName.Length = 0;
+ 		return 1;
+ 	}
+ 
+ 	context->ServicePrincipalName.Length = (USHORT)(_wcslen(ServicePrincipalName) * 2);
+ 	context->ServicePrincipalName.Buffer = (PWSTR)malloc(context->ServicePrincipalName.Length + 2);
+ 
+ 	if (!context->ServicePrincipalName.Buffer)
+ 		return -1;
+ 
+ 	CopyMemory(context->ServicePrincipalName.Buffer, ServicePrincipalName,
+ 	           context->ServicePrincipalName.Length + 2);
+ 	return 1;
+ }
+ 
+ static int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
+ {
+ 	int status;
+ 	char* name = TargetName;
+ 	DWORD nSize = 0;
+ 	CHAR* computerName = NULL;
+ 
++	WINPR_ASSERT(context);
++
+ 	if (!name)
+ 	{
+ 		if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
+@@ -254,7 +262,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 +422,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);
+-
+-		if (!input_buffer)
+-			return SEC_E_INVALID_TOKEN;
+-
+-		if (input_buffer->cbBuffer < 1)
+-			return SEC_E_INVALID_TOKEN;
+-
+-		status = ntlm_read_NegotiateMessage(context, input_buffer);
+-
+-		if (context->state == NTLM_STATE_CHALLENGE)
++		case NTLM_STATE_INITIAL:
+ 		{
+-			if (!pOutput)
++			ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
++
++			if (!pInput)
+ 				return SEC_E_INVALID_TOKEN;
+ 
+-			if (pOutput->cBuffers < 1)
++			if (pInput->cBuffers < 1)
+ 				return SEC_E_INVALID_TOKEN;
+ 
+-			output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
++			input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
+ 
+-			if (!output_buffer->BufferType)
++			if (!input_buffer)
+ 				return SEC_E_INVALID_TOKEN;
+ 
+-			if (output_buffer->cbBuffer < 1)
+-				return SEC_E_INSUFFICIENT_MEMORY;
++			if (input_buffer->cbBuffer < 1)
++				return SEC_E_INVALID_TOKEN;
+ 
+-			return ntlm_write_ChallengeMessage(context, output_buffer);
+-		}
++			status = ntlm_read_NegotiateMessage(context, input_buffer);
++			if (status != SEC_I_CONTINUE_NEEDED)
++				return status;
+ 
+-		return SEC_E_OUT_OF_SEQUENCE;
+-	}
+-	else if (context->state == NTLM_STATE_AUTHENTICATE)
+-	{
+-		if (!pInput)
+-			return SEC_E_INVALID_TOKEN;
+-
+-		if (pInput->cBuffers < 1)
+-			return SEC_E_INVALID_TOKEN;
+-
+-		input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
+-
+-		if (!input_buffer)
+-			return SEC_E_INVALID_TOKEN;
+-
+-		if (input_buffer->cbBuffer < 1)
+-			return SEC_E_INVALID_TOKEN;
+-
+-		status = ntlm_read_AuthenticateMessage(context, input_buffer);
+-
+-		if (pOutput)
+-		{
+-			ULONG i;
+-
+-			for (i = 0; i < pOutput->cBuffers; i++)
++			if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
+ 			{
+-				pOutput->pBuffers[i].cbBuffer = 0;
+-				pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
++				if (!pOutput)
++					return SEC_E_INVALID_TOKEN;
++
++				if (pOutput->cBuffers < 1)
++					return SEC_E_INVALID_TOKEN;
++
++				output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
++
++				if (!output_buffer->BufferType)
++					return SEC_E_INVALID_TOKEN;
++
++				if (output_buffer->cbBuffer < 1)
++					return SEC_E_INSUFFICIENT_MEMORY;
++
++				return ntlm_write_ChallengeMessage(context, output_buffer);
+ 			}
++
++			return SEC_E_OUT_OF_SEQUENCE;
+ 		}
++		break;
++		case NTLM_STATE_AUTHENTICATE:
++		{
++			if (!pInput)
++				return SEC_E_INVALID_TOKEN;
+ 
+-		return status;
++			if (pInput->cBuffers < 1)
++				return SEC_E_INVALID_TOKEN;
++
++			input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
++
++			if (!input_buffer)
++				return SEC_E_INVALID_TOKEN;
++
++			if (input_buffer->cbBuffer < 1)
++				return SEC_E_INVALID_TOKEN;
++
++			status = ntlm_read_AuthenticateMessage(context, input_buffer);
++
++			if (pOutput)
++			{
++				ULONG i;
++
++				for (i = 0; i < pOutput->cBuffers; i++)
++				{
++					pOutput->pBuffers[i].cbBuffer = 0;
++					pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN;
++				}
++			}
++
++			return status;
++		}
++		break;
++		default:
++			break;
+ 	}
+-
+ 	return SEC_E_OUT_OF_SEQUENCE;
+ }
+ 
+@@ -540,70 +556,73 @@ 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;
+ 
+ 		if (pOutput->cBuffers < 1)
+ 			return SEC_E_INVALID_TOKEN;
+ 
+ 		output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
+ 
+ 		if (!output_buffer)
+ 			return SEC_E_INVALID_TOKEN;
+ 
+ 		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;
+ 	}
+ 	else
+ 	{
+ 		if (pInput->cBuffers < 1)
+ 			return SEC_E_INVALID_TOKEN;
+ 
+ 		input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
+ 
+ 		if (!input_buffer)
+ 			return SEC_E_INVALID_TOKEN;
+ 
+ 		if (input_buffer->cbBuffer < 1)
+ 			return SEC_E_INVALID_TOKEN;
+ 
+ 		channel_bindings = sspi_FindSecBuffer(pInput, SECBUFFER_CHANNEL_BINDINGS);
+ 
+ 		if (channel_bindings)
+ 		{
+ 			context->Bindings.BindingsLength = channel_bindings->cbBuffer;
+ 			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);
+ 
++			if (status != SEC_I_CONTINUE_NEEDED)
++				return status;
++
+ 			if (!pOutput)
+ 				return SEC_E_INVALID_TOKEN;
+ 
+ 			if (pOutput->cBuffers < 1)
+ 				return SEC_E_INVALID_TOKEN;
+ 
+ 			output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
+ 
+ 			if (!output_buffer)
+ 				return SEC_E_INVALID_TOKEN;
+ 
+ 			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,29 +691,39 @@ 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;
+ 
+ 	blob = (BYTE*)ntproof->pvBuffer;
+ 	CopyMemory(blob, ntlm->ServerChallenge, 8); /* Server challenge. */
+ 	blob[8] = 1;                                /* Response version. */
+ 	blob[9] = 1; /* Highest response version understood by the client. */
+ 	/* Reserved 6B. */
+ 	CopyMemory(&blob[16], ntlm->Timestamp, 8);       /* Time. */
+ 	CopyMemory(&blob[24], ntlm->ClientChallenge, 8); /* Client challenge. */
+ 	/* Reserved 4B. */
+ 	/* Server name. */
+ 	CopyMemory(&blob[36], target->pvBuffer, target->cbBuffer);
+ 	return SEC_E_OK;
+ }
+ 
+ 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 +998,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 +1095,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 +1287,86 @@ 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;
++
++	_snprintf(buffer, size, "[0x%08" PRIx32 "] ", flags);
++
++		for (x = 0; x < 31; x++)
++		{
++			const UINT32 mask = 1 << x;
++			size_t len = strnlen(buffer, size);
++			if (flags & mask)
++			{
++				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, 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 c6216ea41a43..a9fe5c2b0b5b 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;
+ 
+@@ -176,32 +176,29 @@ 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;
+ 	NTLM_MESSAGE_FIELDS Workstation;
+ };
+ 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];
+ 	NTLM_VERSION_INFO Version;
+ 	NTLM_MESSAGE_FIELDS TargetName;
+ 	NTLM_MESSAGE_FIELDS TargetInfo;
+ };
+ 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 47669bb2e8aa..9b2efd37a96b 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 <assert.h>
++#include <winpr/assert.h>
+ 
+ #include "ntlm.h"
+ #include "../sspi.h"
+ 
+ #include <winpr/crt.h>
++#include <winpr/assert.h>
+ #include <winpr/print.h>
+ #include <winpr/sysinfo.h>
+ #include <winpr/tchar.h>
+@@ -75,23 +76,25 @@ 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";
+ 	}
+ }
+ 
+ static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair);
+ static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvPairList);
+ 
+ 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,62 +127,68 @@ 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;
+ 
+ 	pAvPair = ntlm_av_pair_get(pAvPairList, cbAvPairList, MsvAvEOL, &cbAvPair);
+ 	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)
+ {
+ 	UINT16 AvLen;
+ 	if (!pAvPair)
+ 		return FALSE;
+ 
+ 	if (size < sizeof(NTLM_AV_PAIR))
+ 		return FALSE;
+ 
+ 	Data_Read_UINT16(&pAvPair->AvLen, AvLen);
+ 
+ 	*pAvLen = AvLen;
+ 	return TRUE;
+ }
+ 
++#ifdef WITH_DEBUG_NTLM
+ void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
+ {
+ 	UINT16 pair;
+ 	size_t cbAvPair = cbAvPairList;
+ 	NTLM_AV_PAIR* pAvPair = pAvPairList;
+ 
+ 	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)
+ {
+ 	/* size of headers + value lengths + terminating MsvAvEOL AV_PAIR */
+ 	return ((AvPairsCount + 1) * 4) + AvPairsValueLength;
+ }
+ 
+ PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
+ {
++	WINPR_ASSERT(pAvPair);
+ 	return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
+ }
+ 
+@@ -259,44 +268,47 @@ 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);
+ 	}
+ 
+ 	pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
+ 	return ntlm_av_pair_list_init(pAvPair, cbAvPair);
+ }
+ 
+ static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList,
+                                   NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
+ {
+ 	UINT16 pair;
+ 	size_t avLen;
+ 
+ 	if (!ntlm_av_pair_check(pAvPair, cbAvPair))
+ 		return FALSE;
+ 
+ 	if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
+ 		return FALSE;
+ 
+ 	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)
+ {
+ 	char* name;
+ 	int status;
+ 	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,34 +451,37 @@ 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
+ 	 * produce additional information to be processed in an implementation-specific way when
+ 	 * the client and server are on the same host. If the server and client platforms are
+ 	 * different or if they are on different hosts, then the information MUST be ignored.
+ 	 * Any fields after the MachineID field MUST be ignored on receipt.
+ 	 */
+ 	Data_Write_UINT32(&context->SingleHostData.Size, 48);
+ 	Data_Write_UINT32(&context->SingleHostData.Z4, 0);
+ 	Data_Write_UINT32(&context->SingleHostData.DataPresent, 1);
+ 	Data_Write_UINT32(&context->SingleHostData.CustomData, SECURITY_MANDATORY_MEDIUM_RID);
+ 	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;
+ 	size_t cbAvPairList;
+ 	UNICODE_STRING NbDomainName = { 0 };
+ 	UNICODE_STRING NbComputerName = { 0 };
+ 	UNICODE_STRING DnsDomainName = { 0 };
+ 	UNICODE_STRING DnsComputerName = { 0 };
+ 
++	WINPR_ASSERT(context);
++
+ 	if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
+ 		goto fail;
+ 
+@@ -516,36 +534,39 @@ 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);
+ 	ntlm_free_unicode_string(&DnsDomainName);
+ 	ntlm_free_unicode_string(&DnsComputerName);
+ 	return rc;
+ }
+ 
+-int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
++BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
+ {
+ 	ULONG size;
+ 	ULONG AvPairsCount;
+ 	ULONG AvPairsValueLength;
+ 	NTLM_AV_PAIR* AvTimestamp;
+ 	NTLM_AV_PAIR* AvNbDomainName;
+ 	NTLM_AV_PAIR* AvNbComputerName;
+ 	NTLM_AV_PAIR* AvDnsDomainName;
+ 	NTLM_AV_PAIR* AvDnsComputerName;
+ 	NTLM_AV_PAIR* AvDnsTreeName;
+ 	NTLM_AV_PAIR* ChallengeTargetInfo;
+ 	NTLM_AV_PAIR* AuthenticateTargetInfo;
+ 	size_t cbAvTimestamp;
+ 	size_t cbAvNbDomainName;
+ 	size_t cbAvNbComputerName;
+ 	size_t cbAvDnsDomainName;
+ 	size_t cbAvDnsComputerName;
+ 	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,39 +735,41 @@ 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)
+ 		{
+ 			if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvTargetName,
+ 			                      (PBYTE)context->ServicePrincipalName.Buffer,
+ 			                      context->ServicePrincipalName.Length))
+ 				goto fail;
+ 		}
+ 	}
+ 
+ 	if (context->NTLMv2)
+ 	{
+ 		NTLM_AV_PAIR* AvEOL;
+ 		AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, NULL);
+ 
+ 		if (!AvEOL)
+ 			goto fail;
+ 
+ 		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 ac228a86972e..82d2364b215a 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 dbd7f7fb0e06..202240b13f48 100644
+--- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c
++++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c
+@@ -21,745 +21,864 @@
+ #include "config.h"
+ #endif
+ 
+-#include <assert.h>
++#include <winpr/assert.h>
+ 
+ #include "ntlm.h"
+ #include "../sspi.h"
+ 
+ #include <winpr/crt.h>
+ #include <winpr/sam.h>
+ #include <winpr/ntlm.h>
+ #include <winpr/print.h>
+ #include <winpr/crypto.h>
+ #include <winpr/sysinfo.h>
+ 
+ #include "ntlm_compute.h"
+ 
+ #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 };
+ 
+ /**
+  * Populate VERSION structure.
+  * VERSION @msdn{cc236654}
+  * @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;
+ }
+ 
+ /**
+  * Read VERSION structure.
+  * VERSION @msdn{cc236654}
+  * @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;
+ }
+ 
+ /**
+  * Write VERSION structure.
+  * VERSION @msdn{cc236654}
+  * @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;
+ }
+ 
+ /**
+  * Print VERSION structure.
+  * 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);
+ 
+-static int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
++	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 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);
+ 	Stream_Read_UINT16(s, challenge->Reserved1);
+ 	Stream_Read_UINT32(s, challenge->Reserved2);
+ 	Stream_Read(s, challenge->Timestamp, 8);
+ 	Stream_Read(s, challenge->ClientChallenge, 8);
+ 	Stream_Read_UINT32(s, challenge->Reserved3);
+ 	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);
+ 	Stream_Write_UINT32(s, challenge->Reserved2);
+ 	Stream_Write(s, challenge->Timestamp, 8);
+ 	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));
+ }
+ 
+ /**
+  * Get current time, in tenths of microseconds since midnight of January 1, 1601.
+  * @param[out] timestamp 64-bit little-endian timestamp
+  */
+ 
+ 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;
+ 	CopyMemory(timestamp, &(time64.QuadPart), 8);
+ }
+ 
+ /**
+  * Generate timestamp for AUTHENTICATE_MESSAGE.
+  * @param NTLM context
+  */
+ 
+ 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
+ 		ntlm_current_time(context->Timestamp);
+ }
+ 
+ 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)
+ 		return -1;
+ 
+ 	entry = SamLookupUserW(
+ 	    sam, (LPWSTR)credentials->identity.User, credentials->identity.UserLength * 2,
+ 	    (LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * 2);
+ 
+ 	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,
+ 		                 credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain,
+ 		                 credentials->identity.DomainLength * 2, (BYTE*)hash);
+ 		SamFreeEntry(sam, entry);
+ 		SamClose(sam);
+ 		return 1;
+ 	}
+ 
+ 	entry = SamLookupUserW(sam, (LPWSTR)credentials->identity.User,
+ 	                       credentials->identity.UserLength * 2, NULL, 0);
+ 
+ 	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,
+ 		                 credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain,
+ 		                 credentials->identity.DomainLength * 2, (BYTE*)hash);
+ 		SamFreeEntry(sam, entry);
+ 		SamClose(sam);
+ 		return 1;
+ 	}
+ 	else
+ 	{
+ 		SamClose(sam);
+ 		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,
+ 		                 credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain,
+ 		                 credentials->identity.DomainLength * 2, (BYTE*)hash);
+ 	}
+ 	else if (credentials->identity.PasswordLength > SSPI_CREDENTIALS_HASH_LENGTH_OFFSET)
+ 	{
+ 		/* 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,
+ 		                 credentials->identity.DomainLength * 2, (BYTE*)hash);
+ 	}
+ 	else if (credentials->identity.Password)
+ 	{
+ 		NTOWFv2W((LPWSTR)credentials->identity.Password, credentials->identity.PasswordLength * 2,
+ 		         (LPWSTR)credentials->identity.User, credentials->identity.UserLength * 2,
+ 		         (LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * 2,
+ 		         (BYTE*)hash);
+ 	}
+ 	else if (context->HashCallback)
+ 	{
+ 		int ret;
+ 		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 */
+ 	winpr_HMAC(WINPR_MD_MD5, (void*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH, (BYTE*)value,
+ 	           WINPR_MD5_DIGEST_LENGTH, (BYTE*)response, WINPR_MD5_DIGEST_LENGTH);
+ 	/* 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;
+ }
+ 
+ /**
+  * Compute NTLMv2 Response.
+  * NTLMv2_RESPONSE @msdn{cc236653}
+  * NTLMv2 Authentication @msdn{cc236700}
+  * @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;
+ 
+ 	ZeroMemory(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
+ 	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 */
+ 	blob[0] = 1; /* RespType (1 byte) */
+ 	blob[1] = 1; /* HighRespType (1 byte) */
+ 	/* Reserved1 (2 bytes) */
+ 	/* Reserved2 (4 bytes) */
+ 	CopyMemory(&blob[8], context->Timestamp, 8);        /* Timestamp (8 bytes) */
+ 	CopyMemory(&blob[16], context->ClientChallenge, 8); /* ClientChallenge (8 bytes) */
+ 	/* 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 */
+ 
+ 	if (!sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8))
+ 		goto exit;
+ 
+ 	blob = (BYTE*)ntlm_v2_temp_chal.pvBuffer;
+ 	CopyMemory(blob, context->ServerChallenge, 8);
+ 	CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
+ 	winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
+ 	           (BYTE*)ntlm_v2_temp_chal.pvBuffer, ntlm_v2_temp_chal.cbBuffer,
+ 	           context->NtProofString, WINPR_MD5_DIGEST_LENGTH);
+ 
+ 	/* NtChallengeResponse, Concatenate NTProofStr with temp */
+ 
+ 	if (!sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16))
+ 		goto exit;
+ 
+ 	blob = (BYTE*)context->NtChallengeResponse.pvBuffer;
+ 	CopyMemory(blob, context->NtProofString, WINPR_MD5_DIGEST_LENGTH);
+ 	CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
+ 	/* Compute SessionBaseKey, the HMAC-MD5 hash of NTProofStr using the NTLMv2 hash as the key */
+ 	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);
+ 	return ret;
+ }
+ 
+ /**
+  * Encrypt the given plain text using RC4 and the given key.
+  * @param key RC4 key
+  * @param length text length
+  * @param plaintext plain text
+  * @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);
+ 
+ 	if (rc4)
+ 	{
+ 		winpr_RC4_Update(rc4, length, plaintext, ciphertext);
+ 		winpr_RC4_Free(rc4);
+ 	}
+ }
+ 
+ /**
+  * Generate client challenge (8-byte nonce).
+  * @param NTLM context
+  */
+ 
+ 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));
+ }
+ 
+ /**
+  * Generate server challenge (8-byte nonce).
+  * @param NTLM 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));
+ }
+ 
+ /**
+  * Generate KeyExchangeKey (the 128-bit SessionBaseKey).
+  * @msdn{cc236710}
+  * @param NTLM 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));
+ }
+ 
+ /**
+  * Generate RandomSessionKey (16-byte nonce).
+  * @param NTLM 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));
+ }
+ 
+ /**
+  * Generate ExportedSessionKey (the RandomSessionKey, exported)
+  * @param NTLM context
+  */
+ 
+ void ntlm_generate_exported_session_key(NTLM_CONTEXT* context)
+ {
+-	CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, 16);
++	WINPR_ASSERT(context);
++
++	CopyMemory(context->ExportedSessionKey, context->RandomSessionKey,
++	           sizeof(context->ExportedSessionKey));
+ }
+ 
+ /**
+  * Encrypt RandomSessionKey (RC4-encrypted RandomSessionKey, using KeyExchangeKey as the key).
+  * @param NTLM context
+  */
+ 
+ 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);
+ }
+ 
+ /**
+  * Decrypt RandomSessionKey (RC4-encrypted RandomSessionKey, using KeyExchangeKey as the key).
+  * @param NTLM context
+  */
+ 
+ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
+ {
++	WINPR_ASSERT(context);
++
+ 	/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the
+ 	 * KeyExchangeKey */
+ 
+ 	/**
+ 	 * 	if (NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
+ 	 * 		Set RandomSessionKey to RC4K(KeyExchangeKey,
+ 	 * 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));
++	}
+ }
+ 
+ /**
+  * Generate signing key.
+  * @msdn{cc236711}
+  * @param exported_session_key ExportedSessionKey
+  * @param sign_magic Sign magic string
+  * @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;
+ }
+ 
+ /**
+  * Generate client signing key (ClientSigningKey).
+  * @msdn{cc236711}
+  * @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);
+ }
+ 
+ /**
+  * Generate server signing key (ServerSigningKey).
+  * @msdn{cc236711}
+  * @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);
+-}
++	const SecBuffer signMagic = { sizeof(NTLM_SERVER_SIGN_MAGIC), 0, NTLM_SERVER_SIGN_MAGIC };
+ 
+-/**
+- * Generate sealing key.
+- * @msdn{cc236712}
+- * @param exported_session_key ExportedSessionKey
+- * @param seal_magic Seal magic string
+- * @param sealing_key Destination sealing key
+- */
+-
+-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);
+ }
+ 
+ /**
+  * Generate client sealing key (ClientSealingKey).
+  * @msdn{cc236712}
+  * @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);
+ }
+ 
+ /**
+  * Generate server sealing key (ServerSealingKey).
+  * @msdn{cc236712}
+  * @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);
+ }
+ 
+ /**
+  * Initialize RC4 stream cipher states for sealing.
+  * @param NTLM 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
+ 	{
+ 		context->SendSigningKey = context->ClientSigningKey;
+ 		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))
+ 	{
+ 		winpr_HMAC_Update(hmac, (BYTE*)context->NegotiateMessage.pvBuffer,
+ 		                  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 47f6c5dc84b4..a5572b504fa2 100644
+--- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.h
++++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.h
+@@ -24,38 +24,41 @@
+ 
+ #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);
+ 
+ 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);
+ void ntlm_generate_random_session_key(NTLM_CONTEXT* context);
+ 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 7502ecfc2bf0..ccb2e1078642 100644
+--- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c
++++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c
+@@ -25,281 +25,613 @@
+ #include "../sspi.h"
+ 
+ #include <winpr/crt.h>
++#include <winpr/assert.h>
+ #include <winpr/print.h>
+ #include <winpr/stream.h>
+ #include <winpr/sysinfo.h>
+ 
+ #include "ntlm_compute.h"
+ 
+ #include "ntlm_message.h"
+ 
+-#include "../log.h"
++#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' };
+ 
+-#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" };
++static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields);
++
++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;
++	}
++
++	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) */
+-	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)
++void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields)
+ {
+ 	if (fields)
+ 	{
+ 		if (fields->Buffer)
+ 		{
+ 			free(fields->Buffer);
+ 			fields->Len = 0;
+ 			fields->MaxLen = 0;
+ 			fields->Buffer = NULL;
+ 			fields->BufferOffset = 0;
+ 		}
+ 	}
+ }
+ 
+-#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;
++	char buffer[1024] = { 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;
++	}
++
++	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);
++
++	if (Stream_GetRemainingCapacity(s) < 4)
++	{
++		WLog_ERR(TAG, "%s::NegotiateFlags expected 4bytes, have %" PRIuz "bytes", name,
++		         Stream_GetRemainingCapacity(s));
++		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;
++}
++
++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;
+-		}
+ 	}
+ 
++		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);
+-	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_StaticInit2(&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,547 +661,531 @@ 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) */
++	if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_CHALLENGE_MESSAGE"))
+ 		goto fail;
+ 
+-	if (Stream_GetRemainingLength(s) < 4)
+-		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;
+ 	}
+ 
+ 	/* Payload (variable) */
+ 	PayloadOffset = Stream_GetPosition(s);
+ 
+ 	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;
+ 	}
+ 
+ 	if (message->TargetInfo.Len > 0)
+ 	{
+ 		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;
+ 		context->ChallengeTargetInfo.cbBuffer = message->TargetInfo.Len;
+ 		AvTimestamp = ntlm_av_pair_get((NTLM_AV_PAIR*)message->TargetInfo.Buffer,
+ 		                               message->TargetInfo.Len, MsvAvTimestamp, &cbAvTimestamp);
+ 
+ 		if (AvTimestamp)
+ 		{
+ 			PBYTE ptr = ntlm_av_pair_get_value_pointer(AvTimestamp);
+ 
+ 			if (!ptr)
+ 				goto fail;
+ 
+ 			if (context->NTLMv2)
+ 				context->UseMIC = TRUE;
+ 
+ 			CopyMemory(context->ChallengeTimestamp, ptr, 8);
+ 		}
+ 	}
+ 
+ 	length = (PayloadOffset - StartOffset) + message->TargetName.Len + message->TargetInfo.Len;
+ 	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);
+ 		context->ChallengeTargetInfo.pvBuffer = context->AuthenticateTargetInfo.pvBuffer;
+ 		context->ChallengeTargetInfo.cbBuffer = context->AuthenticateTargetInfo.cbBuffer;
+ 	}
+ 
+ 	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 */
+ 	ntlm_generate_random_session_key(context);   /* RandomSessionKey */
+ 	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_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
+ 
+ 	if (!s)
+ 		return SEC_E_INTERNAL_ERROR;
+ 
+ 	ntlm_get_version_info(&(message->Version)); /* Version */
+ 	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)
+ 	{
+ 		message->TargetName.Len = (UINT16)context->TargetName.cbBuffer;
+ 		message->TargetName.Buffer = (PBYTE)context->TargetName.pvBuffer;
+ 	}
+ 
+ 	message->NegotiateFlags |= NTLMSSP_NEGOTIATE_TARGET_INFO;
+ 
+ 	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
+ 	{
+ 		message->TargetInfo.Len = (UINT16)context->ChallengeTargetInfo.cbBuffer;
+ 		message->TargetInfo.Buffer = (PBYTE)context->ChallengeTargetInfo.pvBuffer;
+ 	}
+ 
+ 	PayloadOffset = 48;
+ 
+ 	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
+ 		PayloadOffset += 8;
+ 
+ 	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) */
+-	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->TargetName)))
++		return SEC_E_INTERNAL_ERROR;
+ 
+-	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
+-		ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */
++	if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_CHALLENGE_MESSAGE"))
++		return SEC_E_INTERNAL_ERROR;
+ 
+-	/* Payload (variable) */
+-
+-	if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
+-		ntlm_write_message_fields_buffer(s, &(message->TargetName));
+-
+-	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
+-		ntlm_write_message_fields_buffer(s, &(message->TargetInfo));
+-
+-	length = Stream_GetPosition(s);
+-	buffer->cbBuffer = length;
+-
+-	if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length))
++	if (Stream_GetRemainingCapacity(s) < 16)
+ 	{
+-		Stream_Free(s, FALSE);
++		WLog_ERR(TAG,
++		         "NTLM_CHALLENGE_MESSAGE::ServerChallenge expected 16bytes, got %" PRIuz "bytes",
++		         Stream_GetRemainingCapacity(s));
+ 		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);
++	Stream_Write(s, message->ServerChallenge, 8);    /* ServerChallenge (8 bytes) */
++	Stream_Write(s, message->Reserved, 8);           /* Reserved (8 bytes), should be ignored */
++
++	/* TargetInfoFields (8 bytes) */
++	if (!ntlm_write_message_fields(s, &(message->TargetInfo)))
++		return SEC_E_INTERNAL_ERROR;
+ 
+ 	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION)
+-		ntlm_print_version_info(&(message->Version));
++	{
++		if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */
++			return SEC_E_INTERNAL_ERROR;
++	}
+ 
+-	ntlm_print_message_fields(&(message->TargetName), "TargetName");
+-	ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo");
++	/* Payload (variable) */
++	if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET)
++	{
++		if (!ntlm_write_message_fields_buffer(s, &(message->TargetName)))
++			return SEC_E_INTERNAL_ERROR;
++	}
++
++	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO)
++	{
++		if (!ntlm_write_message_fields_buffer(s, &(message->TargetInfo)))
++			return SEC_E_INTERNAL_ERROR;
++	}
++
++	length = Stream_GetPosition(s);
++	WINPR_ASSERT(length <= ULONG_MAX);
++	buffer->cbBuffer = (ULONG)length;
++
++	if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length))
++		return SEC_E_INTERNAL_ERROR;
++
++	CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length);
++#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;
+ 
+ 	if ((context->NegotiateKeyExchange && !message->EncryptedRandomSessionKey.Len) ||
+ 	    (!context->NegotiateKeyExchange && message->EncryptedRandomSessionKey.Len))
+ 		goto fail;
+ 
+ 	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 */
++	if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */
+ 		goto fail;
+ 
+-	if (ntlm_read_message_fields_buffer(s, &(message->LmChallengeResponse)) <
+-	    0) /* LmChallengeResponse */
++	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;
+ 
+ 		context->NtChallengeResponse.pvBuffer = message->NtChallengeResponse.Buffer;
+ 		context->NtChallengeResponse.cbBuffer = message->NtChallengeResponse.Len;
+ 		sspi_SecBufferFree(&(context->ChallengeTargetInfo));
+ 		context->ChallengeTargetInfo.pvBuffer = (void*)context->NTLMv2Response.Challenge.AvPairs;
+ 		context->ChallengeTargetInfo.cbBuffer = message->NtChallengeResponse.Len - (28 + 16);
+ 		CopyMemory(context->ClientChallenge, context->NTLMv2Response.Challenge.ClientChallenge, 8);
+ 		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_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)
+ 	{
+ 		if (message->EncryptedRandomSessionKey.Len != 16)
+ 			goto fail;
+ 
+ 		CopyMemory(context->EncryptedRandomSessionKey, message->EncryptedRandomSessionKey.Buffer,
+ 		           16);
+ 	}
+ 
+ 	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)
+ 	{
+ 		credentials->identity.User = (UINT16*)malloc(message->UserName.Len);
+ 
+ 		if (!credentials->identity.User)
+ 			goto fail;
+ 
+ 		CopyMemory(credentials->identity.User, message->UserName.Buffer, message->UserName.Len);
+ 		credentials->identity.UserLength = message->UserName.Len / 2;
+ 	}
+ 
+ 	if (message->DomainName.Len > 0)
+ 	{
+ 		credentials->identity.Domain = (UINT16*)malloc(message->DomainName.Len);
+ 
+ 		if (!credentials->identity.Domain)
+ 			goto fail;
+ 
+ 		CopyMemory(credentials->identity.Domain, message->DomainName.Buffer,
+ 		           message->DomainName.Len);
+ 		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;
+ }
+ 
+ /**
+  * Send NTLMSSP AUTHENTICATE_MESSAGE.\n
+  * AUTHENTICATE_MESSAGE @msdn{cc236643}
+  * @param NTLM context
+  * @param buffer
+  */
+ 
+ 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_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer);
+ 
+ 	if (!s)
+ 		return SEC_E_INTERNAL_ERROR;
+@@ -948,219 +1264,214 @@ 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 */
+-
+-	ntlm_write_message_fields_buffer(s, &(message->UserName)); /* UserName */
+-
+-	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
+-		ntlm_write_message_fields_buffer(s, &(message->Workstation)); /* Workstation */
+-
+-	ntlm_write_message_fields_buffer(s, &(message->LmChallengeResponse)); /* LmChallengeResponse */
+-	ntlm_write_message_fields_buffer(s, &(message->NtChallengeResponse)); /* NtChallengeResponse */
+-
+-	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH)
+-		ntlm_write_message_fields_buffer(
+-		    s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKey */
+-
+-	length = Stream_GetPosition(s);
+-
+-	if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length))
+ 	{
+-		Stream_Free(s, FALSE);
+-		return SEC_E_INTERNAL_ERROR;
++		if (!ntlm_write_message_fields_buffer(s, &(message->DomainName))) /* DomainName */
++			return SEC_E_INTERNAL_ERROR;
+ 	}
+ 
++	if (!ntlm_write_message_fields_buffer(s, &(message->UserName))) /* UserName */
++		return SEC_E_INTERNAL_ERROR;
++
++	if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED)
++	{
++		if (!ntlm_write_message_fields_buffer(s, &(message->Workstation))) /* Workstation */
++			return SEC_E_INTERNAL_ERROR;
++	}
++
++	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)
++	{
++		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, (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;
+ }
+ 
+ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context)
+ {
+ 	UINT32 flags = 0;
+ 	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 */
+-		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) < 0) /* NtChallengeResponse */
++	if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */
+ 		return SEC_E_INTERNAL_ERROR;
+ 
+ 	/* KeyExchangeKey */
+ 	ntlm_generate_key_exchange_key(context);
+ 	/* EncryptedRandomSessionKey */
+ 	ntlm_decrypt_random_session_key(context);
+ 	/* ExportedSessionKey */
+ 	ntlm_generate_exported_session_key(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
+ 			WLog_ERR(TAG, "Expected MIC:");
+ 			winpr_HexDump(TAG, WLOG_ERROR, messageIntegrityCheck, sizeof(messageIntegrityCheck));
+ 			WLog_ERR(TAG, "Actual MIC:");
+ 			winpr_HexDump(TAG, WLOG_ERROR, message->MessageIntegrityCheck,
+ 			              sizeof(message->MessageIntegrityCheck));
+ #endif
+ 			return SEC_E_MESSAGE_ALTERED;
+ 		}
+ 	}
+ 	else
+ 	{
+ 		/* no mic message was present
+ 
+ 		   https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/f9e6fbc4-a953-4f24-b229-ccdcc213b9ec
+ 		   the mic is optional, as not supported in Windows NT, Windows 2000, Windows XP, and
+ 		   Windows Server 2003 and, as it seems, in the NTLMv2 implementation of Qt5.
+ 
+ 		   now check the NtProofString, to detect if the entered client password matches the
+ 		   expected password.
+ 		   */
+ 
+ #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)
+ 		{
+ 			WLog_ERR(TAG, "NtProofString verification failed!");
+ #ifdef WITH_DEBUG_NTLM
+ 			WLog_ERR(TAG, "Expected NtProofString:");
+ 			winpr_HexDump(TAG, WLOG_ERROR, context->NtProofString, sizeof(context->NtProofString));
+ 			WLog_ERR(TAG, "Actual NtProofString:");
+ 			winpr_HexDump(TAG, WLOG_ERROR, context->NTLMv2Response.Response,
+ 			              sizeof(context->NTLMv2Response));
+ #endif
+ 			return SEC_E_LOGON_DENIED;
+ 		}
+ 	}
+ 
+ 	/* 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 100d95a8ec08..58ff35dd5a6a 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 82d266fe6031..9260bf0df647 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,13 +681,23 @@ int TestNTLM(int argc, char* argv[])
+ 		goto fail;
+ 	}
+ 
+-	rc = 0;
++	rc = TRUE;
+ 
+ fail:
+ 	/**
+ 	 * Cleanup & Termination
+ 	 */
+ 	test_ntlm_client_free(client);
+ 	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 --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c
+index 5a13b99bebbc..1d491b874fbb 100644
+--- a/winpr/libwinpr/sspicli/sspicli.c
++++ b/winpr/libwinpr/sspicli/sspicli.c
+@@ -21,11 +21,9 @@
+ #include "config.h"
+ #endif
+ 
+-#include <assert.h>
++#include <winpr/assert.h>
+ #include <winpr/sspicli.h>
+ 
+-#define WINPR_ASSERT(x) assert(x)
+-
+ /**
+  * sspicli.dll:
+  *

Deleted: PKGBUILD
===================================================================
--- PKGBUILD	2022-04-22 12:13:44 UTC (rev 1187302)
+++ PKGBUILD	2022-04-22 12:14:10 UTC (rev 1187303)
@@ -1,68 +0,0 @@
-# Maintainer: Sergej Pupykin <pupykin.s+arch at gmail.com>
-# Contributor: David Runge <dvzrv at archlinux.org>
-# Contributor: Stijn Segers <francesco dot borromini at gmail dot com>
-
-_name=FreeRDP
-pkgname=freerdp
-pkgver=2.6.1
-pkgrel=2
-epoch=2
-pkgdesc="Free implementation of the Remote Desktop Protocol (RDP)"
-arch=(x86_64)
-url="https://www.freerdp.com/"
-license=(Apache)
-depends=(dbus-glib glibc gstreamer gst-plugins-base-libs libcups libgssglue
-libx11 libxcursor libxext libxdamage libxfixes libxkbcommon libxi libxinerama
-libxkbfile libxrandr libxrender libxtst openssl pcsclite wayland)
-makedepends=(alsa-lib cmake docbook-xsl ffmpeg icu krb5 libjpeg-turbo libpulse
-libusb pam systemd-libs xmlto xorgproto)
-provides=(libfreerdp2.so libfreerdp-client2.so libfreerdp-server2
-libfreerdp-shadow2.so libfreerdp-shadow-subsystem2.so libwinpr2.so
-libwinpr-tools2.so libuwac0.so)
-source=(
-  $pkgname-$pkgver.tar.gz::https://github.com/$pkgname/$pkgname/archive/$pkgver.tar.gz
-  $pkgname-2.0.0-manpage_formatting.patch
-)
-sha512sums=('53ca93dfc09cfb49f9c434ef492a7c2f0359ecfdb28c68fcb41d5875508da45cc62e054dc134577245a3a5a63102bdb89e50aeed3090f01b578879c5d5db6dca'
-            'd960e042d1527b5d5721136b6b20fc36f65beafd010581ea5b908668537fe9fe622de6689a29c0274b0d6f1e513615f0d02e56c1d1d1e613d093e145d39af8d7')
-b2sums=('351fcf2482cf6a8d47107376eafa132732476b31e56143cdb6748aedcad087ffbe26a9e667bd7bff96663580302d359ac856fb29a7b42ce5abda9c04c5fc44cb'
-        '8242fe56ba9cf5352d836f656645a46142c1aecea3e8200203117a0cccc226135591c16fa0a24cfa196ade7b703832ff6871a948fd3bbbcc1d9c6df9885dc360')
-
-prepare() {
-  # fix man page formatting:
-  # https://bugs.archlinux.org/task/64814
-  patch -d $_name-$pkgver -p1 -i ../$pkgname-2.0.0-manpage_formatting.patch
-}
-
-build() {
-  cmake -DCMAKE_INSTALL_PREFIX=/usr \
-        -DCMAKE_INSTALL_LIBDIR=lib \
-        -DCMAKE_BUILD_TYPE=None \
-        -DPROXY_PLUGINDIR=/usr/lib/freerdp2/server/proxy/plugins \
-        -DWITH_DSP_FFMPEG=ON \
-        -DWITH_FFMPEG=ON \
-        -DWITH_PULSE=ON \
-        -DWITH_CUPS=ON \
-        -DWITH_PCSC=ON \
-        -DWITH_ICU=ON \
-        -DWITH_JPEG=ON \
-        -DWITH_SERVER=ON \
-        -DWITH_SWSCALE=ON \
-        -DWITH_CHANNELS=ON \
-        -DWITH_CLIENT_CHANNELS=ON \
-        -DWITH_SERVER_CHANNELS=ON \
-        -DCHANNEL_URBDRC_CLIENT=ON \
-        -Wno-dev \
-        -B build \
-        -S $_name-$pkgver
-  make VERBOSE=1 -C build
-}
-
-package() {
-  depends+=(libasound.so libavcodec.so libavutil.so libicuuc.so libjpeg.so
-  libpam.so libpulse.so libswscale.so libswresample.so libsystemd.so
-  libusb-1.0.so)
-
-  make DESTDIR="$pkgdir" install -C build
-  install -vDm 644 $_name-$pkgver/{ChangeLog,README.md} -t "$pkgdir/usr/share/doc/$pkgname"
-}

Copied: freerdp/repos/community-x86_64/PKGBUILD (from rev 1187302, freerdp/trunk/PKGBUILD)
===================================================================
--- PKGBUILD	                        (rev 0)
+++ PKGBUILD	2022-04-22 12:14:10 UTC (rev 1187303)
@@ -0,0 +1,75 @@
+# Maintainer: Sergej Pupykin <pupykin.s+arch at gmail.com>
+# Contributor: David Runge <dvzrv at archlinux.org>
+# Contributor: Stijn Segers <francesco dot borromini at gmail dot com>
+
+_name=FreeRDP
+pkgname=freerdp
+pkgver=2.6.1
+pkgrel=3
+epoch=2
+pkgdesc="Free implementation of the Remote Desktop Protocol (RDP)"
+arch=(x86_64)
+url="https://www.freerdp.com/"
+license=(Apache)
+depends=(dbus-glib glibc gstreamer gst-plugins-base-libs libcups libgssglue
+libx11 libxcursor libxext libxdamage libxfixes libxkbcommon libxi libxinerama
+libxkbfile libxrandr libxrender libxtst openssl pcsclite wayland)
+makedepends=(alsa-lib cmake docbook-xsl ffmpeg icu krb5 libjpeg-turbo libpulse
+libusb pam systemd-libs xmlto xorgproto)
+provides=(libfreerdp2.so libfreerdp-client2.so libfreerdp-server2
+libfreerdp-shadow2.so libfreerdp-shadow-subsystem2.so libwinpr2.so
+libwinpr-tools2.so libuwac0.so)
+source=(
+  $pkgname-$pkgver.tar.gz::https://github.com/$pkgname/$pkgname/archive/$pkgver.tar.gz
+  0001-Merge-stable-2.0.patch
+  $pkgname-2.0.0-manpage_formatting.patch
+)
+sha512sums=('53ca93dfc09cfb49f9c434ef492a7c2f0359ecfdb28c68fcb41d5875508da45cc62e054dc134577245a3a5a63102bdb89e50aeed3090f01b578879c5d5db6dca'
+            '7073e66ff670651c4553fb40d020d8e8883bedf27f898b90d3be33c78aa22efec1ddd030e90b857aeca272b3052d46919299bcb1bd11e7cd86f35fa7f17698f4'
+            'd960e042d1527b5d5721136b6b20fc36f65beafd010581ea5b908668537fe9fe622de6689a29c0274b0d6f1e513615f0d02e56c1d1d1e613d093e145d39af8d7')
+b2sums=('351fcf2482cf6a8d47107376eafa132732476b31e56143cdb6748aedcad087ffbe26a9e667bd7bff96663580302d359ac856fb29a7b42ce5abda9c04c5fc44cb'
+        '52c0cadf9249fcc1ae7bfe7711d29ea35dc1041bd6035c7a02f499b29995a7721ccf8b931052013d2a72e62d5f42bd99e37ff7e57f5440f0df56d4257f134fe0'
+        '8242fe56ba9cf5352d836f656645a46142c1aecea3e8200203117a0cccc226135591c16fa0a24cfa196ade7b703832ff6871a948fd3bbbcc1d9c6df9885dc360')
+
+prepare() {
+  # Advance to stable-2.0 head in order to fix a critical security issue
+  # https://gitlab.gnome.org/GNOME/gnome-remote-desktop/-/issues/95
+  patch -d $_name-$pkgver -p1 -i ../0001-Merge-stable-2.0.patch
+
+  # fix man page formatting:
+  # https://bugs.archlinux.org/task/64814
+  patch -d $_name-$pkgver -p1 -i ../$pkgname-2.0.0-manpage_formatting.patch
+}
+
+build() {
+  cmake -DCMAKE_INSTALL_PREFIX=/usr \
+        -DCMAKE_INSTALL_LIBDIR=lib \
+        -DCMAKE_BUILD_TYPE=None \
+        -DPROXY_PLUGINDIR=/usr/lib/freerdp2/server/proxy/plugins \
+        -DWITH_DSP_FFMPEG=ON \
+        -DWITH_FFMPEG=ON \
+        -DWITH_PULSE=ON \
+        -DWITH_CUPS=ON \
+        -DWITH_PCSC=ON \
+        -DWITH_ICU=ON \
+        -DWITH_JPEG=ON \
+        -DWITH_SERVER=ON \
+        -DWITH_SWSCALE=ON \
+        -DWITH_CHANNELS=ON \
+        -DWITH_CLIENT_CHANNELS=ON \
+        -DWITH_SERVER_CHANNELS=ON \
+        -DCHANNEL_URBDRC_CLIENT=ON \
+        -Wno-dev \
+        -B build \
+        -S $_name-$pkgver
+  make VERBOSE=1 -C build
+}
+
+package() {
+  depends+=(libasound.so libavcodec.so libavutil.so libicuuc.so libjpeg.so
+  libpam.so libpulse.so libswscale.so libswresample.so libsystemd.so
+  libusb-1.0.so)
+
+  make DESTDIR="$pkgdir" install -C build
+  install -vDm 644 $_name-$pkgver/{ChangeLog,README.md} -t "$pkgdir/usr/share/doc/$pkgname"
+}

Deleted: freerdp-2.0.0-manpage_formatting.patch
===================================================================
--- freerdp-2.0.0-manpage_formatting.patch	2022-04-22 12:13:44 UTC (rev 1187302)
+++ freerdp-2.0.0-manpage_formatting.patch	2022-04-22 12:14:10 UTC (rev 1187303)
@@ -1,12 +0,0 @@
-diff -ruN a/cmake/FindDocBookXSL.cmake b/cmake/FindDocBookXSL.cmake
---- a/cmake/FindDocBookXSL.cmake	2018-11-20 11:43:51.000000000 +0100
-+++ b/cmake/FindDocBookXSL.cmake	2020-01-30 10:37:44.827482448 +0100
-@@ -30,7 +30,7 @@
-    set (STYLESHEET_PATH_LIST)
-    foreach (STYLESHEET_PREFIX_ITER ${CMAKE_SYSTEM_PREFIX_PATH})
-       file(GLOB STYLESHEET_SUFFIX_ITER RELATIVE ${STYLESHEET_PREFIX_ITER}
--           ${STYLESHEET_PREFIX_ITER}/share/xml/docbook/xsl-stylesheets-*
-+           ${STYLESHEET_PREFIX_ITER}/share/xml/docbook/xsl-stylesheets-*-nons
-       )
-       if (STYLESHEET_SUFFIX_ITER)
-          list (APPEND STYLESHEET_PATH_LIST ${STYLESHEET_SUFFIX_ITER})

Copied: freerdp/repos/community-x86_64/freerdp-2.0.0-manpage_formatting.patch (from rev 1187302, freerdp/trunk/freerdp-2.0.0-manpage_formatting.patch)
===================================================================
--- freerdp-2.0.0-manpage_formatting.patch	                        (rev 0)
+++ freerdp-2.0.0-manpage_formatting.patch	2022-04-22 12:14:10 UTC (rev 1187303)
@@ -0,0 +1,12 @@
+diff -ruN a/cmake/FindDocBookXSL.cmake b/cmake/FindDocBookXSL.cmake
+--- a/cmake/FindDocBookXSL.cmake	2018-11-20 11:43:51.000000000 +0100
++++ b/cmake/FindDocBookXSL.cmake	2020-01-30 10:37:44.827482448 +0100
+@@ -30,7 +30,7 @@
+    set (STYLESHEET_PATH_LIST)
+    foreach (STYLESHEET_PREFIX_ITER ${CMAKE_SYSTEM_PREFIX_PATH})
+       file(GLOB STYLESHEET_SUFFIX_ITER RELATIVE ${STYLESHEET_PREFIX_ITER}
+-           ${STYLESHEET_PREFIX_ITER}/share/xml/docbook/xsl-stylesheets-*
++           ${STYLESHEET_PREFIX_ITER}/share/xml/docbook/xsl-stylesheets-*-nons
+       )
+       if (STYLESHEET_SUFFIX_ITER)
+          list (APPEND STYLESHEET_PATH_LIST ${STYLESHEET_SUFFIX_ITER})



More information about the arch-commits mailing list