New upstream version 2.7.0+dfsg1
This commit is contained in:
parent
f2ecc9e1e9
commit
b937a3a632
@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER})
|
||||
endif()
|
||||
set(WITH_LIBRARY_VERSIONING "ON")
|
||||
|
||||
set(RAW_VERSION_STRING "2.6.1")
|
||||
set(RAW_VERSION_STRING "2.7.0")
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
|
||||
elseif(USE_VERSION_FROM_GIT_TAG)
|
||||
|
||||
21
ChangeLog
21
ChangeLog
@ -1,7 +1,26 @@
|
||||
# 2022-04-25 Version 2.7.0
|
||||
|
||||
Noteworthy changes:
|
||||
* Backported OpenSSL3 gateway support (#7822)
|
||||
* 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.7.0
|
||||
|
||||
# 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)
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <assert.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
@ -37,8 +37,6 @@
|
||||
|
||||
#include "../common/ainput_common.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define TAG CHANNELS_TAG("ainput.client")
|
||||
|
||||
typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK;
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
#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>
|
||||
@ -39,8 +39,6 @@
|
||||
|
||||
#include "../common/ainput_common.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define TAG CHANNELS_TAG("ainput.server")
|
||||
|
||||
typedef enum
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -39,6 +39,7 @@ struct _rdpsnd_server_private
|
||||
HANDLE StopEvent;
|
||||
HANDLE channelEvent;
|
||||
void* ChannelHandle;
|
||||
DWORD SessionId;
|
||||
|
||||
BOOL waitingHeader;
|
||||
DWORD expectedBytes;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -490,17 +490,19 @@ static LIBUSB_DEVICE* udev_get_libusb_dev(libusb_context* context, uint8_t bus_n
|
||||
|
||||
for (i = 0; i < total_device; i++)
|
||||
{
|
||||
uint8_t cbus = libusb_get_bus_number(libusb_list[i]);
|
||||
uint8_t caddr = libusb_get_device_address(libusb_list[i]);
|
||||
|
||||
if ((bus_number == cbus) && (dev_number == caddr))
|
||||
LIBUSB_DEVICE* dev = libusb_list[i];
|
||||
if ((bus_number == libusb_get_bus_number(dev)) &&
|
||||
(dev_number == libusb_get_device_address(dev)))
|
||||
{
|
||||
device = libusb_list[i];
|
||||
break;
|
||||
device = dev;
|
||||
}
|
||||
else
|
||||
{
|
||||
libusb_unref_device(dev);
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_device_list(libusb_list, 1);
|
||||
libusb_free_device_list(libusb_list, 0);
|
||||
return device;
|
||||
}
|
||||
|
||||
@ -522,7 +524,6 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
|
||||
static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting)
|
||||
{
|
||||
int error = 0, diff = 0;
|
||||
@ -1012,6 +1013,9 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev)
|
||||
if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc)
|
||||
return FALSE;
|
||||
|
||||
#ifdef _WIN32
|
||||
return TRUE;
|
||||
#else
|
||||
urbdrc = pdev->urbdrc;
|
||||
|
||||
if ((pdev->status & URBDRC_DEVICE_DETACH_KERNEL) == 0)
|
||||
@ -1032,6 +1036,7 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev)
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev)
|
||||
@ -1048,12 +1053,14 @@ static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev)
|
||||
|
||||
log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_release_interface", err);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (err != LIBUSB_ERROR_NO_DEVICE)
|
||||
{
|
||||
err = libusb_attach_kernel_driver(pdev->libusb_handle, i);
|
||||
log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_attach_kernel_driver if=%d",
|
||||
err, i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@ -1474,6 +1481,7 @@ static void udev_free(IUDEVICE* idev)
|
||||
ArrayList_Free(udev->request_queue);
|
||||
/* free the config descriptor that send from windows */
|
||||
msusb_msconfig_free(udev->MsConfig);
|
||||
libusb_unref_device(udev->libusb_dev);
|
||||
libusb_close(udev->libusb_handle);
|
||||
libusb_close(udev->hub_handle);
|
||||
free(udev->devDescriptor);
|
||||
@ -1522,8 +1530,8 @@ static void udev_load_interface(UDEVICE* pdev)
|
||||
pdev->iface.free = udev_free;
|
||||
}
|
||||
|
||||
static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev,
|
||||
UINT16 bus_number, UINT16 dev_number)
|
||||
static int udev_get_device_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev,
|
||||
UINT16 bus_number, UINT16 dev_number)
|
||||
{
|
||||
int error;
|
||||
ssize_t i, total_device;
|
||||
@ -1535,21 +1543,19 @@ static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVI
|
||||
|
||||
for (i = 0; i < total_device; i++)
|
||||
{
|
||||
LIBUSB_DEVICE_HANDLE* handle;
|
||||
uint8_t cbus = libusb_get_bus_number(libusb_list[i]);
|
||||
uint8_t caddr = libusb_get_device_address(libusb_list[i]);
|
||||
LIBUSB_DEVICE* dev = libusb_list[i];
|
||||
|
||||
if ((bus_number != cbus) || (dev_number != caddr))
|
||||
if ((bus_number != libusb_get_bus_number(dev)) ||
|
||||
(dev_number != libusb_get_device_address(dev)))
|
||||
continue;
|
||||
|
||||
error = libusb_open(libusb_list[i], &handle);
|
||||
error = libusb_open(dev, &pdev->libusb_handle);
|
||||
|
||||
if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error))
|
||||
break;
|
||||
|
||||
/* get port number */
|
||||
error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers));
|
||||
libusb_close(handle);
|
||||
error = libusb_get_port_numbers(dev, port_numbers, sizeof(port_numbers));
|
||||
|
||||
if (error < 1)
|
||||
{
|
||||
@ -1567,29 +1573,40 @@ static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVI
|
||||
WLog_Print(urbdrc->log, WLOG_DEBUG, " DevPath: %s", pdev->path);
|
||||
break;
|
||||
}
|
||||
libusb_free_device_list(libusb_list, 1);
|
||||
|
||||
if (error < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev,
|
||||
UINT16 bus_number, UINT16 dev_number)
|
||||
{
|
||||
int error;
|
||||
ssize_t i, total_device;
|
||||
LIBUSB_DEVICE** libusb_list;
|
||||
LIBUSB_DEVICE_HANDLE* handle;
|
||||
total_device = libusb_get_device_list(ctx, &libusb_list);
|
||||
|
||||
/* Look for device hub. */
|
||||
if (error == 0)
|
||||
error = -1;
|
||||
|
||||
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,8 +1747,6 @@ size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendo
|
||||
{
|
||||
LIBUSB_DEVICE** libusb_list;
|
||||
UDEVICE** array;
|
||||
UINT16 bus_number;
|
||||
UINT16 dev_number;
|
||||
ssize_t i, total_device;
|
||||
size_t num = 0;
|
||||
|
||||
@ -1752,23 +1763,27 @@ size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendo
|
||||
|
||||
for (i = 0; i < total_device; i++)
|
||||
{
|
||||
LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, libusb_list[i]);
|
||||
LIBUSB_DEVICE* dev = libusb_list[i];
|
||||
LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, dev);
|
||||
|
||||
if ((descriptor->idVendor == idVendor) && (descriptor->idProduct == idProduct))
|
||||
{
|
||||
bus_number = libusb_get_bus_number(libusb_list[i]);
|
||||
dev_number = libusb_get_device_address(libusb_list[i]);
|
||||
array[num] = (PUDEVICE)udev_init(urbdrc, ctx, libusb_list[i], bus_number, dev_number);
|
||||
array[num] = (PUDEVICE)udev_init(urbdrc, ctx, dev, libusb_get_bus_number(dev),
|
||||
libusb_get_device_address(dev));
|
||||
|
||||
if (array[num] != NULL)
|
||||
num++;
|
||||
}
|
||||
else
|
||||
{
|
||||
libusb_unref_device(dev);
|
||||
}
|
||||
|
||||
free(descriptor);
|
||||
}
|
||||
|
||||
fail:
|
||||
libusb_free_device_list(libusb_list, 1);
|
||||
libusb_free_device_list(libusb_list, 0);
|
||||
*devArray = (IUDEVICE**)array;
|
||||
return num;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -24,9 +24,10 @@
|
||||
#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>
|
||||
@ -46,6 +47,7 @@
|
||||
#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,8 +2291,10 @@ 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
|
||||
{
|
||||
@ -2275,21 +2303,24 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
|
||||
{
|
||||
*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -88,9 +88,9 @@ extern "C"
|
||||
DWORD* PublicKeyLength);
|
||||
|
||||
#define TSSK_KEY_LENGTH 64
|
||||
extern const BYTE tssk_modulus[];
|
||||
extern const BYTE tssk_privateExponent[];
|
||||
extern const BYTE tssk_exponent[];
|
||||
WINPR_API extern const BYTE tssk_modulus[];
|
||||
WINPR_API extern const BYTE tssk_privateExponent[];
|
||||
WINPR_API extern const BYTE tssk_exponent[];
|
||||
|
||||
FREERDP_API int crypto_rsa_public_encrypt(const BYTE* input, int length, UINT32 key_length,
|
||||
const BYTE* modulus, const BYTE* exponent,
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
*/
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <assert.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
@ -29,8 +29,6 @@
|
||||
|
||||
#include "h264.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define RESOLVE_MEDIANDK_FUNC(sys, name) \
|
||||
({ \
|
||||
BOOL rc = TRUE; \
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/bitstream.h>
|
||||
@ -41,8 +41,6 @@
|
||||
#include "rfx_types.h"
|
||||
#include "progressive.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define TAG FREERDP_TAG("codec.progressive")
|
||||
|
||||
struct _RFX_PROGRESSIVE_UPGRADE_STATE
|
||||
@ -370,13 +368,11 @@ static INLINE PROGRESSIVE_SURFACE_CONTEXT*
|
||||
progressive_get_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId)
|
||||
{
|
||||
void* key = (void*)(((ULONG_PTR)surfaceId) + 1);
|
||||
void* pData = NULL;
|
||||
|
||||
if (!progressive)
|
||||
return NULL;
|
||||
|
||||
pData = HashTable_GetItemValue(progressive->SurfaceContexts, key);
|
||||
return pData;
|
||||
return HashTable_GetItemValue(progressive->SurfaceContexts, key);
|
||||
}
|
||||
|
||||
static void progressive_tile_free(RFX_PROGRESSIVE_TILE* tile)
|
||||
@ -389,10 +385,14 @@ static void progressive_tile_free(RFX_PROGRESSIVE_TILE* tile)
|
||||
}
|
||||
}
|
||||
|
||||
static void progressive_surface_context_free(PROGRESSIVE_SURFACE_CONTEXT* surface)
|
||||
static void progressive_surface_context_free(void* ptr)
|
||||
{
|
||||
PROGRESSIVE_SURFACE_CONTEXT* surface = ptr;
|
||||
UINT32 index;
|
||||
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
for (index = 0; index < surface->gridSize; index++)
|
||||
{
|
||||
RFX_PROGRESSIVE_TILE* tile = &(surface->tiles[index]);
|
||||
@ -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,6 +2741,8 @@ PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor)
|
||||
if (!progressive_context_reset(progressive))
|
||||
goto fail;
|
||||
|
||||
progressive->SurfaceContexts->valueFree = progressive_surface_context_free;
|
||||
|
||||
return progressive;
|
||||
fail:
|
||||
progressive_context_free(progressive);
|
||||
@ -2752,11 +2751,6 @@ fail:
|
||||
|
||||
void progressive_context_free(PROGRESSIVE_CONTEXT* progressive)
|
||||
{
|
||||
int count;
|
||||
int index;
|
||||
ULONG_PTR* pKeys = NULL;
|
||||
PROGRESSIVE_SURFACE_CONTEXT* surface;
|
||||
|
||||
if (!progressive)
|
||||
return;
|
||||
|
||||
@ -2765,21 +2759,7 @@ void progressive_context_free(PROGRESSIVE_CONTEXT* progressive)
|
||||
rfx_context_free(progressive->rfx_context);
|
||||
|
||||
BufferPool_Free(progressive->bufferPool);
|
||||
|
||||
if (progressive->SurfaceContexts)
|
||||
{
|
||||
count = HashTable_GetKeys(progressive->SurfaceContexts, &pKeys);
|
||||
|
||||
for (index = 0; index < count; index++)
|
||||
{
|
||||
surface = (PROGRESSIVE_SURFACE_CONTEXT*)HashTable_GetItemValue(
|
||||
progressive->SurfaceContexts, (void*)pKeys[index]);
|
||||
progressive_surface_context_free(surface);
|
||||
}
|
||||
|
||||
free(pKeys);
|
||||
HashTable_Free(progressive->SurfaceContexts);
|
||||
}
|
||||
HashTable_Free(progressive->SurfaceContexts);
|
||||
|
||||
free(progressive);
|
||||
}
|
||||
|
||||
@ -1071,7 +1071,10 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length,
|
||||
UINT8 channelId;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 2)
|
||||
{
|
||||
WLog_ERR(TAG, "extraBlockLen too small(%" PRIuz ")", Stream_GetRemainingLength(s));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
extraBlockLen = 2;
|
||||
Stream_Read_UINT8(s, codecId); /* codecId (1 byte) must be set to 0x01 */
|
||||
@ -1212,6 +1215,9 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length,
|
||||
NULL, FREERDP_FLIP_NONE))
|
||||
{
|
||||
region16_uninit(&updateRegion);
|
||||
WLog_ERR(TAG,
|
||||
"nbUpdateRectx[% " PRIu32 " (%" PRIu32 ")] freerdp_image_copy failed",
|
||||
j, nbUpdateRects);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -1226,6 +1232,7 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "%s failed", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -2483,7 +2483,23 @@ static long rdg_bio_ctrl(BIO* in_bio, int cmd, long arg1, void* arg2)
|
||||
*/
|
||||
status = BIO_ctrl(tlsOut->bio, cmd, arg1, arg2);
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
else if (cmd == BIO_CTRL_GET_KTLS_SEND)
|
||||
{
|
||||
/* Even though BIO_get_ktls_send says that returning negative values is valid
|
||||
* openssl internal sources are full of if(!BIO_get_ktls_send && ) stuff. This has some
|
||||
* nasty sideeffects. return 0 as proper no KTLS offloading flag
|
||||
*/
|
||||
status = 0;
|
||||
}
|
||||
else if (cmd == BIO_CTRL_GET_KTLS_RECV)
|
||||
{
|
||||
/* Even though BIO_get_ktls_recv says that returning negative values is valid
|
||||
* there is no reason to trust trust negative values are implemented right everywhere
|
||||
*/
|
||||
status = 0;
|
||||
}
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@ -2716,7 +2716,14 @@ static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
|
||||
status = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
case BIO_CTRL_GET_KTLS_SEND:
|
||||
status = 0;
|
||||
break;
|
||||
case BIO_CTRL_GET_KTLS_RECV:
|
||||
status = 0;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -37,7 +37,11 @@ static BOOL update_recv_surfcmd_bitmap_header_ex(wStream* s, TS_COMPRESSED_BITMA
|
||||
return FALSE;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 24)
|
||||
{
|
||||
WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s),
|
||||
24);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, header->highUniqueId);
|
||||
Stream_Read_UINT32(s, header->lowUniqueId);
|
||||
@ -54,7 +58,11 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp)
|
||||
return FALSE;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 12)
|
||||
{
|
||||
WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s),
|
||||
12);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT8(s, bmp->bpp);
|
||||
Stream_Read_UINT8(s, bmp->flags);
|
||||
@ -86,7 +94,11 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp)
|
||||
}
|
||||
|
||||
if (Stream_GetRemainingLength(s) < bmp->bitmapDataLength)
|
||||
{
|
||||
WLog_ERR(TAG, "expected bitmapDataLength %" PRIu32 ", not enough data",
|
||||
bmp->bitmapDataLength);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pos = Stream_GetPosition(s) + bmp->bitmapDataLength;
|
||||
bmp->bitmapData = Stream_Pointer(s);
|
||||
@ -132,7 +144,10 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT
|
||||
SURFACE_BITS_COMMAND cmd = { 0 };
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
{
|
||||
WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 8);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
cmd.cmdType = cmdType;
|
||||
Stream_Read_UINT16(s, cmd.destLeft);
|
||||
@ -152,7 +167,12 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return update->SurfaceBits(update->context, &cmd);
|
||||
if (!update->SurfaceBits(update->context, &cmd))
|
||||
{
|
||||
WLog_DBG(TAG, "update->SurfaceBits implementation failed");
|
||||
goto fail;
|
||||
}
|
||||
return TRUE;
|
||||
fail:
|
||||
return FALSE;
|
||||
}
|
||||
@ -161,11 +181,21 @@ static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s)
|
||||
{
|
||||
SURFACE_FRAME_MARKER marker;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 6)
|
||||
if (Stream_GetRemainingLength(s) < 2)
|
||||
{
|
||||
WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 6);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT16(s, marker.frameAction);
|
||||
Stream_Read_UINT32(s, marker.frameId);
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
WLog_WARN(TAG,
|
||||
"[SERVER-BUG]: got %" PRIuz ", expected %" PRIuz
|
||||
" bytes. [MS-RDPBCGR] 2.2.9.2.3 Frame Marker Command (TS_FRAME_MARKER) is "
|
||||
"missing frameId, ignoring",
|
||||
Stream_GetRemainingLength(s), 4);
|
||||
else
|
||||
Stream_Read_UINT32(s, marker.frameId);
|
||||
WLog_Print(update->log, WLOG_DEBUG,
|
||||
"SurfaceFrameMarker: action: %s (%" PRIu32 ") id: %" PRIu32 "",
|
||||
(!marker.frameAction) ? "Begin" : "End", marker.frameAction, marker.frameId);
|
||||
@ -176,7 +206,13 @@ static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return update->SurfaceFrameMarker(update->context, &marker);
|
||||
if (!update->SurfaceFrameMarker(update->context, &marker))
|
||||
{
|
||||
WLog_DBG(TAG, "update->SurfaceFrameMarker implementation failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int update_recv_surfcmds(rdpUpdate* update, wStream* s)
|
||||
@ -246,10 +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);
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
@ -31,8 +31,6 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
BOOL utils_abort_connect(rdpContext* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
@ -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()
|
||||
@ -51,7 +57,7 @@ if (NOT WIN32)
|
||||
endif()
|
||||
|
||||
# Soname versioning
|
||||
set(RAW_VERSION_STRING "2.6.1")
|
||||
set(RAW_VERSION_STRING "2.7.0")
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
|
||||
elseif(USE_VERSION_FROM_GIT_TAG)
|
||||
|
||||
59
winpr/include/winpr/assert.h
Normal file
59
winpr/include/winpr/assert.h
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Runtime ASSERT macros
|
||||
*
|
||||
* Copyright 2021 Armin Novak <armin.novak@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 */
|
||||
@ -472,8 +472,8 @@ typedef const CERT_CONTEXT* PCCERT_CONTEXT;
|
||||
#define CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE \
|
||||
(CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT)
|
||||
|
||||
HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType,
|
||||
HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void* pvPara);
|
||||
WINPR_API HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType,
|
||||
HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void* pvPara);
|
||||
|
||||
WINPR_API HCERTSTORE CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv, LPCWSTR szSubsystemProtocol);
|
||||
WINPR_API HCERTSTORE CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv, LPCSTR szSubsystemProtocol);
|
||||
@ -597,15 +597,17 @@ extern "C"
|
||||
#define CRYPT_STRING_NOCRLF 0x40000000
|
||||
#define CRYPT_STRING_NOCR 0x80000000
|
||||
|
||||
BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary,
|
||||
DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags);
|
||||
BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary,
|
||||
DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags);
|
||||
WINPR_API BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags,
|
||||
BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip,
|
||||
DWORD* pdwFlags);
|
||||
WINPR_API BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags,
|
||||
BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip,
|
||||
DWORD* pdwFlags);
|
||||
|
||||
BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPWSTR pszString,
|
||||
DWORD* pcchString);
|
||||
BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPSTR pszString,
|
||||
DWORD* pcchString);
|
||||
WINPR_API BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags,
|
||||
LPWSTR pszString, DWORD* pcchString);
|
||||
WINPR_API BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags,
|
||||
LPSTR pszString, DWORD* pcchString);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define CryptStringToBinary CryptStringToBinaryW
|
||||
|
||||
@ -484,13 +484,13 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
|
||||
DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize,
|
||||
va_list* Arguments);
|
||||
WINPR_API DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
|
||||
DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize,
|
||||
va_list* Arguments);
|
||||
|
||||
DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
|
||||
DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize,
|
||||
va_list* Arguments);
|
||||
WINPR_API DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
|
||||
DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize,
|
||||
va_list* Arguments);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define FormatMessage FormatMessageW
|
||||
|
||||
@ -590,9 +590,9 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern const SCARD_IO_REQUEST g_rgSCardT0Pci;
|
||||
extern const SCARD_IO_REQUEST g_rgSCardT1Pci;
|
||||
extern const SCARD_IO_REQUEST g_rgSCardRawPci;
|
||||
WINPR_API extern const SCARD_IO_REQUEST g_rgSCardT0Pci;
|
||||
WINPR_API extern const SCARD_IO_REQUEST g_rgSCardT1Pci;
|
||||
WINPR_API extern const SCARD_IO_REQUEST g_rgSCardRawPci;
|
||||
|
||||
#define SCARD_PCI_T0 (&g_rgSCardT0Pci)
|
||||
#define SCARD_PCI_T1 (&g_rgSCardT1Pci)
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <assert.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/file.h>
|
||||
|
||||
@ -36,8 +36,6 @@
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("registry")
|
||||
|
||||
#define WINPR_ASSERT assert
|
||||
|
||||
#define WINPR_HKLM_HIVE "/etc/winpr/HKLM.reg"
|
||||
|
||||
struct reg_data_type
|
||||
|
||||
@ -22,8 +22,10 @@
|
||||
#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>
|
||||
@ -49,6 +51,8 @@ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
|
||||
DWORD nSize = 0;
|
||||
CHAR* computerName;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!Workstation)
|
||||
{
|
||||
if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
|
||||
@ -91,6 +95,8 @@ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
|
||||
|
||||
static int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!ServicePrincipalName)
|
||||
{
|
||||
context->ServicePrincipalName.Buffer = NULL;
|
||||
@ -116,6 +122,8 @@ static int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
|
||||
DWORD nSize = 0;
|
||||
CHAR* computerName = NULL;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (!name)
|
||||
{
|
||||
if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) ||
|
||||
@ -254,7 +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,7 +556,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE))
|
||||
if ((!pInput) || (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE))
|
||||
{
|
||||
if (!pOutput)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
@ -556,10 +572,10 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||
if (output_buffer->cbBuffer < 1)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (context->state == NTLM_STATE_INITIAL)
|
||||
context->state = NTLM_STATE_NEGOTIATE;
|
||||
if (ntlm_get_state(context) == NTLM_STATE_INITIAL)
|
||||
ntlm_change_state(context, NTLM_STATE_NEGOTIATE);
|
||||
|
||||
if (context->state == NTLM_STATE_NEGOTIATE)
|
||||
if (ntlm_get_state(context) == NTLM_STATE_NEGOTIATE)
|
||||
return ntlm_write_NegotiateMessage(context, output_buffer);
|
||||
|
||||
return SEC_E_OUT_OF_SEQUENCE;
|
||||
@ -585,10 +601,13 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||
context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*)channel_bindings->pvBuffer;
|
||||
}
|
||||
|
||||
if (context->state == NTLM_STATE_CHALLENGE)
|
||||
if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE)
|
||||
{
|
||||
status = ntlm_read_ChallengeMessage(context, input_buffer);
|
||||
|
||||
if (status != SEC_I_CONTINUE_NEEDED)
|
||||
return status;
|
||||
|
||||
if (!pOutput)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
@ -603,7 +622,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||
if (output_buffer->cbBuffer < 1)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (context->state == NTLM_STATE_AUTHENTICATE)
|
||||
if (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE)
|
||||
return ntlm_write_AuthenticateMessage(context, output_buffer);
|
||||
}
|
||||
|
||||
@ -672,7 +691,12 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContex
|
||||
SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof)
|
||||
{
|
||||
BYTE* blob;
|
||||
SecBuffer* target = &ntlm->ChallengeTargetInfo;
|
||||
SecBuffer* target;
|
||||
|
||||
WINPR_ASSERT(ntlm);
|
||||
WINPR_ASSERT(ntproof);
|
||||
|
||||
target = &ntlm->ChallengeTargetInfo;
|
||||
|
||||
if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer))
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
@ -693,8 +717,13 @@ SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof)
|
||||
SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue)
|
||||
{
|
||||
BYTE* blob;
|
||||
ULONG msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
|
||||
ntlm->AuthenticateMessage.cbBuffer;
|
||||
ULONG msgSize;
|
||||
|
||||
WINPR_ASSERT(ntlm);
|
||||
WINPR_ASSERT(micvalue);
|
||||
|
||||
msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer +
|
||||
ntlm->AuthenticateMessage.cbBuffer;
|
||||
|
||||
if (!sspi_SecBufferAlloc(micvalue, msgSize))
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
@ -969,8 +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;
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ enum _NTLM_AV_ID
|
||||
MsvAvTimestamp,
|
||||
MsvAvSingleHost,
|
||||
MsvAvTargetName,
|
||||
MsvChannelBindings
|
||||
MsvAvChannelBindings
|
||||
};
|
||||
typedef enum _NTLM_AV_ID NTLM_AV_ID;
|
||||
|
||||
@ -176,8 +176,7 @@ typedef struct _NTLM_MESSAGE_HEADER NTLM_MESSAGE_HEADER;
|
||||
|
||||
struct _NTLM_NEGOTIATE_MESSAGE
|
||||
{
|
||||
BYTE Signature[8];
|
||||
UINT32 MessageType;
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
NTLM_VERSION_INFO Version;
|
||||
NTLM_MESSAGE_FIELDS DomainName;
|
||||
@ -187,8 +186,7 @@ typedef struct _NTLM_NEGOTIATE_MESSAGE NTLM_NEGOTIATE_MESSAGE;
|
||||
|
||||
struct _NTLM_CHALLENGE_MESSAGE
|
||||
{
|
||||
BYTE Signature[8];
|
||||
UINT32 MessageType;
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
BYTE ServerChallenge[8];
|
||||
BYTE Reserved[8];
|
||||
@ -200,8 +198,7 @@ typedef struct _NTLM_CHALLENGE_MESSAGE NTLM_CHALLENGE_MESSAGE;
|
||||
|
||||
struct _NTLM_AUTHENTICATE_MESSAGE
|
||||
{
|
||||
BYTE Signature[8];
|
||||
UINT32 MessageType;
|
||||
NTLM_MESSAGE_HEADER header;
|
||||
UINT32 NegotiateFlags;
|
||||
NTLM_VERSION_INFO Version;
|
||||
NTLM_MESSAGE_FIELDS DomainName;
|
||||
@ -251,7 +248,7 @@ struct _NTLM_CONTEXT
|
||||
NTLM_NEGOTIATE_MESSAGE NEGOTIATE_MESSAGE;
|
||||
NTLM_CHALLENGE_MESSAGE CHALLENGE_MESSAGE;
|
||||
NTLM_AUTHENTICATE_MESSAGE AUTHENTICATE_MESSAGE;
|
||||
UINT32 MessageIntegrityCheckOffset;
|
||||
size_t MessageIntegrityCheckOffset;
|
||||
SecBuffer NegotiateMessage;
|
||||
SecBuffer ChallengeMessage;
|
||||
SecBuffer AuthenticateMessage;
|
||||
@ -280,6 +277,13 @@ struct _NTLM_CONTEXT
|
||||
};
|
||||
typedef struct _NTLM_CONTEXT NTLM_CONTEXT;
|
||||
|
||||
char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags);
|
||||
const char* ntlm_message_type_string(UINT32 messageType);
|
||||
|
||||
const char* ntlm_state_string(NTLM_STATE state);
|
||||
void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state);
|
||||
NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm);
|
||||
|
||||
SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof);
|
||||
SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue);
|
||||
|
||||
|
||||
@ -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,8 +76,8 @@ static const char* get_av_pair_string(UINT16 pair)
|
||||
return "MsvAvSingleHost";
|
||||
case MsvAvTargetName:
|
||||
return "MsvAvTargetName";
|
||||
case MsvChannelBindings:
|
||||
return "MsvChannelBindings";
|
||||
case MsvAvChannelBindings:
|
||||
return "MsvAvChannelBindings";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@ -87,11 +88,13 @@ static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvP
|
||||
|
||||
static INLINE void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
Data_Write_UINT16(&pAvPair->AvId, id);
|
||||
}
|
||||
|
||||
static INLINE void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
Data_Write_UINT16(&pAvPair->AvLen, len);
|
||||
}
|
||||
|
||||
@ -124,6 +127,7 @@ static INLINE BOOL ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair, size_t size,
|
||||
|
||||
ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
|
||||
{
|
||||
size_t size;
|
||||
size_t cbAvPair;
|
||||
NTLM_AV_PAIR* pAvPair;
|
||||
|
||||
@ -131,7 +135,9 @@ ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
|
||||
if (!pAvPair)
|
||||
return 0;
|
||||
|
||||
return ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR);
|
||||
size = ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR);
|
||||
WINPR_ASSERT(size <= ULONG_MAX);
|
||||
return (ULONG)size;
|
||||
}
|
||||
|
||||
static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pAvLen)
|
||||
@ -149,6 +155,7 @@ static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
|
||||
{
|
||||
UINT16 pair;
|
||||
@ -158,19 +165,20 @@ void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
|
||||
if (!ntlm_av_pair_check(pAvPair, cbAvPair))
|
||||
return;
|
||||
|
||||
WLog_INFO(TAG, "AV_PAIRs =");
|
||||
WLog_VRB(TAG, "AV_PAIRs =");
|
||||
|
||||
while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL))
|
||||
{
|
||||
size_t cbLen = 0;
|
||||
ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen);
|
||||
|
||||
WLog_INFO(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair);
|
||||
winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair), cbLen);
|
||||
WLog_VRB(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen);
|
||||
|
||||
pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength)
|
||||
{
|
||||
@ -180,6 +188,7 @@ static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength
|
||||
|
||||
PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
|
||||
{
|
||||
WINPR_ASSERT(pAvPair);
|
||||
return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
|
||||
}
|
||||
|
||||
@ -259,11 +268,11 @@ static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTL
|
||||
if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen)
|
||||
return FALSE;
|
||||
|
||||
ntlm_av_pair_set_id(pAvPair, AvId);
|
||||
ntlm_av_pair_set_id(pAvPair, (UINT16)AvId);
|
||||
ntlm_av_pair_set_len(pAvPair, AvLen);
|
||||
if (AvLen)
|
||||
{
|
||||
assert(Value != NULL);
|
||||
WINPR_ASSERT(Value != NULL);
|
||||
CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen);
|
||||
}
|
||||
|
||||
@ -286,8 +295,9 @@ static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList
|
||||
if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(avLen <= UINT16_MAX);
|
||||
return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair,
|
||||
ntlm_av_pair_get_value_pointer(pAvPair), avLen);
|
||||
ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen);
|
||||
}
|
||||
|
||||
static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
|
||||
@ -297,6 +307,8 @@ static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FO
|
||||
DWORD nSize = 0;
|
||||
CHAR* computerName;
|
||||
|
||||
WINPR_ASSERT(pName);
|
||||
|
||||
if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || GetLastError() != ERROR_MORE_DATA)
|
||||
return -1;
|
||||
|
||||
@ -394,6 +406,9 @@ static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context)
|
||||
BYTE* ChannelBindingToken;
|
||||
UINT32 ChannelBindingTokenLength;
|
||||
SEC_CHANNEL_BINDINGS* ChannelBindings;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH);
|
||||
ChannelBindings = context->Bindings.Bindings;
|
||||
|
||||
@ -436,6 +451,7 @@ out:
|
||||
|
||||
static void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
/**
|
||||
* The Single_Host_Data structure allows a client to send machine-specific information
|
||||
* within an authentication exchange to services on the same machine. The client can
|
||||
@ -451,10 +467,10 @@ static void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
|
||||
FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
|
||||
}
|
||||
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
int rc = -1;
|
||||
int length;
|
||||
BOOL rc = FALSE;
|
||||
ULONG length;
|
||||
ULONG AvPairsCount;
|
||||
ULONG AvPairsLength;
|
||||
NTLM_AV_PAIR* pAvPairList;
|
||||
@ -464,6 +480,8 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
UNICODE_STRING DnsDomainName = { 0 };
|
||||
UNICODE_STRING DnsComputerName = { 0 };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
|
||||
goto fail;
|
||||
|
||||
@ -516,7 +534,7 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
sizeof(context->Timestamp)))
|
||||
goto fail;
|
||||
|
||||
rc = 1;
|
||||
rc = TRUE;
|
||||
fail:
|
||||
ntlm_free_unicode_string(&NbDomainName);
|
||||
ntlm_free_unicode_string(&NbComputerName);
|
||||
@ -525,7 +543,7 @@ fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
ULONG size;
|
||||
ULONG AvPairsCount;
|
||||
@ -546,6 +564,9 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
size_t cbAvDnsTreeName;
|
||||
size_t cbChallengeTargetInfo;
|
||||
size_t cbAuthenticateTargetInfo;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
AvPairsCount = 1;
|
||||
AvPairsValueLength = 0;
|
||||
ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer;
|
||||
@ -635,7 +656,7 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
* SEC_CHANNEL_BINDINGS structure
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd919963/
|
||||
*/
|
||||
AvPairsCount++; /* MsvChannelBindings */
|
||||
AvPairsCount++; /* MsvAvChannelBindings */
|
||||
AvPairsValueLength += 16;
|
||||
ntlm_compute_channel_bindings(context);
|
||||
|
||||
@ -714,15 +735,17 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
|
||||
if (context->SendSingleHostData)
|
||||
{
|
||||
WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX);
|
||||
if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost,
|
||||
(PBYTE)&context->SingleHostData, context->SingleHostData.Size))
|
||||
(PBYTE)&context->SingleHostData,
|
||||
(UINT16)context->SingleHostData.Size))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!context->SuppressExtendedProtection)
|
||||
{
|
||||
if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvChannelBindings,
|
||||
context->ChannelBindingsHash, 16))
|
||||
if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
|
||||
MsvAvChannelBindings, context->ChannelBindingsHash, 16))
|
||||
goto fail;
|
||||
|
||||
if (context->ServicePrincipalName.Length > 0)
|
||||
@ -745,8 +768,8 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR));
|
||||
}
|
||||
|
||||
return 1;
|
||||
return TRUE;
|
||||
fail:
|
||||
sspi_SecBufferFree(&context->AuthenticateTargetInfo);
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include "ntlm.h"
|
||||
#include "../sspi.h"
|
||||
@ -38,16 +38,10 @@
|
||||
#include "../../log.h"
|
||||
#define TAG WINPR_TAG("sspi.NTLM")
|
||||
|
||||
const char LM_MAGIC[] = "KGS!@#$%";
|
||||
|
||||
static const char NTLM_CLIENT_SIGN_MAGIC[] =
|
||||
"session key to client-to-server signing key magic constant";
|
||||
static const char NTLM_SERVER_SIGN_MAGIC[] =
|
||||
"session key to server-to-client signing key magic constant";
|
||||
static const char NTLM_CLIENT_SEAL_MAGIC[] =
|
||||
"session key to client-to-server sealing key magic constant";
|
||||
static const char NTLM_SERVER_SEAL_MAGIC[] =
|
||||
"session key to server-to-client sealing key magic constant";
|
||||
static char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant";
|
||||
static char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client signing key magic constant";
|
||||
static char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant";
|
||||
static char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant";
|
||||
|
||||
static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
@ -58,16 +52,21 @@ static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
OSVERSIONINFOA osVersionInfo;
|
||||
OSVERSIONINFOA osVersionInfo = { 0 };
|
||||
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
||||
GetVersionExA(&osVersionInfo);
|
||||
if (!GetVersionExA(&osVersionInfo))
|
||||
return FALSE;
|
||||
versionInfo->ProductMajorVersion = (UINT8)osVersionInfo.dwMajorVersion;
|
||||
versionInfo->ProductMinorVersion = (UINT8)osVersionInfo.dwMinorVersion;
|
||||
versionInfo->ProductBuild = (UINT16)osVersionInfo.dwBuildNumber;
|
||||
ZeroMemory(versionInfo->Reserved, sizeof(versionInfo->Reserved));
|
||||
versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,17 +75,24 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
* @param s
|
||||
*/
|
||||
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz,
|
||||
Stream_GetRemainingLength(s), 8);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
|
||||
Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
|
||||
Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
|
||||
Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,13 +101,24 @@ int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
if (Stream_GetRemainingCapacity(s) < 5 + sizeof(versionInfo->Reserved))
|
||||
{
|
||||
WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz,
|
||||
Stream_GetRemainingCapacity(s), 5 + sizeof(versionInfo->Reserved));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
|
||||
Stream_Write_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
|
||||
Stream_Write_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
|
||||
Stream_Write(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
|
||||
Stream_Write_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,23 +126,33 @@ void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
* VERSION @msdn{cc236654}
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
WLog_INFO(TAG, "VERSION ={");
|
||||
WLog_INFO(TAG, "\tProductMajorVersion: %" PRIu8 "", versionInfo->ProductMajorVersion);
|
||||
WLog_INFO(TAG, "\tProductMinorVersion: %" PRIu8 "", versionInfo->ProductMinorVersion);
|
||||
WLog_INFO(TAG, "\tProductBuild: %" PRIu16 "", versionInfo->ProductBuild);
|
||||
WLog_INFO(TAG, "\tReserved: 0x%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "", versionInfo->Reserved[0],
|
||||
versionInfo->Reserved[1], versionInfo->Reserved[2]);
|
||||
WLog_INFO(TAG, "\tNTLMRevisionCurrent: 0x%02" PRIX8 "", versionInfo->NTLMRevisionCurrent);
|
||||
}
|
||||
WINPR_ASSERT(versionInfo);
|
||||
|
||||
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);
|
||||
@ -137,21 +164,39 @@ static int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENG
|
||||
size = Stream_Length(s) - Stream_GetPosition(s);
|
||||
|
||||
if (size > UINT32_MAX)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::cbAvPairs too large, got %" PRIuz "bytes", size);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
challenge->cbAvPairs = size;
|
||||
challenge->cbAvPairs = (UINT32)size;
|
||||
challenge->AvPairs = (NTLM_AV_PAIR*)malloc(challenge->cbAvPairs);
|
||||
|
||||
if (!challenge->AvPairs)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::AvPairs failed to allocate %" PRIu32 "bytes",
|
||||
challenge->cbAvPairs);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read(s, challenge->AvPairs, size);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
static BOOL ntlm_write_ntlm_v2_client_challenge(wStream* s,
|
||||
const NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
ULONG length;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(challenge);
|
||||
|
||||
if (Stream_GetRemainingCapacity(s) < 28)
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE expected 28bytes, have %" PRIuz "bytes",
|
||||
Stream_GetRemainingCapacity(s));
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Write_UINT8(s, challenge->RespType);
|
||||
Stream_Write_UINT8(s, challenge->HiRespType);
|
||||
Stream_Write_UINT16(s, challenge->Reserved1);
|
||||
@ -160,20 +205,44 @@ static int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLEN
|
||||
Stream_Write(s, challenge->ClientChallenge, 8);
|
||||
Stream_Write_UINT32(s, challenge->Reserved3);
|
||||
length = ntlm_av_pair_list_length(challenge->AvPairs, challenge->cbAvPairs);
|
||||
if (Stream_GetRemainingCapacity(s) < length)
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"NTLMv2_CLIENT_CHALLENGE::AvPairs expected %" PRIu32 "bytes, have %" PRIuz "bytes",
|
||||
length, Stream_GetRemainingCapacity(s));
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Write(s, challenge->AvPairs, length);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(response);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 16)
|
||||
return -1;
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_RESPONSE expected 16bytes, have %" PRIuz "bytes",
|
||||
Stream_GetRemainingLength(s));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Read(s, response->Response, 16);
|
||||
return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(response);
|
||||
|
||||
if (Stream_GetRemainingCapacity(s) < 16)
|
||||
{
|
||||
WLog_ERR(TAG, "NTLMv2_RESPONSE expected 16bytes, have %" PRIuz "bytes",
|
||||
Stream_GetRemainingCapacity(s));
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Write(s, response->Response, 16);
|
||||
return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
@ -185,8 +254,11 @@ int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
|
||||
void ntlm_current_time(BYTE* timestamp)
|
||||
{
|
||||
FILETIME filetime;
|
||||
ULARGE_INTEGER time64;
|
||||
FILETIME filetime = { 0 };
|
||||
ULARGE_INTEGER time64 = { 0 };
|
||||
|
||||
WINPR_ASSERT(timestamp);
|
||||
|
||||
GetSystemTimeAsFileTime(&filetime);
|
||||
time64.u.LowPart = filetime.dwLowDateTime;
|
||||
time64.u.HighPart = filetime.dwHighDateTime;
|
||||
@ -200,127 +272,137 @@ void ntlm_current_time(BYTE* timestamp)
|
||||
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (memcmp(context->ChallengeTimestamp, NTLM_NULL_BUFFER, 8) != 0)
|
||||
CopyMemory(context->Timestamp, context->ChallengeTimestamp, 8);
|
||||
else
|
||||
ntlm_current_time(context->Timestamp);
|
||||
}
|
||||
|
||||
static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
static BOOL ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
WINPR_SAM* sam;
|
||||
WINPR_SAM_ENTRY* entry;
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
BOOL rc = FALSE;
|
||||
WINPR_SAM* sam = NULL;
|
||||
WINPR_SAM_ENTRY* entry = NULL;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
credentials = context->credentials;
|
||||
sam = SamOpen(context->SamFile, TRUE);
|
||||
|
||||
if (!sam)
|
||||
return -1;
|
||||
goto fail;
|
||||
|
||||
entry = SamLookupUserW(
|
||||
sam, (LPWSTR)credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * 2);
|
||||
sam, (LPWSTR)credentials->identity.User, credentials->identity.UserLength * sizeof(WCHAR),
|
||||
(LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * sizeof(WCHAR));
|
||||
|
||||
if (entry)
|
||||
if (!entry)
|
||||
{
|
||||
entry = SamLookupUserW(sam, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * sizeof(WCHAR), NULL, 0);
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
goto fail;
|
||||
|
||||
#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;
|
||||
}
|
||||
NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * sizeof(WCHAR),
|
||||
(LPWSTR)credentials->identity.Domain,
|
||||
credentials->identity.DomainLength * sizeof(WCHAR), (BYTE*)hash);
|
||||
|
||||
entry = SamLookupUserW(sam, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * 2, NULL, 0);
|
||||
|
||||
if (entry)
|
||||
{
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
WLog_DBG(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;
|
||||
}
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
SamFreeEntry(sam, entry);
|
||||
SamClose(sam);
|
||||
return 1;
|
||||
if (!rc)
|
||||
WLog_ERR(TAG, "Error: Could not find user in SAM database");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
int status;
|
||||
int i, hn, ln;
|
||||
int i;
|
||||
char* PasswordHash = NULL;
|
||||
UINT32 PasswordHashLength = 0;
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
INT64 PasswordHashLength = 0;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
credentials = context->credentials;
|
||||
/* Password contains a password hash of length (PasswordLength -
|
||||
* SSPI_CREDENTIALS_HASH_LENGTH_OFFSET) */
|
||||
PasswordHashLength = credentials->identity.PasswordLength - SSPI_CREDENTIALS_HASH_LENGTH_OFFSET;
|
||||
WINPR_ASSERT(PasswordHashLength >= 0);
|
||||
WINPR_ASSERT(PasswordHashLength <= INT_MAX);
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR)credentials->identity.Password,
|
||||
PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
(int)PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
CharUpperBuffA(PasswordHash, PasswordHashLength);
|
||||
CharUpperBuffA(PasswordHash, (DWORD)PasswordHashLength);
|
||||
|
||||
for (i = 0; i < 32; i += 2)
|
||||
{
|
||||
hn = PasswordHash[i] > '9' ? PasswordHash[i] - 'A' + 10 : PasswordHash[i] - '0';
|
||||
ln = PasswordHash[i + 1] > '9' ? PasswordHash[i + 1] - 'A' + 10 : PasswordHash[i + 1] - '0';
|
||||
hash[i / 2] = (hn << 4) | ln;
|
||||
BYTE hn =
|
||||
(BYTE)(PasswordHash[i] > '9' ? PasswordHash[i] - 'A' + 10 : PasswordHash[i] - '0');
|
||||
BYTE ln = (BYTE)(PasswordHash[i + 1] > '9' ? PasswordHash[i + 1] - 'A' + 10
|
||||
: PasswordHash[i + 1] - '0');
|
||||
hash[i / 2] = (BYTE)((hn << 4) | ln);
|
||||
}
|
||||
|
||||
free(PasswordHash);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
static BOOL ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(hash);
|
||||
|
||||
credentials = context->credentials;
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
|
||||
if (credentials)
|
||||
{
|
||||
WLog_DBG(TAG, "Password (length = %" PRIu32 ")", credentials->identity.PasswordLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.Password,
|
||||
WLog_VRB(TAG, "Password (length = %" PRIu32 ")", credentials->identity.PasswordLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Password,
|
||||
credentials->identity.PasswordLength * 2);
|
||||
WLog_DBG(TAG, "Username (length = %" PRIu32 ")", credentials->identity.UserLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.User,
|
||||
WLog_VRB(TAG, "Username (length = %" PRIu32 ")", credentials->identity.UserLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.User,
|
||||
credentials->identity.UserLength * 2);
|
||||
WLog_DBG(TAG, "Domain (length = %" PRIu32 ")", credentials->identity.DomainLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.Domain,
|
||||
WLog_VRB(TAG, "Domain (length = %" PRIu32 ")", credentials->identity.DomainLength * 2);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Domain,
|
||||
credentials->identity.DomainLength * 2);
|
||||
}
|
||||
else
|
||||
WLog_DBG(TAG, "Strange, NTLM_CONTEXT is missing valid credentials...");
|
||||
WLog_VRB(TAG, "Strange, NTLM_CONTEXT is missing valid credentials...");
|
||||
|
||||
WLog_DBG(TAG, "Workstation (length = %" PRIu16 ")", context->Workstation.Length);
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)context->Workstation.Buffer, context->Workstation.Length);
|
||||
WLog_DBG(TAG, "NTOWFv2, NTLMv2 Hash");
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH);
|
||||
WLog_VRB(TAG, "Workstation (length = %" PRIu16 ")", context->Workstation.Length);
|
||||
winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)context->Workstation.Buffer, context->Workstation.Length);
|
||||
WLog_VRB(TAG, "NTOWFv2, NTLMv2 Hash");
|
||||
winpr_HexDump(TAG, WLOG_TRACE, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH);
|
||||
#endif
|
||||
|
||||
if (memcmp(context->NtlmV2Hash, NTLM_NULL_BUFFER, 16) != 0)
|
||||
return 1;
|
||||
return TRUE;
|
||||
|
||||
if (!credentials)
|
||||
return -1;
|
||||
return FALSE;
|
||||
else if (memcmp(context->NtlmHash, NTLM_NULL_BUFFER, 16) != 0)
|
||||
{
|
||||
NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User,
|
||||
@ -331,7 +413,7 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
/* Special case for WinPR: password hash */
|
||||
if (ntlm_convert_password_hash(context, context->NtlmHash) < 0)
|
||||
return -1;
|
||||
return FALSE;
|
||||
|
||||
NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User,
|
||||
credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain,
|
||||
@ -350,55 +432,57 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
SecBuffer proofValue, micValue;
|
||||
|
||||
if (ntlm_computeProofValue(context, &proofValue) != SEC_E_OK)
|
||||
return -1;
|
||||
return FALSE;
|
||||
|
||||
if (ntlm_computeMicValue(context, &micValue) != SEC_E_OK)
|
||||
{
|
||||
sspi_SecBufferFree(&proofValue);
|
||||
return -1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = context->HashCallback(context->HashCallbackArg, &credentials->identity, &proofValue,
|
||||
context->EncryptedRandomSessionKey,
|
||||
(&context->AUTHENTICATE_MESSAGE)->MessageIntegrityCheck,
|
||||
&micValue, hash);
|
||||
context->AUTHENTICATE_MESSAGE.MessageIntegrityCheck, &micValue,
|
||||
hash);
|
||||
sspi_SecBufferFree(&proofValue);
|
||||
sspi_SecBufferFree(&micValue);
|
||||
return ret ? 1 : -1;
|
||||
return ret ? TRUE : FALSE;
|
||||
}
|
||||
else if (context->UseSamFileDatabase)
|
||||
{
|
||||
return ntlm_fetch_ntlm_v2_hash(context, hash);
|
||||
}
|
||||
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE* response;
|
||||
BYTE value[WINPR_MD5_DIGEST_LENGTH];
|
||||
BYTE value[WINPR_MD5_DIGEST_LENGTH] = { 0 };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (context->LmCompatibilityLevel < 2)
|
||||
{
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
return FALSE;
|
||||
|
||||
ZeroMemory(context->LmChallengeResponse.pvBuffer, 24);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
|
||||
if (ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash) < 0)
|
||||
return -1;
|
||||
if (!ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash))
|
||||
return FALSE;
|
||||
|
||||
/* Concatenate the server and client challenges */
|
||||
CopyMemory(value, context->ServerChallenge, 8);
|
||||
CopyMemory(&value[8], context->ClientChallenge, 8);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
return FALSE;
|
||||
|
||||
response = (BYTE*)context->LmChallengeResponse.pvBuffer;
|
||||
/* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */
|
||||
@ -407,7 +491,7 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
/* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response
|
||||
* (24 bytes) */
|
||||
CopyMemory(&response[16], context->ClientChallenge, 8);
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -417,13 +501,17 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE* blob;
|
||||
SecBuffer ntlm_v2_temp = { 0 };
|
||||
SecBuffer ntlm_v2_temp_chal = { 0 };
|
||||
PSecBuffer TargetInfo = &context->ChallengeTargetInfo;
|
||||
int ret = -1;
|
||||
PSecBuffer TargetInfo;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
TargetInfo = &context->ChallengeTargetInfo;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
|
||||
goto exit;
|
||||
@ -432,7 +520,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
blob = (BYTE*)ntlm_v2_temp.pvBuffer;
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
if (ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash) < 0)
|
||||
if (!ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash))
|
||||
goto exit;
|
||||
|
||||
/* Construct temp */
|
||||
@ -445,8 +533,8 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
/* Reserved3 (4 bytes) */
|
||||
CopyMemory(&blob[28], TargetInfo->pvBuffer, TargetInfo->cbBuffer);
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
WLog_DBG(TAG, "NTLMv2 Response Temp Blob");
|
||||
winpr_HexDump(TAG, WLOG_DEBUG, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
WLog_VRB(TAG, "NTLMv2 Response Temp Blob");
|
||||
winpr_HexDump(TAG, WLOG_TRACE, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
#endif
|
||||
|
||||
/* Concatenate server challenge with temp */
|
||||
@ -473,7 +561,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH,
|
||||
context->NtProofString, WINPR_MD5_DIGEST_LENGTH, context->SessionBaseKey,
|
||||
WINPR_MD5_DIGEST_LENGTH);
|
||||
ret = 1;
|
||||
ret = TRUE;
|
||||
exit:
|
||||
sspi_SecBufferFree(&ntlm_v2_temp);
|
||||
sspi_SecBufferFree(&ntlm_v2_temp_chal);
|
||||
@ -488,7 +576,7 @@ exit:
|
||||
* @param ciphertext cipher text
|
||||
*/
|
||||
|
||||
void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext)
|
||||
void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext)
|
||||
{
|
||||
WINPR_RC4_CTX* rc4 = winpr_RC4_New(key, 16);
|
||||
|
||||
@ -506,9 +594,11 @@ void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext)
|
||||
|
||||
void ntlm_generate_client_challenge(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
/* ClientChallenge is used in computation of LMv2 and NTLMv2 responses */
|
||||
if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, 8) == 0)
|
||||
winpr_RAND(context->ClientChallenge, 8);
|
||||
if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, sizeof(context->ClientChallenge)) == 0)
|
||||
winpr_RAND(context->ClientChallenge, sizeof(context->ClientChallenge));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -518,8 +608,10 @@ void ntlm_generate_client_challenge(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_server_challenge(NTLM_CONTEXT* context)
|
||||
{
|
||||
if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, 8) == 0)
|
||||
winpr_RAND(context->ServerChallenge, 8);
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, sizeof(context->ServerChallenge)) == 0)
|
||||
winpr_RAND(context->ServerChallenge, sizeof(context->ServerChallenge));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -530,8 +622,11 @@ void ntlm_generate_server_challenge(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(sizeof(context->KeyExchangeKey) == sizeof(context->SessionBaseKey));
|
||||
|
||||
/* In NTLMv2, KeyExchangeKey is the 128-bit SessionBaseKey */
|
||||
CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, 16);
|
||||
CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, sizeof(context->KeyExchangeKey));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -541,7 +636,8 @@ void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
winpr_RAND(context->RandomSessionKey, 16);
|
||||
WINPR_ASSERT(context);
|
||||
winpr_RAND(context->RandomSessionKey, sizeof(context->RandomSessionKey));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -551,7 +647,10 @@ void ntlm_generate_random_session_key(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_exported_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, 16);
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
CopyMemory(context->ExportedSessionKey, context->RandomSessionKey,
|
||||
sizeof(context->ExportedSessionKey));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -563,6 +662,7 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the
|
||||
* KeyExchangeKey */
|
||||
WINPR_ASSERT(context);
|
||||
ntlm_rc4k(context->KeyExchangeKey, 16, context->RandomSessionKey,
|
||||
context->EncryptedRandomSessionKey);
|
||||
}
|
||||
@ -574,6 +674,8 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
/* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the
|
||||
* KeyExchangeKey */
|
||||
|
||||
@ -583,10 +685,18 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
* AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey) else Set RandomSessionKey to KeyExchangeKey
|
||||
*/
|
||||
if (context->NegotiateKeyExchange)
|
||||
ntlm_rc4k(context->KeyExchangeKey, 16, context->EncryptedRandomSessionKey,
|
||||
context->RandomSessionKey);
|
||||
{
|
||||
WINPR_ASSERT(sizeof(context->EncryptedRandomSessionKey) ==
|
||||
sizeof(context->RandomSessionKey));
|
||||
ntlm_rc4k(context->KeyExchangeKey, sizeof(context->EncryptedRandomSessionKey),
|
||||
context->EncryptedRandomSessionKey, context->RandomSessionKey);
|
||||
}
|
||||
else
|
||||
CopyMemory(context->RandomSessionKey, context->KeyExchangeKey, 16);
|
||||
{
|
||||
WINPR_ASSERT(sizeof(context->RandomSessionKey) == sizeof(context->KeyExchangeKey));
|
||||
CopyMemory(context->RandomSessionKey, context->KeyExchangeKey,
|
||||
sizeof(context->RandomSessionKey));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -597,29 +707,32 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
* @param signing_key Destination signing key
|
||||
*/
|
||||
|
||||
static int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic,
|
||||
BYTE* signing_key)
|
||||
static BOOL ntlm_generate_signing_key(BYTE* exported_session_key, const SecBuffer* sign_magic,
|
||||
BYTE* signing_key)
|
||||
{
|
||||
int length;
|
||||
BYTE* value;
|
||||
BOOL rc = FALSE;
|
||||
size_t length;
|
||||
BYTE* value = NULL;
|
||||
|
||||
WINPR_ASSERT(exported_session_key);
|
||||
WINPR_ASSERT(sign_magic);
|
||||
WINPR_ASSERT(signing_key);
|
||||
|
||||
length = WINPR_MD5_DIGEST_LENGTH + sign_magic->cbBuffer;
|
||||
value = (BYTE*)malloc(length);
|
||||
|
||||
if (!value)
|
||||
return -1;
|
||||
goto out;
|
||||
|
||||
/* Concatenate ExportedSessionKey with sign magic */
|
||||
CopyMemory(value, exported_session_key, WINPR_MD5_DIGEST_LENGTH);
|
||||
CopyMemory(&value[WINPR_MD5_DIGEST_LENGTH], sign_magic->pvBuffer, sign_magic->cbBuffer);
|
||||
|
||||
if (!winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH))
|
||||
{
|
||||
free(value);
|
||||
return -1;
|
||||
}
|
||||
rc = winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH);
|
||||
|
||||
out:
|
||||
free(value);
|
||||
return 1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -628,12 +741,13 @@ static int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer signMagic;
|
||||
signMagic.pvBuffer = (void*)NTLM_CLIENT_SIGN_MAGIC;
|
||||
signMagic.cbBuffer = sizeof(NTLM_CLIENT_SIGN_MAGIC);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ClientSigningKey);
|
||||
const SecBuffer signMagic = { sizeof(NTLM_CLIENT_SIGN_MAGIC), 0, NTLM_CLIENT_SIGN_MAGIC };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic,
|
||||
context->ClientSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -642,45 +756,13 @@ void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer signMagic;
|
||||
signMagic.pvBuffer = (void*)NTLM_SERVER_SIGN_MAGIC;
|
||||
signMagic.cbBuffer = sizeof(NTLM_SERVER_SIGN_MAGIC);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ServerSigningKey);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -689,12 +771,13 @@ static int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer sealMagic;
|
||||
sealMagic.pvBuffer = (void*)NTLM_CLIENT_SEAL_MAGIC;
|
||||
sealMagic.cbBuffer = sizeof(NTLM_CLIENT_SEAL_MAGIC);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ClientSealingKey);
|
||||
const SecBuffer sealMagic = { sizeof(NTLM_CLIENT_SEAL_MAGIC), 0, NTLM_CLIENT_SEAL_MAGIC };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic,
|
||||
context->ClientSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -703,12 +786,13 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer sealMagic;
|
||||
sealMagic.pvBuffer = (void*)NTLM_SERVER_SEAL_MAGIC;
|
||||
sealMagic.cbBuffer = sizeof(NTLM_SERVER_SEAL_MAGIC);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ServerSealingKey);
|
||||
const SecBuffer sealMagic = { sizeof(NTLM_SERVER_SEAL_MAGIC), 0, NTLM_SERVER_SEAL_MAGIC };
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic,
|
||||
context->ServerSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -718,14 +802,17 @@ void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context)
|
||||
{
|
||||
WINPR_ASSERT(context);
|
||||
if (context->server)
|
||||
{
|
||||
context->SendSigningKey = context->ServerSigningKey;
|
||||
context->RecvSigningKey = context->ClientSigningKey;
|
||||
context->SendSealingKey = context->ClientSealingKey;
|
||||
context->RecvSealingKey = context->ServerSealingKey;
|
||||
context->SendRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16);
|
||||
context->RecvRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16);
|
||||
context->SendRc4Seal =
|
||||
winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey));
|
||||
context->RecvRc4Seal =
|
||||
winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -733,22 +820,29 @@ void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context)
|
||||
context->RecvSigningKey = context->ServerSigningKey;
|
||||
context->SendSealingKey = context->ServerSealingKey;
|
||||
context->RecvSealingKey = context->ClientSealingKey;
|
||||
context->SendRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16);
|
||||
context->RecvRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16);
|
||||
context->SendRc4Seal =
|
||||
winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey));
|
||||
context->RecvRc4Seal =
|
||||
winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey));
|
||||
}
|
||||
}
|
||||
|
||||
void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size)
|
||||
BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
/*
|
||||
* Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE,
|
||||
* CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey
|
||||
*/
|
||||
WINPR_HMAC_CTX* hmac = winpr_HMAC_New();
|
||||
assert(size >= WINPR_MD5_DIGEST_LENGTH);
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(mic);
|
||||
WINPR_ASSERT(size >= WINPR_MD5_DIGEST_LENGTH);
|
||||
|
||||
memset(mic, 0, size);
|
||||
if (!hmac)
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
if (winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->ExportedSessionKey, WINPR_MD5_DIGEST_LENGTH))
|
||||
{
|
||||
@ -756,10 +850,27 @@ void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT
|
||||
context->NegotiateMessage.cbBuffer);
|
||||
winpr_HMAC_Update(hmac, (BYTE*)context->ChallengeMessage.pvBuffer,
|
||||
context->ChallengeMessage.cbBuffer);
|
||||
winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer,
|
||||
context->AuthenticateMessage.cbBuffer);
|
||||
|
||||
if (context->MessageIntegrityCheckOffset > 0)
|
||||
{
|
||||
const BYTE* auth = (BYTE*)context->AuthenticateMessage.pvBuffer;
|
||||
const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 };
|
||||
const size_t rest = context->MessageIntegrityCheckOffset + sizeof(data);
|
||||
|
||||
WINPR_ASSERT(rest <= context->AuthenticateMessage.cbBuffer);
|
||||
winpr_HMAC_Update(hmac, &auth[0], context->MessageIntegrityCheckOffset);
|
||||
winpr_HMAC_Update(hmac, data, sizeof(data));
|
||||
winpr_HMAC_Update(hmac, &auth[rest], context->AuthenticateMessage.cbBuffer - rest);
|
||||
}
|
||||
else
|
||||
{
|
||||
winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer,
|
||||
context->AuthenticateMessage.cbBuffer);
|
||||
}
|
||||
winpr_HMAC_Final(hmac, mic, WINPR_MD5_DIGEST_LENGTH);
|
||||
rc = TRUE;
|
||||
}
|
||||
|
||||
winpr_HMAC_Free(hmac);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -24,13 +24,16 @@
|
||||
|
||||
#include "ntlm_av_pairs.h"
|
||||
|
||||
void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo);
|
||||
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo);
|
||||
#endif
|
||||
|
||||
BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response);
|
||||
|
||||
void ntlm_output_target_name(NTLM_CONTEXT* context);
|
||||
void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
|
||||
@ -38,10 +41,10 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
|
||||
void ntlm_current_time(BYTE* timestamp);
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context);
|
||||
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext);
|
||||
void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext);
|
||||
void ntlm_generate_client_challenge(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_server_challenge(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context);
|
||||
@ -50,12 +53,12 @@ void ntlm_generate_exported_session_key(NTLM_CONTEXT* context);
|
||||
void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context);
|
||||
void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_generate_client_signing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_server_signing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context);
|
||||
BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context);
|
||||
void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size);
|
||||
BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size);
|
||||
|
||||
#endif /* WINPR_AUTH_NTLM_COMPUTE_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
||||
@ -467,18 +467,15 @@ void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
|
||||
free(ntlm);
|
||||
}
|
||||
|
||||
int TestNTLM(int argc, char* argv[])
|
||||
static BOOL test_default(void)
|
||||
{
|
||||
int status;
|
||||
int rc = -1;
|
||||
BOOL rc = FALSE;
|
||||
PSecBuffer pSecBuffer;
|
||||
TEST_NTLM_CLIENT* client = NULL;
|
||||
TEST_NTLM_SERVER* server = NULL;
|
||||
BOOL DynamicTest = TRUE;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
/**
|
||||
* Client Initialization
|
||||
*/
|
||||
@ -684,7 +681,7 @@ int TestNTLM(int argc, char* argv[])
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
/**
|
||||
@ -694,3 +691,13 @@ fail:
|
||||
test_ntlm_server_free(server);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestNTLM(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!test_default())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -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:
|
||||
*
|
||||
|
||||
Loading…
Reference in New Issue
Block a user