[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