diff --git a/CMakeLists.txt b/CMakeLists.txt index 930eee1..172832f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/ChangeLog b/ChangeLog index 5d32697..ad92d8b 100644 --- a/ChangeLog +++ b/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) diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c index bf4ce26..d8eb8ec 100644 --- a/channels/ainput/client/ainput_main.c +++ b/channels/ainput/client/ainput_main.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include @@ -37,8 +37,6 @@ #include "../common/ainput_common.h" -#define WINPR_ASSERT(x) assert(x) - #define TAG CHANNELS_TAG("ainput.client") typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK; diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c index 670b668..bc1737e 100644 --- a/channels/ainput/server/ainput_main.c +++ b/channels/ainput/server/ainput_main.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -39,8 +39,6 @@ #include "../common/ainput_common.h" -#define WINPR_ASSERT(x) assert(x) - #define TAG CHANNELS_TAG("ainput.server") typedef enum diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 309d24c..681ebce 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -1114,7 +1115,10 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) size_t computerNameLenW; if (!rdpdr->computerName[0]) - gethostname(rdpdr->computerName, sizeof(rdpdr->computerName) - 1); + { + DWORD size = sizeof(rdpdr->computerName) - 1; + GetComputerNameA(rdpdr->computerName, &size); + } computerNameLenW = ConvertToUnicode(CP_UTF8, 0, rdpdr->computerName, -1, &computerNameW, 0) * 2; s = Stream_New(NULL, 16 + computerNameLenW + 2); diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c index c0bc0b0..03fc97c 100644 --- a/channels/rdpgfx/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -24,12 +24,10 @@ #endif #include -#include +#include #include #include -#define WINPR_ASSERT(x) assert(x) - #define TAG CHANNELS_TAG("rdpgfx.common") #include "rdpgfx_common.h" diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index be0ca14..537aef6 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -673,12 +673,40 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) DWORD bytesReturned; RdpsndServerPrivate* priv = context->priv; UINT error = ERROR_INTERNAL_ERROR; - priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); + PULONG pSessionId = NULL; - if (!priv->ChannelHandle) + priv->SessionId = WTS_CURRENT_SESSION; + + if (context->use_dynamic_virtual_channel) { - WLog_ERR(TAG, "WTSVirtualChannelOpen failed!"); - return ERROR_INTERNAL_ERROR; + if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &bytesReturned)) + { + priv->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + priv->ChannelHandle = (HANDLE)WTSVirtualChannelOpenEx( + priv->SessionId, "AUDIO_PLAYBACK_DVC", WTS_CHANNEL_OPTION_DYNAMIC); + if (!priv->ChannelHandle) + { + WLog_ERR(TAG, "Open audio dynamic virtual channel (AUDIO_PLAYBACK_DVC) failed!"); + return ERROR_INTERNAL_ERROR; + } + } + else + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + } + else + { + priv->ChannelHandle = + WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); + if (!priv->ChannelHandle) + { + WLog_ERR(TAG, "Open audio static virtual channel (rdpsnd) failed!"); + return ERROR_INTERNAL_ERROR; + } } if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, diff --git a/channels/rdpsnd/server/rdpsnd_main.h b/channels/rdpsnd/server/rdpsnd_main.h index f058abb..9849273 100644 --- a/channels/rdpsnd/server/rdpsnd_main.h +++ b/channels/rdpsnd/server/rdpsnd_main.h @@ -39,6 +39,7 @@ struct _rdpsnd_server_private HANDLE StopEvent; HANDLE channelEvent; void* ChannelHandle; + DWORD SessionId; BOOL waitingHeader; DWORD expectedBytes; diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index 9a44e6e..6987961 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -1749,6 +1749,13 @@ static UINT urbdrc_process_transfer_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLB break; } + if (error) + { + WLog_Print(urbdrc->log, WLOG_WARN, + "USB transfer request URB Function %08" PRIx32 " failed with %08" PRIx32, + URB_Function, error); + } + return error; } diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index aa69890..1322a4f 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -490,17 +490,19 @@ static LIBUSB_DEVICE* udev_get_libusb_dev(libusb_context* context, uint8_t bus_n for (i = 0; i < total_device; i++) { - uint8_t cbus = libusb_get_bus_number(libusb_list[i]); - uint8_t caddr = libusb_get_device_address(libusb_list[i]); - - if ((bus_number == cbus) && (dev_number == caddr)) + LIBUSB_DEVICE* dev = libusb_list[i]; + if ((bus_number == libusb_get_bus_number(dev)) && + (dev_number == libusb_get_device_address(dev))) { - device = libusb_list[i]; - break; + device = dev; + } + else + { + libusb_unref_device(dev); } } - libusb_free_device_list(libusb_list, 1); + libusb_free_device_list(libusb_list, 0); return device; } @@ -522,7 +524,6 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB return descriptor; } - static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting) { int error = 0, diff = 0; @@ -1012,6 +1013,9 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev) if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc) return FALSE; +#ifdef _WIN32 + return TRUE; +#else urbdrc = pdev->urbdrc; if ((pdev->status & URBDRC_DEVICE_DETACH_KERNEL) == 0) @@ -1032,6 +1036,7 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev) } return TRUE; +#endif } static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev) @@ -1048,12 +1053,14 @@ static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev) log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_release_interface", err); +#ifndef _WIN32 if (err != LIBUSB_ERROR_NO_DEVICE) { err = libusb_attach_kernel_driver(pdev->libusb_handle, i); log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_attach_kernel_driver if=%d", err, i); } +#endif } return TRUE; @@ -1474,6 +1481,7 @@ static void udev_free(IUDEVICE* idev) ArrayList_Free(udev->request_queue); /* free the config descriptor that send from windows */ msusb_msconfig_free(udev->MsConfig); + libusb_unref_device(udev->libusb_dev); libusb_close(udev->libusb_handle); libusb_close(udev->hub_handle); free(udev->devDescriptor); @@ -1522,8 +1530,8 @@ static void udev_load_interface(UDEVICE* pdev) pdev->iface.free = udev_free; } -static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, - UINT16 bus_number, UINT16 dev_number) +static int udev_get_device_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, + UINT16 bus_number, UINT16 dev_number) { int error; ssize_t i, total_device; @@ -1535,21 +1543,19 @@ static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVI for (i = 0; i < total_device; i++) { - LIBUSB_DEVICE_HANDLE* handle; - uint8_t cbus = libusb_get_bus_number(libusb_list[i]); - uint8_t caddr = libusb_get_device_address(libusb_list[i]); + LIBUSB_DEVICE* dev = libusb_list[i]; - if ((bus_number != cbus) || (dev_number != caddr)) + if ((bus_number != libusb_get_bus_number(dev)) || + (dev_number != libusb_get_device_address(dev))) continue; - error = libusb_open(libusb_list[i], &handle); + error = libusb_open(dev, &pdev->libusb_handle); if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) break; /* get port number */ - error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers)); - libusb_close(handle); + error = libusb_get_port_numbers(dev, port_numbers, sizeof(port_numbers)); if (error < 1) { @@ -1567,29 +1573,40 @@ static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVI WLog_Print(urbdrc->log, WLOG_DEBUG, " DevPath: %s", pdev->path); break; } + libusb_free_device_list(libusb_list, 1); + + if (error < 0) + return -1; + return 0; +} + +static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, + UINT16 bus_number, UINT16 dev_number) +{ + int error; + ssize_t i, total_device; + LIBUSB_DEVICE** libusb_list; + LIBUSB_DEVICE_HANDLE* handle; + total_device = libusb_get_device_list(ctx, &libusb_list); /* Look for device hub. */ - if (error == 0) + error = -1; + + 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; } diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index 1638b8c..edfe74f 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -195,6 +195,12 @@ static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE /* register all device that match pid vid */ num = udev_new_by_id(urbdrc, udevman->context, idVendor, idProduct, &devArray); + if (num == 0) + { + WLog_Print(urbdrc->log, WLOG_WARN, + "Could not find or redirect any usb devices by id %04x:%04x", idVendor, idProduct); + } + for (i = 0; i < num; i++) { UINT32 id; @@ -834,7 +840,7 @@ static BOOL poll_libusb_events(UDEVMAN* udevman) { int rc = LIBUSB_SUCCESS; struct timeval tv = { 0, 500 }; - if (libusb_try_lock_events(udevman->context)) + if (libusb_try_lock_events(udevman->context) == 0) { if (libusb_event_handling_ok(udevman->context)) { @@ -921,7 +927,7 @@ UINT freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS udevman->next_device_id = BASE_USBDEVICE_NUM; udevman->iface.plugin = pEntryPoints->plugin; rc = libusb_init(&udevman->context); - + if (rc != LIBUSB_SUCCESS) goto fail; diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 24a03d4..c2704a4 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1384,7 +1384,10 @@ static int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) const char* str_data = freerdp_get_logon_error_info_data(data); const char* str_type = freerdp_get_logon_error_info_type(type); WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); - xf_rail_disable_remoteapp_mode(xfc); + if(type != LOGON_MSG_SESSION_CONTINUE) + { + xf_rail_disable_remoteapp_mode(xfc); + } return 1; } diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 8de32c5..11c6d59 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -729,6 +729,8 @@ UINT32 xf_get_local_color_format(xfContext* xfc, BOOL aligned) if (xfc->depth == 32) DstFormat = (!invert) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_BGRA32; + else if (xfc->depth == 30) + DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32_DEPTH30 : PIXEL_FORMAT_BGRX32_DEPTH30; else if (xfc->depth == 24) { if (aligned) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 15d4813..77fcf81 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -24,9 +24,10 @@ #endif #include -#include #include +#include + #include #include #include @@ -46,6 +47,7 @@ #include "cmdline.h" #include + #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; } } } diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index 78d9bf6..ffa1641 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -27,12 +27,20 @@ find_library(AVUTIL_LIBRARY avutil PATHS ${AVUTIL_LIBRARY_DIRS}) # swresample find_path(SWRESAMPLE_INCLUDE_DIR libswresample/swresample.h PATHS ${SWRESAMPLE_INCLUDE_DIRS}) -find_library(SWRESAMPLE_LIBRARY swresample PATHS ${SWRESAMPLE_LIBRARY_DIRS}) +find_library(SWRESAMPLE_LIBRARY NAMES swresample swresample-3 PATHS ${SWRESAMPLE_LIBRARY_DIRS}) + +if (SWRESAMPLE_INCLUDE_DIR AND SWRESAMPLE_LIBRARY) + set(SWRESAMPLE_FOUND ON) +endif() # avresample find_path(AVRESAMPLE_INCLUDE_DIR libavresample/avresample.h PATHS ${AVRESAMPLE_INCLUDE_DIRS}) find_library(AVRESAMPLE_LIBRARY avresample PATHS ${AVRESAMPLE_LIBRARY_DIRS}) +if (AVRESAMPLE_INCLUDE_DIR AND AVRESAMPLE_LIBRARY) + set(AVRESAMPLE_FOUND ON) +endif() + if (AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY) set(AVCODEC_FOUND TRUE) endif(AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY) diff --git a/include/freerdp/codec/color.h b/include/freerdp/codec/color.h index 42cb104..5d3e279 100644 --- a/include/freerdp/codec/color.h +++ b/include/freerdp/codec/color.h @@ -68,6 +68,8 @@ #define PIXEL_FORMAT_BGRX32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_BGRA, 0, 8, 8, 8) #define PIXEL_FORMAT_RGBA32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 8, 8, 8, 8) #define PIXEL_FORMAT_RGBX32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 0, 8, 8, 8) +#define PIXEL_FORMAT_BGRX32_DEPTH30 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_BGRA, 0, 10, 10, 10) +#define PIXEL_FORMAT_RGBX32_DEPTH30 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 0, 10, 10, 10) /* 24bpp formats */ #define PIXEL_FORMAT_RGB24 FREERDP_PIXEL_FORMAT(24, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 8, 8, 8) @@ -149,6 +151,12 @@ extern "C" case PIXEL_FORMAT_RGBX32: return "PIXEL_FORMAT_RGBX32"; + case PIXEL_FORMAT_BGRX32_DEPTH30: + return "PIXEL_FORMAT_BGRX32_DEPTH30"; + + case PIXEL_FORMAT_RGBX32_DEPTH30: + return "PIXEL_FORMAT_RGBX32_DEPTH30"; + /* 24bpp formats */ case PIXEL_FORMAT_RGB24: return "PIXEL_FORMAT_RGB24"; @@ -607,6 +615,7 @@ extern "C" UINT32 _g = g; UINT32 _b = b; UINT32 _a = a; + UINT32 t; switch (format) { @@ -635,6 +644,18 @@ extern "C" case PIXEL_FORMAT_BGRX32: return (_b << 24) | (_g << 16) | (_r << 8) | _a; + case PIXEL_FORMAT_RGBX32_DEPTH30: + // TODO: Not tested + t = (_r << 22) | (_g << 12) | (_b << 2); + // NOTE: Swapping byte-order because WriteColor written UINT32 in big-endian + return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) | (t >> 24); + + case PIXEL_FORMAT_BGRX32_DEPTH30: + // NOTE: Swapping b and r channel (unknown reason) + t = (_r << 22) | (_g << 12) | (_b << 2); + // NOTE: Swapping byte-order because WriteColor written UINT32 in big-endian + return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) | (t >> 24); + /* 24bpp formats */ case PIXEL_FORMAT_RGB24: return (_r << 16) | (_g << 8) | _b; diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index 33f1a1e..3138362 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -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, diff --git a/include/freerdp/rail.h b/include/freerdp/rail.h index 019aff8..e532082 100644 --- a/include/freerdp/rail.h +++ b/include/freerdp/rail.h @@ -142,6 +142,7 @@ enum SPI_MASK #define TS_RAIL_CLIENTSTATUS_HIGH_DPI_ICONS_SUPPORTED 0x00000020 #define TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED 0x00000040 #define TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED 0x00000080 +#define TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED 0x00000100 #define TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED 0x00000200 /* Server Move/Size Start PDU */ diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h index fa83473..b83a636 100644 --- a/include/freerdp/server/rdpsnd.h +++ b/include/freerdp/server/rdpsnd.h @@ -119,6 +119,9 @@ struct _rdpsnd_server_context UINT16 clientVersion; rdpContext* rdpcontext; + + /* Server to request to use dynamic virtual channel. */ + BOOL use_dynamic_virtual_channel; }; #ifdef __cplusplus diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c index ba207e5..9caec04 100644 --- a/libfreerdp/codec/h264_mediacodec.c +++ b/libfreerdp/codec/h264_mediacodec.c @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include @@ -29,8 +29,6 @@ #include "h264.h" -#define WINPR_ASSERT(x) assert(x) - #define RESOLVE_MEDIANDK_FUNC(sys, name) \ ({ \ BOOL rc = TRUE; \ diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 60343b8..a9e39d2 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -23,7 +23,7 @@ #include "config.h" #endif -#include +#include #include #include #include @@ -41,8 +41,6 @@ #include "rfx_types.h" #include "progressive.h" -#define WINPR_ASSERT(x) assert(x) - #define TAG FREERDP_TAG("codec.progressive") struct _RFX_PROGRESSIVE_UPGRADE_STATE @@ -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); } diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index 8c65e75..b41c157 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -1071,7 +1071,10 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, UINT8 channelId; if (Stream_GetRemainingLength(s) < 2) + { + WLog_ERR(TAG, "extraBlockLen too small(%" PRIuz ")", Stream_GetRemainingLength(s)); return FALSE; + } extraBlockLen = 2; Stream_Read_UINT8(s, codecId); /* codecId (1 byte) must be set to 0x01 */ @@ -1212,6 +1215,9 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, NULL, FREERDP_FLIP_NONE)) { region16_uninit(&updateRegion); + WLog_ERR(TAG, + "nbUpdateRectx[% " PRIu32 " (%" PRIu32 ")] freerdp_image_copy failed", + j, nbUpdateRects); return FALSE; } @@ -1226,6 +1232,7 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, return TRUE; } + WLog_ERR(TAG, "%s failed", __FUNCTION__); return FALSE; } diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 44de2c1..6b998c8 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -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; } diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index c03f266..70fdf9e 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -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; } diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index d0c2b56..6a7b990 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -401,13 +401,9 @@ rdpSettings* freerdp_settings_new(DWORD flags) if (!settings->ClientProductId) goto out_fail; - settings->ClientHostname = calloc(1, 32); - - if (!settings->ClientHostname) + if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, settings->ComputerName)) goto out_fail; - gethostname(settings->ClientHostname, 31); - settings->ClientHostname[31] = 0; settings->ColorPointerFlag = TRUE; settings->LargePointerFlag = (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384); settings->PointerCacheSize = 20; @@ -492,6 +488,7 @@ rdpSettings* freerdp_settings_new(DWORD flags) settings->GatewayRpcTransport = TRUE; settings->GatewayHttpTransport = TRUE; settings->GatewayUdpTransport = TRUE; + settings->GatewayHttpUseWebsockets = TRUE; settings->FastPathInput = TRUE; settings->FastPathOutput = TRUE; settings->LongCredentialsSupported = TRUE; diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c index ca89d23..e288799 100644 --- a/libfreerdp/core/surface.c +++ b/libfreerdp/core/surface.c @@ -37,7 +37,11 @@ static BOOL update_recv_surfcmd_bitmap_header_ex(wStream* s, TS_COMPRESSED_BITMA return FALSE; if (Stream_GetRemainingLength(s) < 24) + { + WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), + 24); return FALSE; + } Stream_Read_UINT32(s, header->highUniqueId); Stream_Read_UINT32(s, header->lowUniqueId); @@ -54,7 +58,11 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp) return FALSE; if (Stream_GetRemainingLength(s) < 12) + { + WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), + 12); return FALSE; + } Stream_Read_UINT8(s, bmp->bpp); Stream_Read_UINT8(s, bmp->flags); @@ -86,7 +94,11 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp) } if (Stream_GetRemainingLength(s) < bmp->bitmapDataLength) + { + WLog_ERR(TAG, "expected bitmapDataLength %" PRIu32 ", not enough data", + bmp->bitmapDataLength); return FALSE; + } pos = Stream_GetPosition(s) + bmp->bitmapDataLength; bmp->bitmapData = Stream_Pointer(s); @@ -132,7 +144,10 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT SURFACE_BITS_COMMAND cmd = { 0 }; if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 8); goto fail; + } cmd.cmdType = cmdType; Stream_Read_UINT16(s, cmd.destLeft); @@ -152,7 +167,12 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT goto fail; } - return update->SurfaceBits(update->context, &cmd); + if (!update->SurfaceBits(update->context, &cmd)) + { + WLog_DBG(TAG, "update->SurfaceBits implementation failed"); + goto fail; + } + return TRUE; fail: return FALSE; } @@ -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); diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c index 6b6770b..72432a2 100644 --- a/libfreerdp/core/utils.c +++ b/libfreerdp/core/utils.c @@ -22,7 +22,7 @@ #include "config.h" #endif -#include +#include #include @@ -31,8 +31,6 @@ #include "utils.h" -#define WINPR_ASSERT(x) assert(x) - BOOL utils_abort_connect(rdpContext* context) { WINPR_ASSERT(context); diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 7e5860d..d8a40da 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -21,6 +21,12 @@ project(WinPR C) set(CMAKE_COLOR_MAKEFILE ON) +option(WITH_VERBOSE_WINPR_ASSERT "Compile with verbose WINPR_ASSERT." ON) + +if (WITH_VERBOSE_WINPR_ASSERT) + add_definitions(-DWITH_VERBOSE_WINPR_ASSERT) +endif() + if(FREERDP_VERSION) set(FREERDP_BUILD 1) endif() @@ -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) diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h new file mode 100644 index 0000000..0cef841 --- /dev/null +++ b/winpr/include/winpr/assert.h @@ -0,0 +1,59 @@ +/** + * WinPR: Windows Portable Runtime + * Runtime ASSERT macros + * + * Copyright 2021 Armin Novak + * Copyright 2021 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WINPR_ASSERT_H +#define WINPR_ASSERT_H + +#include +#include +#include +#include +#include + +#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0) +#define WINPR_ASSERT(cond) \ + do \ + { \ + if (!(cond)) \ + { \ + wLog* _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert"); \ + WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ + __FUNCTION__, __LINE__); \ + winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20); \ + abort(); \ + } \ + } while (0) +#else +#define WINPR_ASSERT(cond) \ + do \ + { \ + } while (0) +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_ERROR_H */ diff --git a/winpr/include/winpr/crypto.h b/winpr/include/winpr/crypto.h index 67c2d99..c550719 100644 --- a/winpr/include/winpr/crypto.h +++ b/winpr/include/winpr/crypto.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 diff --git a/winpr/include/winpr/locale.h b/winpr/include/winpr/locale.h index 45ef81b..af776dd 100644 --- a/winpr/include/winpr/locale.h +++ b/winpr/include/winpr/locale.h @@ -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 diff --git a/winpr/include/winpr/smartcard.h b/winpr/include/winpr/smartcard.h index e19a6ee..b040f0a 100644 --- a/winpr/include/winpr/smartcard.h +++ b/winpr/include/winpr/smartcard.h @@ -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) diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index 511d927..3867b06 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -36,8 +36,6 @@ #include "../log.h" #define TAG WINPR_TAG("registry") -#define WINPR_ASSERT assert - #define WINPR_HKLM_HIVE "/etc/winpr/HKLM.reg" struct reg_data_type diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index 9560371..372e6fb 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -22,8 +22,10 @@ #endif #include +#include #include #include +#include #include #include #include @@ -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; +} diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.h b/winpr/libwinpr/sspi/NTLM/ntlm.h index c6216ea..a9fe5c2 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm.h @@ -89,7 +89,7 @@ enum _NTLM_AV_ID MsvAvTimestamp, MsvAvSingleHost, MsvAvTargetName, - MsvChannelBindings + MsvAvChannelBindings }; typedef enum _NTLM_AV_ID NTLM_AV_ID; @@ -176,8 +176,7 @@ typedef struct _NTLM_MESSAGE_HEADER NTLM_MESSAGE_HEADER; struct _NTLM_NEGOTIATE_MESSAGE { - BYTE Signature[8]; - UINT32 MessageType; + NTLM_MESSAGE_HEADER header; UINT32 NegotiateFlags; NTLM_VERSION_INFO Version; NTLM_MESSAGE_FIELDS DomainName; @@ -187,8 +186,7 @@ typedef struct _NTLM_NEGOTIATE_MESSAGE NTLM_NEGOTIATE_MESSAGE; struct _NTLM_CHALLENGE_MESSAGE { - BYTE Signature[8]; - UINT32 MessageType; + NTLM_MESSAGE_HEADER header; UINT32 NegotiateFlags; BYTE ServerChallenge[8]; BYTE Reserved[8]; @@ -200,8 +198,7 @@ typedef struct _NTLM_CHALLENGE_MESSAGE NTLM_CHALLENGE_MESSAGE; struct _NTLM_AUTHENTICATE_MESSAGE { - BYTE Signature[8]; - UINT32 MessageType; + NTLM_MESSAGE_HEADER header; UINT32 NegotiateFlags; NTLM_VERSION_INFO Version; NTLM_MESSAGE_FIELDS DomainName; @@ -251,7 +248,7 @@ struct _NTLM_CONTEXT NTLM_NEGOTIATE_MESSAGE NEGOTIATE_MESSAGE; NTLM_CHALLENGE_MESSAGE CHALLENGE_MESSAGE; NTLM_AUTHENTICATE_MESSAGE AUTHENTICATE_MESSAGE; - UINT32 MessageIntegrityCheckOffset; + size_t MessageIntegrityCheckOffset; SecBuffer NegotiateMessage; SecBuffer ChallengeMessage; SecBuffer AuthenticateMessage; @@ -280,6 +277,13 @@ struct _NTLM_CONTEXT }; typedef struct _NTLM_CONTEXT NTLM_CONTEXT; +char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags); +const char* ntlm_message_type_string(UINT32 messageType); + +const char* ntlm_state_string(NTLM_STATE state); +void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state); +NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm); + SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof); SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c index 47669bb..9b2efd3 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c @@ -21,12 +21,13 @@ #include "config.h" #endif -#include +#include #include "ntlm.h" #include "../sspi.h" #include +#include #include #include #include @@ -75,8 +76,8 @@ static const char* get_av_pair_string(UINT16 pair) return "MsvAvSingleHost"; case MsvAvTargetName: return "MsvAvTargetName"; - case MsvChannelBindings: - return "MsvChannelBindings"; + case MsvAvChannelBindings: + return "MsvAvChannelBindings"; default: return "UNKNOWN"; } @@ -87,11 +88,13 @@ static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvP static INLINE void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id) { + WINPR_ASSERT(pAvPair); Data_Write_UINT16(&pAvPair->AvId, id); } static INLINE void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len) { + WINPR_ASSERT(pAvPair); Data_Write_UINT16(&pAvPair->AvLen, len); } @@ -124,6 +127,7 @@ static INLINE BOOL ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair, size_t size, ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) { + size_t size; size_t cbAvPair; NTLM_AV_PAIR* pAvPair; @@ -131,7 +135,9 @@ ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) if (!pAvPair) return 0; - return ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR); + size = ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR); + WINPR_ASSERT(size <= ULONG_MAX); + return (ULONG)size; } static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pAvLen) @@ -149,6 +155,7 @@ static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size return TRUE; } +#ifdef WITH_DEBUG_NTLM void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) { UINT16 pair; @@ -158,19 +165,20 @@ void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) if (!ntlm_av_pair_check(pAvPair, cbAvPair)) return; - WLog_INFO(TAG, "AV_PAIRs ="); + WLog_VRB(TAG, "AV_PAIRs ="); while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL)) { size_t cbLen = 0; ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen); - WLog_INFO(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair); - winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair), cbLen); + WLog_VRB(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair); + winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen); pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair); } } +#endif static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength) { @@ -180,6 +188,7 @@ static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair) { + WINPR_ASSERT(pAvPair); return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR); } @@ -259,11 +268,11 @@ static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTL if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen) return FALSE; - ntlm_av_pair_set_id(pAvPair, AvId); + ntlm_av_pair_set_id(pAvPair, (UINT16)AvId); ntlm_av_pair_set_len(pAvPair, AvLen); if (AvLen) { - assert(Value != NULL); + WINPR_ASSERT(Value != NULL); CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen); } @@ -286,8 +295,9 @@ static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen)) return FALSE; + WINPR_ASSERT(avLen <= UINT16_MAX); return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair, - ntlm_av_pair_get_value_pointer(pAvPair), avLen); + ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen); } static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type) @@ -297,6 +307,8 @@ static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FO DWORD nSize = 0; CHAR* computerName; + WINPR_ASSERT(pName); + if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || GetLastError() != ERROR_MORE_DATA) return -1; @@ -394,6 +406,9 @@ static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) BYTE* ChannelBindingToken; UINT32 ChannelBindingTokenLength; SEC_CHANNEL_BINDINGS* ChannelBindings; + + WINPR_ASSERT(context); + ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH); ChannelBindings = context->Bindings.Bindings; @@ -436,6 +451,7 @@ out: static void ntlm_compute_single_host_data(NTLM_CONTEXT* context) { + WINPR_ASSERT(context); /** * The Single_Host_Data structure allows a client to send machine-specific information * within an authentication exchange to services on the same machine. The client can @@ -451,10 +467,10 @@ static void ntlm_compute_single_host_data(NTLM_CONTEXT* context) FillMemory(context->SingleHostData.MachineID, 32, 0xAA); } -int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) +BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) { - int rc = -1; - int length; + BOOL rc = FALSE; + ULONG length; ULONG AvPairsCount; ULONG AvPairsLength; NTLM_AV_PAIR* pAvPairList; @@ -464,6 +480,8 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) UNICODE_STRING DnsDomainName = { 0 }; UNICODE_STRING DnsComputerName = { 0 }; + WINPR_ASSERT(context); + if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0) goto fail; @@ -516,7 +534,7 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) sizeof(context->Timestamp))) goto fail; - rc = 1; + rc = TRUE; fail: ntlm_free_unicode_string(&NbDomainName); ntlm_free_unicode_string(&NbComputerName); @@ -525,7 +543,7 @@ fail: return rc; } -int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) +BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) { ULONG size; ULONG AvPairsCount; @@ -546,6 +564,9 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) size_t cbAvDnsTreeName; size_t cbChallengeTargetInfo; size_t cbAuthenticateTargetInfo; + + WINPR_ASSERT(context); + AvPairsCount = 1; AvPairsValueLength = 0; ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer; @@ -635,7 +656,7 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) * SEC_CHANNEL_BINDINGS structure * http://msdn.microsoft.com/en-us/library/windows/desktop/dd919963/ */ - AvPairsCount++; /* MsvChannelBindings */ + AvPairsCount++; /* MsvAvChannelBindings */ AvPairsValueLength += 16; ntlm_compute_channel_bindings(context); @@ -714,15 +735,17 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) if (context->SendSingleHostData) { + WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX); if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost, - (PBYTE)&context->SingleHostData, context->SingleHostData.Size)) + (PBYTE)&context->SingleHostData, + (UINT16)context->SingleHostData.Size)) goto fail; } if (!context->SuppressExtendedProtection) { - if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvChannelBindings, - context->ChannelBindingsHash, 16)) + if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, + MsvAvChannelBindings, context->ChannelBindingsHash, 16)) goto fail; if (context->ServicePrincipalName.Length > 0) @@ -745,8 +768,8 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR)); } - return 1; + return TRUE; fail: sspi_SecBufferFree(&context->AuthenticateTargetInfo); - return -1; + return FALSE; } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h index ac228a8..82d2364 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h @@ -30,7 +30,7 @@ PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair); NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId, size_t* pcbAvPairListRemaining); -int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context); -int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context); +BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context); +BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context); #endif /* WINPR_SSPI_NTLM_AV_PAIRS_H */ diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c index dbd7f7f..4e33aed 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c @@ -21,7 +21,7 @@ #include "config.h" #endif -#include +#include #include "ntlm.h" #include "../sspi.h" @@ -38,16 +38,10 @@ #include "../../log.h" #define TAG WINPR_TAG("sspi.NTLM") -const char LM_MAGIC[] = "KGS!@#$%"; - -static const char NTLM_CLIENT_SIGN_MAGIC[] = - "session key to client-to-server signing key magic constant"; -static const char NTLM_SERVER_SIGN_MAGIC[] = - "session key to server-to-client signing key magic constant"; -static const char NTLM_CLIENT_SEAL_MAGIC[] = - "session key to client-to-server sealing key magic constant"; -static const char NTLM_SERVER_SEAL_MAGIC[] = - "session key to server-to-client sealing key magic constant"; +static char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant"; +static char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client signing key magic constant"; +static char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant"; +static char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant"; static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -58,16 +52,21 @@ static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 * @param s */ -void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) +BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) { - OSVERSIONINFOA osVersionInfo; + OSVERSIONINFOA osVersionInfo = { 0 }; + + WINPR_ASSERT(versionInfo); + osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - GetVersionExA(&osVersionInfo); + if (!GetVersionExA(&osVersionInfo)) + return FALSE; versionInfo->ProductMajorVersion = (UINT8)osVersionInfo.dwMajorVersion; versionInfo->ProductMinorVersion = (UINT8)osVersionInfo.dwMinorVersion; versionInfo->ProductBuild = (UINT16)osVersionInfo.dwBuildNumber; ZeroMemory(versionInfo->Reserved, sizeof(versionInfo->Reserved)); versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; + return TRUE; } /** @@ -76,17 +75,24 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) * @param s */ -int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) +BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) { + WINPR_ASSERT(s); + WINPR_ASSERT(versionInfo); + if (Stream_GetRemainingLength(s) < 8) - return -1; + { + WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz, + Stream_GetRemainingLength(s), 8); + return FALSE; + } Stream_Read_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */ Stream_Read_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */ Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */ Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */ Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */ - return 1; + return TRUE; } /** @@ -95,13 +101,24 @@ int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) * @param s */ -void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) +BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo) { + WINPR_ASSERT(s); + WINPR_ASSERT(versionInfo); + + if (Stream_GetRemainingCapacity(s) < 5 + sizeof(versionInfo->Reserved)) + { + WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz, + Stream_GetRemainingCapacity(s), 5 + sizeof(versionInfo->Reserved)); + return FALSE; + } + Stream_Write_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */ Stream_Write_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */ Stream_Write_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */ Stream_Write(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */ Stream_Write_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */ + return TRUE; } /** @@ -109,23 +126,33 @@ void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) * VERSION @msdn{cc236654} * @param s */ - -void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo) +#ifdef WITH_DEBUG_NTLM +void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo) { - WLog_INFO(TAG, "VERSION ={"); - WLog_INFO(TAG, "\tProductMajorVersion: %" PRIu8 "", versionInfo->ProductMajorVersion); - WLog_INFO(TAG, "\tProductMinorVersion: %" PRIu8 "", versionInfo->ProductMinorVersion); - WLog_INFO(TAG, "\tProductBuild: %" PRIu16 "", versionInfo->ProductBuild); - WLog_INFO(TAG, "\tReserved: 0x%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "", versionInfo->Reserved[0], - versionInfo->Reserved[1], versionInfo->Reserved[2]); - WLog_INFO(TAG, "\tNTLMRevisionCurrent: 0x%02" PRIX8 "", versionInfo->NTLMRevisionCurrent); -} + WINPR_ASSERT(versionInfo); -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; } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.h b/winpr/libwinpr/sspi/NTLM/ntlm_compute.h index 47f6c5d..a5572b5 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.h @@ -24,13 +24,16 @@ #include "ntlm_av_pairs.h" -void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo); -int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); -void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); -void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo); +BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo); +BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); +BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo); -int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); -int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); +#ifdef WITH_DEBUG_NTLM +void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo); +#endif + +BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); +BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response); void ntlm_output_target_name(NTLM_CONTEXT* context); void ntlm_output_channel_bindings(NTLM_CONTEXT* context); @@ -38,10 +41,10 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context); void ntlm_current_time(BYTE* timestamp); void ntlm_generate_timestamp(NTLM_CONTEXT* context); -int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context); -int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context); +BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context); +BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context); -void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext); +void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext); void ntlm_generate_client_challenge(NTLM_CONTEXT* context); void ntlm_generate_server_challenge(NTLM_CONTEXT* context); void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context); @@ -50,12 +53,12 @@ void ntlm_generate_exported_session_key(NTLM_CONTEXT* context); void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context); void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context); -void ntlm_generate_client_signing_key(NTLM_CONTEXT* context); -void ntlm_generate_server_signing_key(NTLM_CONTEXT* context); -void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context); -void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context); +BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context); +BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context); +BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context); +BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context); void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context); -void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size); +BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size); #endif /* WINPR_AUTH_NTLM_COMPUTE_H */ diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c index 7502ecf..ccb2e10 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c @@ -25,6 +25,7 @@ #include "../sspi.h" #include +#include #include #include #include @@ -33,143 +34,388 @@ #include "ntlm_message.h" -#include "../log.h" +#include "../../log.h" #define TAG WINPR_TAG("sspi.NTLM") +static wStream* Stream_StaticConstInit(wStream* buffer, const BYTE* data, size_t size) +{ + Stream_StaticInit(buffer, data, size); + return buffer; +} + +static wStream* Stream_StaticInit2(wStream* buffer, BYTE* data, size_t size) +{ + Stream_StaticInit(buffer, data, size); + return buffer; +} + static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' }; -#ifdef WITH_DEBUG_NTLM -static const char* const NTLM_NEGOTIATE_STRINGS[] = { "NTLMSSP_NEGOTIATE_56", - "NTLMSSP_NEGOTIATE_KEY_EXCH", - "NTLMSSP_NEGOTIATE_128", - "NTLMSSP_RESERVED1", - "NTLMSSP_RESERVED2", - "NTLMSSP_RESERVED3", - "NTLMSSP_NEGOTIATE_VERSION", - "NTLMSSP_RESERVED4", - "NTLMSSP_NEGOTIATE_TARGET_INFO", - "NTLMSSP_REQUEST_NON_NT_SESSION_KEY", - "NTLMSSP_RESERVED5", - "NTLMSSP_NEGOTIATE_IDENTIFY", - "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY", - "NTLMSSP_RESERVED6", - "NTLMSSP_TARGET_TYPE_SERVER", - "NTLMSSP_TARGET_TYPE_DOMAIN", - "NTLMSSP_NEGOTIATE_ALWAYS_SIGN", - "NTLMSSP_RESERVED7", - "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED", - "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED", - "NTLMSSP_NEGOTIATE_ANONYMOUS", - "NTLMSSP_RESERVED8", - "NTLMSSP_NEGOTIATE_NTLM", - "NTLMSSP_RESERVED9", - "NTLMSSP_NEGOTIATE_LM_KEY", - "NTLMSSP_NEGOTIATE_DATAGRAM", - "NTLMSSP_NEGOTIATE_SEAL", - "NTLMSSP_NEGOTIATE_SIGN", - "NTLMSSP_RESERVED10", - "NTLMSSP_REQUEST_TARGET", - "NTLMSSP_NEGOTIATE_OEM", - "NTLMSSP_NEGOTIATE_UNICODE" }; +static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields); + +const char* ntlm_get_negotiate_string(UINT32 flag) +{ + if (flag & NTLMSSP_NEGOTIATE_56) + return "NTLMSSP_NEGOTIATE_56"; + if (flag & NTLMSSP_NEGOTIATE_KEY_EXCH) + return "NTLMSSP_NEGOTIATE_KEY_EXCH"; + if (flag & NTLMSSP_NEGOTIATE_128) + return "NTLMSSP_NEGOTIATE_128"; + if (flag & NTLMSSP_RESERVED1) + return "NTLMSSP_RESERVED1"; + if (flag & NTLMSSP_RESERVED2) + return "NTLMSSP_RESERVED2"; + if (flag & NTLMSSP_RESERVED3) + return "NTLMSSP_RESERVED3"; + if (flag & NTLMSSP_NEGOTIATE_VERSION) + return "NTLMSSP_NEGOTIATE_VERSION"; + if (flag & NTLMSSP_RESERVED4) + return "NTLMSSP_RESERVED4"; + if (flag & NTLMSSP_NEGOTIATE_TARGET_INFO) + return "NTLMSSP_NEGOTIATE_TARGET_INFO"; + if (flag & NTLMSSP_REQUEST_NON_NT_SESSION_KEY) + return "NTLMSSP_REQUEST_NON_NT_SESSION_KEY"; + if (flag & NTLMSSP_RESERVED5) + return "NTLMSSP_RESERVED5"; + if (flag & NTLMSSP_NEGOTIATE_IDENTIFY) + return "NTLMSSP_NEGOTIATE_IDENTIFY"; + if (flag & NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY) + return "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY"; + if (flag & NTLMSSP_RESERVED6) + return "NTLMSSP_RESERVED6"; + if (flag & NTLMSSP_TARGET_TYPE_SERVER) + return "NTLMSSP_TARGET_TYPE_SERVER"; + if (flag & NTLMSSP_TARGET_TYPE_DOMAIN) + return "NTLMSSP_TARGET_TYPE_DOMAIN"; + if (flag & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) + return "NTLMSSP_NEGOTIATE_ALWAYS_SIGN"; + if (flag & NTLMSSP_RESERVED7) + return "NTLMSSP_RESERVED7"; + if (flag & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) + return "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED"; + if (flag & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) + return "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED"; + if (flag & NTLMSSP_NEGOTIATE_ANONYMOUS) + return "NTLMSSP_NEGOTIATE_ANONYMOUS"; + if (flag & NTLMSSP_RESERVED8) + return "NTLMSSP_RESERVED8"; + if (flag & NTLMSSP_NEGOTIATE_NTLM) + return "NTLMSSP_NEGOTIATE_NTLM"; + if (flag & NTLMSSP_RESERVED9) + return "NTLMSSP_RESERVED9"; + if (flag & NTLMSSP_NEGOTIATE_LM_KEY) + return "NTLMSSP_NEGOTIATE_LM_KEY"; + if (flag & NTLMSSP_NEGOTIATE_DATAGRAM) + return "NTLMSSP_NEGOTIATE_DATAGRAM"; + if (flag & NTLMSSP_NEGOTIATE_SEAL) + return "NTLMSSP_NEGOTIATE_SEAL"; + if (flag & NTLMSSP_NEGOTIATE_SIGN) + return "NTLMSSP_NEGOTIATE_SIGN"; + if (flag & NTLMSSP_RESERVED10) + return "NTLMSSP_RESERVED10"; + if (flag & NTLMSSP_REQUEST_TARGET) + return "NTLMSSP_REQUEST_TARGET"; + if (flag & NTLMSSP_NEGOTIATE_OEM) + return "NTLMSSP_NEGOTIATE_OEM"; + if (flag & NTLMSSP_NEGOTIATE_UNICODE) + return "NTLMSSP_NEGOTIATE_UNICODE"; + return "NTLMSSP_NEGOTIATE_UNKNOWN"; +} + +#if defined(WITH_DEBUG_NTLM) +static void ntlm_print_message_fields(const NTLM_MESSAGE_FIELDS* fields, const char* name) +{ + WINPR_ASSERT(fields); + WINPR_ASSERT(name); + + WLog_VRB(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name, + fields->Len, fields->MaxLen, fields->BufferOffset); + + if (fields->Len > 0) + winpr_HexDump(TAG, WLOG_TRACE, fields->Buffer, fields->Len); +} static void ntlm_print_negotiate_flags(UINT32 flags) { int i; - const char* str; - WLog_INFO(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags); + + WLog_VRB(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags); for (i = 31; i >= 0; i--) { if ((flags >> i) & 1) { - str = NTLM_NEGOTIATE_STRINGS[(31 - i)]; - WLog_INFO(TAG, "\t%s (%d),", str, (31 - i)); + const char* str = ntlm_get_negotiate_string(1 << i); + WLog_VRB(TAG, "\t%s (%d),", str, (31 - i)); } } } + +static void ntlm_print_negotiate_message(const SecBuffer* NegotiateMessage, + const NTLM_NEGOTIATE_MESSAGE* message) +{ + WINPR_ASSERT(NegotiateMessage); + WINPR_ASSERT(message); + + WLog_VRB(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", NegotiateMessage->cbBuffer); + winpr_HexDump(TAG, WLOG_TRACE, NegotiateMessage->pvBuffer, NegotiateMessage->cbBuffer); + ntlm_print_negotiate_flags(message->NegotiateFlags); + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + ntlm_print_version_info(&(message->Version)); +} + +static void ntlm_print_challenge_message(const SecBuffer* ChallengeMessage, + const NTLM_CHALLENGE_MESSAGE* message, + const SecBuffer* ChallengeTargetInfo) +{ + WINPR_ASSERT(ChallengeMessage); + WINPR_ASSERT(message); + + WLog_VRB(TAG, "CHALLENGE_MESSAGE (length = %" PRIu32 ")", ChallengeMessage->cbBuffer); + winpr_HexDump(TAG, WLOG_TRACE, ChallengeMessage->pvBuffer, ChallengeMessage->cbBuffer); + ntlm_print_negotiate_flags(message->NegotiateFlags); + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + ntlm_print_version_info(&(message->Version)); + + ntlm_print_message_fields(&(message->TargetName), "TargetName"); + ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); + + if (ChallengeTargetInfo && (ChallengeTargetInfo->cbBuffer > 0)) + { + WLog_VRB(TAG, "ChallengeTargetInfo (%" PRIu32 "):", ChallengeTargetInfo->cbBuffer); + ntlm_print_av_pair_list(ChallengeTargetInfo->pvBuffer, ChallengeTargetInfo->cbBuffer); + } +} + +static void ntlm_print_authenticate_message(const SecBuffer* AuthenticateMessage, + const NTLM_AUTHENTICATE_MESSAGE* message, UINT32 flags, + const SecBuffer* AuthenticateTargetInfo) +{ + WINPR_ASSERT(AuthenticateMessage); + WINPR_ASSERT(message); + + WLog_VRB(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")", AuthenticateMessage->cbBuffer); + winpr_HexDump(TAG, WLOG_TRACE, AuthenticateMessage->pvBuffer, AuthenticateMessage->cbBuffer); + ntlm_print_negotiate_flags(message->NegotiateFlags); + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + ntlm_print_version_info(&(message->Version)); + + if (AuthenticateTargetInfo && (AuthenticateTargetInfo->cbBuffer > 0)) + { + WLog_VRB(TAG, "AuthenticateTargetInfo (%" PRIu32 "):", AuthenticateTargetInfo->cbBuffer); + ntlm_print_av_pair_list(AuthenticateTargetInfo->pvBuffer, AuthenticateTargetInfo->cbBuffer); + } + + ntlm_print_message_fields(&(message->DomainName), "DomainName"); + ntlm_print_message_fields(&(message->UserName), "UserName"); + ntlm_print_message_fields(&(message->Workstation), "Workstation"); + ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); + ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); + ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); + + if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) + { + WLog_VRB(TAG, "MessageIntegrityCheck (length = 16)"); + winpr_HexDump(TAG, WLOG_TRACE, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck)); + } +} + +static void ntlm_print_authentication_complete(const NTLM_CONTEXT* context) +{ + WINPR_ASSERT(context); + + WLog_VRB(TAG, "ClientChallenge"); + winpr_HexDump(TAG, WLOG_TRACE, context->ClientChallenge, 8); + WLog_VRB(TAG, "ServerChallenge"); + winpr_HexDump(TAG, WLOG_TRACE, context->ServerChallenge, 8); + WLog_VRB(TAG, "SessionBaseKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->SessionBaseKey, 16); + WLog_VRB(TAG, "KeyExchangeKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->KeyExchangeKey, 16); + WLog_VRB(TAG, "ExportedSessionKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ExportedSessionKey, 16); + WLog_VRB(TAG, "RandomSessionKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->RandomSessionKey, 16); + WLog_VRB(TAG, "ClientSigningKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ClientSigningKey, 16); + WLog_VRB(TAG, "ClientSealingKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ClientSealingKey, 16); + WLog_VRB(TAG, "ServerSigningKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ServerSigningKey, 16); + WLog_VRB(TAG, "ServerSealingKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ServerSealingKey, 16); + WLog_VRB(TAG, "Timestamp"); + winpr_HexDump(TAG, WLOG_TRACE, context->Timestamp, 8); +} #endif -static int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) +static BOOL ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header, UINT32 expected) { + WINPR_ASSERT(s); + WINPR_ASSERT(header); + if (Stream_GetRemainingLength(s) < 12) - return -1; + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_HEADER::header %" PRIuz ", expected 12", + Stream_GetRemainingLength(s)); + return FALSE; + } Stream_Read(s, header->Signature, 8); Stream_Read_UINT32(s, header->MessageType); if (strncmp((char*)header->Signature, NTLM_SIGNATURE, 8) != 0) - return -1; + { + WLog_ERR(TAG, "NTLM_MESSAGE_HEADER Invalid signature, got %s, expected %s", + header->Signature, NTLM_SIGNATURE); + return FALSE; + } - return 1; + if (header->MessageType != expected) + { + WLog_ERR(TAG, "NTLM_MESSAGE_HEADER Invalid message tyep, got %s, expected %s", + ntlm_message_type_string(header->MessageType), ntlm_message_type_string(expected)); + return FALSE; + } + + return TRUE; } -static void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) +static BOOL ntlm_write_message_header(wStream* s, const NTLM_MESSAGE_HEADER* header) { + WINPR_ASSERT(s); + WINPR_ASSERT(header); + + if (Stream_GetRemainingCapacity(s) < sizeof(NTLM_SIGNATURE) + 4) + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_HEADER::header %" PRIuz ", expected 12", + Stream_GetRemainingCapacity(s)); + return FALSE; + } + Stream_Write(s, header->Signature, sizeof(NTLM_SIGNATURE)); Stream_Write_UINT32(s, header->MessageType); + + return TRUE; } -static void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) +static BOOL ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) { + WINPR_ASSERT(header); + CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); header->MessageType = MessageType; + return TRUE; } -static int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static BOOL ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) { + WINPR_ASSERT(s); + WINPR_ASSERT(fields); + if (Stream_GetRemainingLength(s) < 8) - return -1; + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::header %" PRIuz ", expected %" PRIuz, + Stream_GetRemainingLength(s), 8); + return FALSE; + } + + ntlm_free_message_fields_buffer(fields); Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */ Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ - return 1; + return TRUE; } -static void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static BOOL ntlm_write_message_fields(wStream* s, const NTLM_MESSAGE_FIELDS* fields) { + UINT16 MaxLen; + WINPR_ASSERT(s); + WINPR_ASSERT(fields); + + MaxLen = fields->MaxLen; if (fields->MaxLen < 1) - fields->MaxLen = fields->Len; + MaxLen = fields->Len; + if (Stream_GetRemainingCapacity(s) < 8) + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::header %" PRIuz ", expected %" PRIuz, + Stream_GetRemainingCapacity(s), 8); + return FALSE; + } Stream_Write_UINT16(s, fields->Len); /* Len (2 bytes) */ - Stream_Write_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ + Stream_Write_UINT16(s, MaxLen); /* MaxLen (2 bytes) */ Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ + return TRUE; } -static int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static BOOL ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) { + WINPR_ASSERT(s); + WINPR_ASSERT(fields); + if (fields->Len > 0) { const UINT32 offset = fields->BufferOffset + fields->Len; if (fields->BufferOffset > UINT32_MAX - fields->Len) - return -1; + { + WLog_ERR(TAG, + "NTLM_MESSAGE_FIELDS::BufferOffset %" PRIu32 + " too large, maximum allowed is %" PRIu32, + fields->BufferOffset, UINT32_MAX - fields->Len); + return FALSE; + } if (offset > Stream_Length(s)) - return -1; + { + WLog_ERR(TAG, + "NTLM_MESSAGE_FIELDS::Buffer offset %" PRIu32 " beyond received data %" PRIuz, + offset, Stream_Length(s)); + return FALSE; + } fields->Buffer = (PBYTE)malloc(fields->Len); if (!fields->Buffer) - return -1; + { + WLog_ERR(TAG, "NTLM_MESSAGE_FIELDS::Buffer allocation of %" PRIu16 "bytes failed", + fields->Len); + return FALSE; + } Stream_SetPosition(s, fields->BufferOffset); Stream_Read(s, fields->Buffer, fields->Len); } - return 1; + return TRUE; } -static void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static BOOL ntlm_write_message_fields_buffer(wStream* s, const NTLM_MESSAGE_FIELDS* fields) { + WINPR_ASSERT(s); + WINPR_ASSERT(fields); + if (fields->Len > 0) { Stream_SetPosition(s, fields->BufferOffset); + if (Stream_GetRemainingCapacity(s) < fields->Len) + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::Len %" PRIuz ", expected %" PRIu16, + Stream_GetRemainingCapacity(s), fields->Len); + return FALSE; + } Stream_Write(s, fields->Buffer, fields->Len); } + return TRUE; } -static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) +void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) { if (fields) { @@ -184,122 +430,208 @@ static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) } } -#ifdef WITH_DEBUG_NTLM -static void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name) +static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required, const char* name) { - WLog_DBG(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name, - fields->Len, fields->MaxLen, fields->BufferOffset); + UINT32 NegotiateFlags = 0; + char buffer[1024] = { 0 }; + WINPR_ASSERT(s); + WINPR_ASSERT(flags); + WINPR_ASSERT(name); - if (fields->Len > 0) - winpr_HexDump(TAG, WLOG_DEBUG, fields->Buffer, fields->Len); + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "%s::NegotiateFlags expected 4bytes, have %" PRIuz "bytes", name, + Stream_GetRemainingLength(s)); + return FALSE; + } + + Stream_Read_UINT32(s, NegotiateFlags); /* NegotiateFlags (4 bytes) */ + + if ((NegotiateFlags & required) != required) + { + WLog_ERR(TAG, "%s::NegotiateFlags invalid flags 0x08%" PRIx32 ", 0x%08" PRIx32 " required", + name, NegotiateFlags, required); + return FALSE; + } + + WLog_DBG(TAG, "Read flags %s", + ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), NegotiateFlags)); + *flags = NegotiateFlags; + return TRUE; +} + +static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* name) +{ + char buffer[1024] = { 0 }; + WINPR_ASSERT(s); + WINPR_ASSERT(name); + + if (Stream_GetRemainingCapacity(s) < 4) + { + WLog_ERR(TAG, "%s::NegotiateFlags expected 4bytes, have %" PRIuz "bytes", name, + Stream_GetRemainingCapacity(s)); + return FALSE; + } + + WLog_DBG(TAG, "Write flags %s", ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), flags)); + Stream_Write_UINT32(s, flags); /* NegotiateFlags (4 bytes) */ + return TRUE; +} + +static BOOL ntlm_read_message_integrity_check(wStream* s, size_t* offset, BYTE* data, size_t size, + const char* name) +{ + WINPR_ASSERT(s); + WINPR_ASSERT(offset); + WINPR_ASSERT(data); + WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH); + WINPR_ASSERT(name); + + *offset = Stream_GetPosition(s); + + if (Stream_GetRemainingLength(s) < size) + { + WLog_ERR(TAG, + "%s::MessageIntegrityCheckOffset expected %" PRIuz "bytes, got " + "%" PRIuz "byets", + name, size, Stream_GetRemainingLength(s)); + return FALSE; + } + + Stream_Read(s, data, size); + return TRUE; +} + +static BOOL ntlm_write_message_integrity_check(wStream* s, size_t offset, const BYTE* data, + size_t size, const char* name) +{ + size_t pos; + + WINPR_ASSERT(s); + WINPR_ASSERT(data); + WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH); + WINPR_ASSERT(name); + + pos = Stream_GetPosition(s); + + if (offset + size > Stream_Capacity(s)) + { + WLog_ERR(TAG, + "%s::MessageIntegrityCheck invalid offset[length] %" PRIuz "[%" PRIuz + "], got %" PRIuz, + name, offset, size, Stream_GetRemainingCapacity(s)); + return FALSE; + } + Stream_SetPosition(s, offset); + if (Stream_GetRemainingCapacity(s) < size) + { + WLog_ERR(TAG, "%s::MessageIntegrityCheck expected %" PRIuz "bytes, got %" PRIuz "bytes", + name, size, Stream_GetRemainingCapacity(s)); + return FALSE; + } + + Stream_Write(s, data, size); + Stream_SetPosition(s, pos); + return TRUE; } -#endif SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { + wStream sbuffer; wStream* s; size_t length; + const NTLM_NEGOTIATE_MESSAGE empty = { 0 }; NTLM_NEGOTIATE_MESSAGE* message; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + message = &context->NEGOTIATE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; - if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) - { - Stream_Free(s, FALSE); + if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_NEGOTIATE)) return SEC_E_INVALID_TOKEN; - } - if (message->MessageType != MESSAGE_TYPE_NEGOTIATE) - { - Stream_Free(s, FALSE); + if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, + NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | + NTLMSSP_NEGOTIATE_UNICODE, + "NTLM_NEGOTIATE_MESSAGE")) return SEC_E_INVALID_TOKEN; - } - - if (Stream_GetRemainingLength(s) < 4) - { - Stream_Free(s, FALSE); - return SEC_E_INVALID_TOKEN; - } - Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ - - if (!((message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) && - (message->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) && - (message->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE))) - { - Stream_Free(s, FALSE); - return SEC_E_INVALID_TOKEN; - } context->NegotiateFlags = message->NegotiateFlags; /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ - - if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */ + // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) { - Stream_Free(s, FALSE); - return SEC_E_INVALID_TOKEN; + if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ + return SEC_E_INVALID_TOKEN; } /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ - - if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */ + // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) { - Stream_Free(s, FALSE); - return SEC_E_INVALID_TOKEN; + if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ + return SEC_E_INVALID_TOKEN; } if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { - if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ - { - Stream_Free(s, FALSE); + if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ return SEC_E_INVALID_TOKEN; - } } + if (!ntlm_read_message_fields_buffer(s, &message->DomainName)) + return SEC_E_INVALID_TOKEN; + + if (!ntlm_read_message_fields_buffer(s, &message->Workstation)) + return SEC_E_INVALID_TOKEN; + length = Stream_GetPosition(s); - buffer->cbBuffer = length; + WINPR_ASSERT(length <= ULONG_MAX); + buffer->cbBuffer = (ULONG)length; - if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length)) - { - Stream_Free(s, FALSE); + if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length)) return SEC_E_INTERNAL_ERROR; - } CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); context->NegotiateMessage.BufferType = buffer->BufferType; -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", context->NegotiateMessage.cbBuffer); - winpr_HexDump(TAG, WLOG_DEBUG, context->NegotiateMessage.pvBuffer, - context->NegotiateMessage.cbBuffer); - ntlm_print_negotiate_flags(message->NegotiateFlags); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - +#if defined(WITH_DEBUG_NTLM) + ntlm_print_negotiate_message(&context->NegotiateMessage, message); #endif - context->state = NTLM_STATE_CHALLENGE; - Stream_Free(s, FALSE); + ntlm_change_state(context, NTLM_STATE_CHALLENGE); return SEC_I_CONTINUE_NEEDED; } SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { + wStream sbuffer; wStream* s; size_t length; + const NTLM_NEGOTIATE_MESSAGE empty = { 0 }; NTLM_NEGOTIATE_MESSAGE* message; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + message = &context->NEGOTIATE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; - ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_NEGOTIATE); + if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_NEGOTIATE)) + return SEC_E_INTERNAL_ERROR; if (context->NTLMv2) { @@ -329,96 +661,101 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu context->NegotiateFlags = message->NegotiateFlags; /* Message Header (12 bytes) */ - ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + if (!ntlm_write_message_header(s, &message->header)) + return SEC_E_INTERNAL_ERROR; + + if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_NEGOTIATE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; + /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ /* DomainNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->DomainName)); + if (!ntlm_write_message_fields(s, &(message->DomainName))) + return SEC_E_INTERNAL_ERROR; + /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ /* WorkstationFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->Workstation)); + if (!ntlm_write_message_fields(s, &(message->Workstation))) + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_write_version_info(s, &(message->Version)); + { + if (!ntlm_write_version_info(s, &(message->Version))) + return SEC_E_INTERNAL_ERROR; + } length = Stream_GetPosition(s); - buffer->cbBuffer = length; + WINPR_ASSERT(length <= ULONG_MAX); + buffer->cbBuffer = (ULONG)length; - if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length)) - { - Stream_Free(s, FALSE); + if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length)) return SEC_E_INTERNAL_ERROR; - } CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); context->NegotiateMessage.BufferType = buffer->BufferType; -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %d)", length); - winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - +#if defined(WITH_DEBUG_NTLM) + ntlm_print_negotiate_message(&context->NegotiateMessage, message); #endif - context->state = NTLM_STATE_CHALLENGE; - Stream_Free(s, FALSE); + ntlm_change_state(context, NTLM_STATE_CHALLENGE); return SEC_I_CONTINUE_NEEDED; } SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { SECURITY_STATUS status = SEC_E_INVALID_TOKEN; + wStream sbuffer; wStream* s; size_t length; size_t StartOffset; size_t PayloadOffset; NTLM_AV_PAIR* AvTimestamp; + const NTLM_CHALLENGE_MESSAGE empty = { 0 }; NTLM_CHALLENGE_MESSAGE* message; + if (!context || !buffer) return SEC_E_INTERNAL_ERROR; ntlm_generate_client_challenge(context); message = &context->CHALLENGE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; StartOffset = Stream_GetPosition(s); - if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) + if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_CHALLENGE)) goto fail; - if (message->MessageType != MESSAGE_TYPE_CHALLENGE) + if (!ntlm_read_message_fields(s, &(message->TargetName))) /* TargetNameFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->TargetName)) < 0) /* TargetNameFields (8 bytes) */ + if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_CHALLENGE_MESSAGE")) goto fail; - if (Stream_GetRemainingLength(s) < 4) - goto fail; - - Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ context->NegotiateFlags = message->NegotiateFlags; - if (Stream_GetRemainingLength(s) < 8) + if (Stream_GetRemainingLength(s) < 16) + { + WLog_ERR(TAG, + "NTLM_CHALLENGE_MESSAGE::ServerChallenge expected 16bytes, got %" PRIuz "bytes", + Stream_GetRemainingLength(s)); goto fail; + } Stream_Read(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ CopyMemory(context->ServerChallenge, message->ServerChallenge, 8); - - if (Stream_GetRemainingLength(s) < 8) - goto fail; - Stream_Read(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */ - if (ntlm_read_message_fields(s, &(message->TargetInfo)) < 0) /* TargetInfoFields (8 bytes) */ + if (!ntlm_read_message_fields(s, &(message->TargetInfo))) /* TargetInfoFields (8 bytes) */ goto fail; if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { - if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ + if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ goto fail; } @@ -428,7 +765,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf status = SEC_E_INTERNAL_ERROR; if (message->TargetName.Len > 0) { - if (ntlm_read_message_fields_buffer(s, &(message->TargetName)) < 0) + if (!ntlm_read_message_fields_buffer(s, &(message->TargetName))) goto fail; } @@ -436,7 +773,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf { size_t cbAvTimestamp; - if (ntlm_read_message_fields_buffer(s, &(message->TargetInfo)) < 0) + if (!ntlm_read_message_fields_buffer(s, &(message->TargetInfo))) goto fail; context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer; @@ -462,36 +799,19 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf if (length > buffer->cbBuffer) goto fail; - if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length)) + if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length)) goto fail; if (context->ChallengeMessage.pvBuffer) CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s) + StartOffset, length); -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length); - winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer, - context->ChallengeMessage.cbBuffer); - ntlm_print_negotiate_flags(context->NegotiateFlags); - - if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - - ntlm_print_message_fields(&(message->TargetName), "TargetName"); - ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); - - if (context->ChallengeTargetInfo.cbBuffer > 0) - { - WLog_DBG(TAG, "ChallengeTargetInfo (%" PRIu32 "):", context->ChallengeTargetInfo.cbBuffer); - ntlm_print_av_pair_list(context->ChallengeTargetInfo.pvBuffer, - context->ChallengeTargetInfo.cbBuffer); - } - +#if defined(WITH_DEBUG_NTLM) + ntlm_print_challenge_message(&context->ChallengeMessage, message, NULL); #endif /* AV_PAIRs */ if (context->NTLMv2) { - if (ntlm_construct_authenticate_target_info(context) < 0) + if (!ntlm_construct_authenticate_target_info(context)) goto fail; sspi_SecBufferFree(&context->ChallengeTargetInfo); @@ -501,10 +821,10 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf ntlm_generate_timestamp(context); /* Timestamp */ - if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */ + if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ goto fail; - if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */ + if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */ goto fail; ntlm_generate_key_exchange_key(context); /* KeyExchangeKey */ @@ -512,54 +832,45 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf ntlm_generate_exported_session_key(context); /* ExportedSessionKey */ ntlm_encrypt_random_session_key(context); /* EncryptedRandomSessionKey */ /* Generate signing keys */ - ntlm_generate_client_signing_key(context); - ntlm_generate_server_signing_key(context); + if (!ntlm_generate_client_signing_key(context)) + goto fail; + if (!ntlm_generate_server_signing_key(context)) + goto fail; /* Generate sealing keys */ - ntlm_generate_client_sealing_key(context); - ntlm_generate_server_sealing_key(context); + if (!ntlm_generate_client_sealing_key(context)) + goto fail; + if (!ntlm_generate_server_sealing_key(context)) + goto fail; /* Initialize RC4 seal state using client sealing key */ ntlm_init_rc4_seal_states(context); -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "ClientChallenge"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8); - WLog_DBG(TAG, "ServerChallenge"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8); - WLog_DBG(TAG, "SessionBaseKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16); - WLog_DBG(TAG, "KeyExchangeKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16); - WLog_DBG(TAG, "ExportedSessionKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16); - WLog_DBG(TAG, "RandomSessionKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16); - WLog_DBG(TAG, "ClientSigningKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16); - WLog_DBG(TAG, "ClientSealingKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16); - WLog_DBG(TAG, "ServerSigningKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16); - WLog_DBG(TAG, "ServerSealingKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16); - WLog_DBG(TAG, "Timestamp"); - winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8); +#if defined(WITH_DEBUG_NTLM) + ntlm_print_authentication_complete(context); #endif - context->state = NTLM_STATE_AUTHENTICATE; + ntlm_change_state(context, NTLM_STATE_AUTHENTICATE); status = SEC_I_CONTINUE_NEEDED; fail: ntlm_free_message_fields_buffer(&(message->TargetName)); - Stream_Free(s, FALSE); return status; } SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { + wStream sbuffer; wStream* s; size_t length; UINT32 PayloadOffset; + const NTLM_CHALLENGE_MESSAGE empty = { 0 }; NTLM_CHALLENGE_MESSAGE* message; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + message = &context->CHALLENGE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; @@ -568,17 +879,17 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu ntlm_generate_server_challenge(context); /* Server Challenge */ ntlm_generate_timestamp(context); /* Timestamp */ - if (ntlm_construct_challenge_target_info(context) < 0) /* TargetInfo */ - { - Stream_Free(s, FALSE); + if (!ntlm_construct_challenge_target_info(context)) /* TargetInfo */ return SEC_E_INTERNAL_ERROR; - } CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */ message->NegotiateFlags = context->NegotiateFlags; - ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_CHALLENGE); + if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_CHALLENGE)) + return SEC_E_INTERNAL_ERROR; + /* Message Header (12 bytes) */ - ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); + if (!ntlm_write_message_header(s, &message->header)) + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) { @@ -602,99 +913,119 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu message->TargetName.BufferOffset = PayloadOffset; message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len; /* TargetNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->TargetName)); - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ - Stream_Write(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ - Stream_Write(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */ - /* TargetInfoFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->TargetInfo)); + if (!ntlm_write_message_fields(s, &(message->TargetName))) + return SEC_E_INTERNAL_ERROR; - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */ + if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_CHALLENGE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; - /* Payload (variable) */ - - if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) - ntlm_write_message_fields_buffer(s, &(message->TargetName)); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO) - ntlm_write_message_fields_buffer(s, &(message->TargetInfo)); - - length = Stream_GetPosition(s); - buffer->cbBuffer = length; - - if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length)) + if (Stream_GetRemainingCapacity(s) < 16) { - Stream_Free(s, FALSE); + WLog_ERR(TAG, + "NTLM_CHALLENGE_MESSAGE::ServerChallenge expected 16bytes, got %" PRIuz "bytes", + Stream_GetRemainingCapacity(s)); return SEC_E_INTERNAL_ERROR; } - CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length); -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length); - winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer, - context->ChallengeMessage.cbBuffer); - ntlm_print_negotiate_flags(message->NegotiateFlags); + Stream_Write(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ + Stream_Write(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */ + + /* TargetInfoFields (8 bytes) */ + if (!ntlm_write_message_fields(s, &(message->TargetInfo))) + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); + { + if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + } - ntlm_print_message_fields(&(message->TargetName), "TargetName"); - ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); + /* Payload (variable) */ + if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) + { + if (!ntlm_write_message_fields_buffer(s, &(message->TargetName))) + return SEC_E_INTERNAL_ERROR; + } + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO) + { + if (!ntlm_write_message_fields_buffer(s, &(message->TargetInfo))) + return SEC_E_INTERNAL_ERROR; + } + + length = Stream_GetPosition(s); + WINPR_ASSERT(length <= ULONG_MAX); + buffer->cbBuffer = (ULONG)length; + + if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length)) + return SEC_E_INTERNAL_ERROR; + + CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length); +#if defined(WITH_DEBUG_NTLM) + ntlm_print_challenge_message(&context->ChallengeMessage, message, + &context->ChallengeTargetInfo); #endif - context->state = NTLM_STATE_AUTHENTICATE; - Stream_Free(s, FALSE); + ntlm_change_state(context, NTLM_STATE_AUTHENTICATE); return SEC_I_CONTINUE_NEEDED; } SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { SECURITY_STATUS status = SEC_E_INVALID_TOKEN; + wStream sbuffer; wStream* s; size_t length; UINT32 flags = 0; NTLM_AV_PAIR* AvFlags = NULL; - UINT32 PayloadBufferOffset; + size_t PayloadBufferOffset; + const NTLM_AUTHENTICATE_MESSAGE empty = { 0 }; NTLM_AUTHENTICATE_MESSAGE* message; - SSPI_CREDENTIALS* credentials = context->credentials; + SSPI_CREDENTIALS* credentials; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + + credentials = context->credentials; + WINPR_ASSERT(credentials); message = &context->AUTHENTICATE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; - if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) + if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_AUTHENTICATE)) goto fail; - if (message->MessageType != MESSAGE_TYPE_AUTHENTICATE) + if (!ntlm_read_message_fields( + s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->LmChallengeResponse)) < - 0) /* LmChallengeResponseFields (8 bytes) */ + if (!ntlm_read_message_fields( + s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->NtChallengeResponse)) < - 0) /* NtChallengeResponseFields (8 bytes) */ + if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */ + if (!ntlm_read_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->UserName)) < 0) /* UserNameFields (8 bytes) */ + if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */ + if (!ntlm_read_message_fields( + s, + &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->EncryptedRandomSessionKey)) < - 0) /* EncryptedRandomSessionKeyFields (8 bytes) */ + if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_AUTHENTICATE_MESSAGE")) goto fail; - if (Stream_GetRemainingLength(s) < 4) - goto fail; - Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ context->NegotiateKeyExchange = (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE; @@ -704,44 +1035,42 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { - if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ + if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ goto fail; } PayloadBufferOffset = Stream_GetPosition(s); status = SEC_E_INTERNAL_ERROR; - if (ntlm_read_message_fields_buffer(s, &(message->DomainName)) < 0) /* DomainName */ + if (!ntlm_read_message_fields_buffer(s, &(message->DomainName))) /* DomainName */ goto fail; - if (ntlm_read_message_fields_buffer(s, &(message->UserName)) < 0) /* UserName */ + if (!ntlm_read_message_fields_buffer(s, &(message->UserName))) /* UserName */ goto fail; - if (ntlm_read_message_fields_buffer(s, &(message->Workstation)) < 0) /* Workstation */ + if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ goto fail; - if (ntlm_read_message_fields_buffer(s, &(message->LmChallengeResponse)) < - 0) /* LmChallengeResponse */ + if (!ntlm_read_message_fields_buffer(s, + &(message->LmChallengeResponse))) /* LmChallengeResponse */ goto fail; - if (ntlm_read_message_fields_buffer(s, &(message->NtChallengeResponse)) < - 0) /* NtChallengeResponse */ + if (!ntlm_read_message_fields_buffer(s, + &(message->NtChallengeResponse))) /* NtChallengeResponse */ goto fail; if (message->NtChallengeResponse.Len > 0) { - int rc; size_t cbAvFlags; - wStream* snt = - Stream_New(message->NtChallengeResponse.Buffer, message->NtChallengeResponse.Len); + wStream ssbuffer; + wStream* snt = Stream_StaticConstInit(&ssbuffer, message->NtChallengeResponse.Buffer, + message->NtChallengeResponse.Len); if (!snt) goto fail; status = SEC_E_INVALID_TOKEN; - rc = ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response)); - Stream_Free(snt, FALSE); - if (rc < 0) + if (!ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response))) goto fail; status = SEC_E_INTERNAL_ERROR; @@ -759,8 +1088,8 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); } - if (ntlm_read_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)) < - 0) /* EncryptedRandomSessionKey */ + if (!ntlm_read_message_fields_buffer( + s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */ goto fail; if (message->EncryptedRandomSessionKey.Len > 0) @@ -773,51 +1102,28 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer } length = Stream_GetPosition(s); + WINPR_ASSERT(length <= ULONG_MAX); - if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length)) + if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length)) goto fail; CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length); - buffer->cbBuffer = length; + buffer->cbBuffer = (ULONG)length; Stream_SetPosition(s, PayloadBufferOffset); if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) { - context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s); - status = SEC_E_INVALID_TOKEN; - if (Stream_GetRemainingLength(s) < 16) + if (!ntlm_read_message_integrity_check( + s, &context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE")) goto fail; - - Stream_Read(s, message->MessageIntegrityCheck, 16); } status = SEC_E_INTERNAL_ERROR; -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")", - context->AuthenticateMessage.cbBuffer); - winpr_HexDump(TAG, WLOG_DEBUG, context->AuthenticateMessage.pvBuffer, - context->AuthenticateMessage.cbBuffer); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - - ntlm_print_message_fields(&(message->DomainName), "DomainName"); - ntlm_print_message_fields(&(message->UserName), "UserName"); - ntlm_print_message_fields(&(message->Workstation), "Workstation"); - ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); - ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); - ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); - ntlm_print_av_pair_list(context->NTLMv2Response.Challenge.AvPairs, - context->NTLMv2Response.Challenge.cbAvPairs); - - if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) - { - WLog_DBG(TAG, "MessageIntegrityCheck:"); - winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16); - } - +#if defined(WITH_DEBUG_NTLM) + ntlm_print_authenticate_message(&context->AuthenticateMessage, message, flags, NULL); #endif if (message->UserName.Len > 0) @@ -843,13 +1149,11 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer credentials->identity.DomainLength = message->DomainName.Len / 2; } - Stream_Free(s, FALSE); /* Computations beyond this point require the NTLM hash of the password */ - context->state = NTLM_STATE_COMPLETION; + ntlm_change_state(context, NTLM_STATE_COMPLETION); return SEC_I_COMPLETE_NEEDED; fail: - Stream_Free(s, FALSE); return status; } @@ -862,14 +1166,26 @@ fail: SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { + wStream sbuffer; wStream* s; size_t length; UINT32 PayloadBufferOffset; + const NTLM_AUTHENTICATE_MESSAGE empty = { 0 }; NTLM_AUTHENTICATE_MESSAGE* message; - SSPI_CREDENTIALS* credentials = context->credentials; + SSPI_CREDENTIALS* credentials; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + + credentials = context->credentials; + WINPR_ASSERT(credentials); + message = &context->AUTHENTICATE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; @@ -948,95 +1264,103 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len; message->EncryptedRandomSessionKey.BufferOffset = message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len; - ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_AUTHENTICATE); - ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); /* Message Header (12 bytes) */ - ntlm_write_message_fields( - s, &(message->LmChallengeResponse)); /* LmChallengeResponseFields (8 bytes) */ - ntlm_write_message_fields( - s, &(message->NtChallengeResponse)); /* NtChallengeResponseFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->DomainName)); /* DomainNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->UserName)); /* UserNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->Workstation)); /* WorkstationFields (8 bytes) */ - ntlm_write_message_fields( - s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKeyFields (8 bytes) */ - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_AUTHENTICATE)) + return SEC_E_INVALID_TOKEN; + if (!ntlm_write_message_header(s, &message->header)) /* Message Header (12 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields( + s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields( + s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields( + s, + &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_AUTHENTICATE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */ + { + if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + } if (context->UseMIC) { - context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s); - Stream_Zero(s, 16); /* Message Integrity Check (16 bytes) */ + const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 }; + + context->MessageIntegrityCheckOffset = Stream_GetPosition(s); + if (!ntlm_write_message_integrity_check(s, Stream_GetPosition(s), data, sizeof(data), + "NTLM_AUTHENTICATE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; } if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) - ntlm_write_message_fields_buffer(s, &(message->DomainName)); /* DomainName */ - - ntlm_write_message_fields_buffer(s, &(message->UserName)); /* UserName */ - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) - ntlm_write_message_fields_buffer(s, &(message->Workstation)); /* Workstation */ - - ntlm_write_message_fields_buffer(s, &(message->LmChallengeResponse)); /* LmChallengeResponse */ - ntlm_write_message_fields_buffer(s, &(message->NtChallengeResponse)); /* NtChallengeResponse */ - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) - ntlm_write_message_fields_buffer( - s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKey */ - - length = Stream_GetPosition(s); - - if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length)) { - Stream_Free(s, FALSE); - return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields_buffer(s, &(message->DomainName))) /* DomainName */ + return SEC_E_INTERNAL_ERROR; } + if (!ntlm_write_message_fields_buffer(s, &(message->UserName))) /* UserName */ + return SEC_E_INTERNAL_ERROR; + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) + { + if (!ntlm_write_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ + return SEC_E_INTERNAL_ERROR; + } + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) + { + if (!ntlm_write_message_fields_buffer( + s, &(message->LmChallengeResponse))) /* LmChallengeResponse */ + return SEC_E_INTERNAL_ERROR; + } + if (!ntlm_write_message_fields_buffer( + s, &(message->NtChallengeResponse))) /* NtChallengeResponse */ + return SEC_E_INTERNAL_ERROR; + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) + { + if (!ntlm_write_message_fields_buffer( + s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */ + return SEC_E_INTERNAL_ERROR; + } + + length = Stream_GetPosition(s); + WINPR_ASSERT(length <= ULONG_MAX); + + if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length)) + return SEC_E_INTERNAL_ERROR; + CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length); - buffer->cbBuffer = length; + buffer->cbBuffer = (ULONG)length; if (context->UseMIC) { /* Message Integrity Check */ - ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck, 16); - Stream_SetPosition(s, context->MessageIntegrityCheckOffset); - Stream_Write(s, message->MessageIntegrityCheck, 16); - Stream_SetPosition(s, length); - } - -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %d)", length); - winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); - ntlm_print_negotiate_flags(message->NegotiateFlags); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - - if (context->AuthenticateTargetInfo.cbBuffer > 0) - { - WLog_DBG(TAG, - "AuthenticateTargetInfo (%" PRIu32 "):", context->AuthenticateTargetInfo.cbBuffer); - ntlm_print_av_pair_list(context->AuthenticateTargetInfo.pvBuffer, - context->AuthenticateTargetInfo.cbBuffer); - } - - ntlm_print_message_fields(&(message->DomainName), "DomainName"); - ntlm_print_message_fields(&(message->UserName), "UserName"); - ntlm_print_message_fields(&(message->Workstation), "Workstation"); - ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); - ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); - ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); - - if (context->UseMIC) - { - WLog_DBG(TAG, "MessageIntegrityCheck (length = 16)"); - winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16); + ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck)); + if (!ntlm_write_message_integrity_check( + s, context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; } +#if defined(WITH_DEBUG_NTLM) + ntlm_print_authenticate_message(&context->AuthenticateMessage, message, + context->UseMIC ? MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK : 0, + &context->AuthenticateTargetInfo); #endif - context->state = NTLM_STATE_FINAL; - Stream_Free(s, FALSE); + ntlm_change_state(context, NTLM_STATE_FINAL); return SEC_E_OK; } @@ -1046,25 +1370,29 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) size_t cbAvFlags; NTLM_AV_PAIR* AvFlags = NULL; NTLM_AUTHENTICATE_MESSAGE* message; - BYTE messageIntegrityCheck[16]; if (!context) return SEC_E_INVALID_PARAMETER; - if (context->state != NTLM_STATE_COMPLETION) + if (ntlm_get_state(context) != NTLM_STATE_COMPLETION) return SEC_E_OUT_OF_SEQUENCE; message = &context->AUTHENTICATE_MESSAGE; + WINPR_ASSERT(message); + AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags); if (AvFlags) Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); - if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */ - return SEC_E_INTERNAL_ERROR; + if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) + { + if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ + return SEC_E_INTERNAL_ERROR; + } - if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */ + if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */ return SEC_E_INTERNAL_ERROR; /* KeyExchangeKey */ @@ -1076,16 +1404,16 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) { - ZeroMemory( - &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset], - 16); + BYTE messageIntegrityCheck[16] = { 0 }; + ntlm_compute_message_integrity_check(context, messageIntegrityCheck, sizeof(messageIntegrityCheck)); CopyMemory( &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset], - message->MessageIntegrityCheck, 16); + message->MessageIntegrityCheck, sizeof(message->MessageIntegrityCheck)); - if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck, 16) != 0) + if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck)) != 0) { WLog_ERR(TAG, "Message Integrity Check (MIC) verification failed!"); #ifdef WITH_DEBUG_NTLM @@ -1111,7 +1439,7 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) */ #ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "No MIC present, using NtProofString for verification."); + WLog_VRB(TAG, "No MIC present, using NtProofString for verification."); #endif if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0) @@ -1129,38 +1457,21 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) } /* Generate signing keys */ - ntlm_generate_client_signing_key(context); - ntlm_generate_server_signing_key(context); + if (!ntlm_generate_client_signing_key(context)) + return SEC_E_INTERNAL_ERROR; + if (!ntlm_generate_server_signing_key(context)) + return SEC_E_INTERNAL_ERROR; /* Generate sealing keys */ - ntlm_generate_client_sealing_key(context); - ntlm_generate_server_sealing_key(context); + if (!ntlm_generate_client_sealing_key(context)) + return SEC_E_INTERNAL_ERROR; + if (!ntlm_generate_server_sealing_key(context)) + return SEC_E_INTERNAL_ERROR; /* Initialize RC4 seal state */ ntlm_init_rc4_seal_states(context); -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "ClientChallenge"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8); - WLog_DBG(TAG, "ServerChallenge"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8); - WLog_DBG(TAG, "SessionBaseKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16); - WLog_DBG(TAG, "KeyExchangeKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16); - WLog_DBG(TAG, "ExportedSessionKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16); - WLog_DBG(TAG, "RandomSessionKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16); - WLog_DBG(TAG, "ClientSigningKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16); - WLog_DBG(TAG, "ClientSealingKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16); - WLog_DBG(TAG, "ServerSigningKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16); - WLog_DBG(TAG, "ServerSealingKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16); - WLog_DBG(TAG, "Timestamp"); - winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8); +#if defined(WITH_DEBUG_NTLM) + ntlm_print_authentication_complete(context); #endif - context->state = NTLM_STATE_FINAL; + ntlm_change_state(context, NTLM_STATE_FINAL); ntlm_free_message_fields_buffer(&(message->DomainName)); ntlm_free_message_fields_buffer(&(message->UserName)); ntlm_free_message_fields_buffer(&(message->Workstation)); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.h b/winpr/libwinpr/sspi/NTLM/ntlm_message.h index 100d95a..58ff35d 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.h @@ -23,12 +23,14 @@ #include "ntlm.h" SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); -SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer); -SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); -SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context); +const char* ntlm_get_negotiate_string(UINT32 flag); + #endif /* WINPR_SSPI_NTLM_MESSAGE_H */ diff --git a/winpr/libwinpr/sspi/test/TestNTLM.c b/winpr/libwinpr/sspi/test/TestNTLM.c index 82d266f..9260bf0 100644 --- a/winpr/libwinpr/sspi/test/TestNTLM.c +++ b/winpr/libwinpr/sspi/test/TestNTLM.c @@ -467,18 +467,15 @@ void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm) free(ntlm); } -int TestNTLM(int argc, char* argv[]) +static BOOL test_default(void) { int status; - int rc = -1; + BOOL rc = FALSE; PSecBuffer pSecBuffer; TEST_NTLM_CLIENT* client = NULL; TEST_NTLM_SERVER* server = NULL; BOOL DynamicTest = TRUE; - WINPR_UNUSED(argc); - WINPR_UNUSED(argv); - /** * Client Initialization */ @@ -684,7 +681,7 @@ int TestNTLM(int argc, char* argv[]) goto fail; } - rc = 0; + rc = TRUE; fail: /** @@ -694,3 +691,13 @@ fail: test_ntlm_server_free(server); return rc; } + +int TestNTLM(int argc, char* argv[]) +{ + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + + if (!test_default()) + return -1; + return 0; +} diff --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c index 5a13b99..1d491b8 100644 --- a/winpr/libwinpr/sspicli/sspicli.c +++ b/winpr/libwinpr/sspicli/sspicli.c @@ -21,11 +21,9 @@ #include "config.h" #endif -#include +#include #include -#define WINPR_ASSERT(x) assert(x) - /** * sspicli.dll: *