VYPR
Unrated severityNVD Advisory· Published Jun 22, 2020· Updated Aug 4, 2024

Use-After-Free in gdi_SelectObject in FreeRDP

CVE-2020-4031

Description

In FreeRDP before version 2.1.2, there is a use-after-free in gdi_SelectObject. All FreeRDP clients using compatibility mode with /relax-order-checks are affected. This is fixed in version 2.1.2.

Affected products

1

Patches

2
584efae07338

Merge pull request #6285 from akallabeth/stable-backports2

https://github.com/freerdp/freerdpMartin FleiszJun 22, 2020via osv
82 files changed · +1936 594
  • ChangeLog+23 0 modified
    @@ -1,3 +1,26 @@
    +# 2020-06-22  Version 2.1.2
    +
    +Important notes:
    +* CVE-2020-4033 Out of bound read in RLEDECOMPRESS
    +* CVE-2020-4031 Use-After-Free in gdi_SelectObject
    +* CVE-2020-4032 Integer casting vulnerability in `update_recv_secondary_order`
    +* CVE-2020-4030 OOB read in `TrioParse`
    +* CVE-2020-11099 OOB Read in license_read_new_or_upgrade_license_packet
    +* CVE-2020-11098 Out-of-bound read in glyph_cache_put
    +* CVE-2020-11097 OOB read in ntlm_av_pair_get
    +* CVE-2020-11095 Global OOB read in update_recv_primary_order
    +* CVE-2020-11096 Global OOB read in update_read_cache_bitmap_v3_order
    +* Gateway RPC fixes for windows
    +* Fixed resource fee race resulting in double free in USB redirection
    +* Fixed wayland client crashes
    +* Fixed X11 client mouse mapping issues (X11 mapping on/off)
    +* Some proxy related improvements (capture module)
    +* Code cleanup (use getlogin_r, ...)
    +
    +For a complete and detailed change log since the last release candidate run:
    +git log 2.1.1..2.1.2
    +
    +
     # 2020-05-20  Version 2.1.1
     
     Important notes:
    
  • channels/drdynvc/client/drdynvc_main.c+12 5 modified
    @@ -580,10 +580,15 @@ static UINT dvcman_open_channel(drdynvcPlugin* drdynvc, IWTSVirtualChannelManage
     	{
     		pCallback = channel->channel_callback;
     
    -		if ((pCallback->OnOpen) && (error = pCallback->OnOpen(pCallback)))
    +		if (pCallback->OnOpen)
     		{
    -			WLog_Print(drdynvc->log, WLOG_ERROR, "OnOpen failed with error %" PRIu32 "!", error);
    -			return error;
    +			error = pCallback->OnOpen(pCallback);
    +			if (error)
    +			{
    +				WLog_Print(drdynvc->log, WLOG_ERROR, "OnOpen failed with error %" PRIu32 "!",
    +				           error);
    +				return error;
    +			}
     		}
     
     		WLog_Print(drdynvc->log, WLOG_DEBUG, "open_channel: ChannelId %" PRIu32 "", ChannelId);
    @@ -1583,13 +1588,15 @@ static UINT drdynvc_virtual_channel_event_terminated(drdynvcPlugin* drdynvc)
     	if (!drdynvc)
     		return CHANNEL_RC_BAD_CHANNEL_HANDLE;
     
    +	MessageQueue_Free(drdynvc->queue);
    +	drdynvc->queue = NULL;
    +
     	if (drdynvc->channel_mgr)
     	{
     		dvcman_free(drdynvc, drdynvc->channel_mgr);
     		drdynvc->channel_mgr = NULL;
     	}
    -	MessageQueue_Free(drdynvc->queue);
    -	drdynvc->queue = NULL;
    +
     	drdynvc->InitHandle = 0;
     	free(drdynvc->context);
     	free(drdynvc);
    
  • channels/encomsp/client/encomsp_main.c+3 0 modified
    @@ -1116,8 +1116,11 @@ static DWORD WINAPI encomsp_virtual_channel_client_thread(LPVOID arg)
     			if ((error = encomsp_process_receive(encomsp, data)))
     			{
     				WLog_ERR(TAG, "encomsp_process_receive failed with error %" PRIu32 "!", error);
    +				Stream_Free(data, TRUE);
     				break;
     			}
    +
    +			Stream_Free(data, TRUE);
     		}
     	}
     
    
  • channels/geometry/client/geometry_main.c+0 18 modified
    @@ -27,7 +27,6 @@
     
     #include <winpr/crt.h>
     #include <winpr/synch.h>
    -#include <winpr/interlocked.h>
     #include <winpr/print.h>
     #include <winpr/stream.h>
     #include <winpr/cmdline.h>
    @@ -82,23 +81,6 @@ static BOOL mappedGeometryKeyCompare(UINT64* g1, UINT64* g2)
     	return *g1 == *g2;
     }
     
    -void mappedGeometryRef(MAPPED_GEOMETRY* g)
    -{
    -	InterlockedIncrement(&g->refCounter);
    -}
    -
    -void mappedGeometryUnref(MAPPED_GEOMETRY* g)
    -{
    -	if (InterlockedDecrement(&g->refCounter))
    -		return;
    -
    -	g->MappedGeometryUpdate = NULL;
    -	g->MappedGeometryClear = NULL;
    -	g->custom = NULL;
    -	free(g->geometry.rects);
    -	free(g);
    -}
    -
     static void freerdp_rgndata_reset(FREERDP_RGNDATA* data)
     {
     	data->nRectCount = 0;
    
  • channels/printer/client/cups/printer_cups.c+2 1 modified
    @@ -69,10 +69,11 @@ struct rdp_cups_print_job
     static void printer_cups_get_printjob_name(char* buf, size_t size, size_t id)
     {
     	time_t tt;
    +	struct tm tres;
     	struct tm* t;
     
     	tt = time(NULL);
    -	t = localtime(&tt);
    +	t = localtime_r(&tt, &tres);
     	sprintf_s(buf, size - 1, "FreeRDP Print %04d-%02d-%02d %02d-%02d-%02d - Job %" PRIdz,
     	          t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, id);
     }
    
  • channels/printer/client/win/printer_win.c+2 1 modified
    @@ -78,13 +78,14 @@ struct rdp_win_print_job
     static WCHAR* printer_win_get_printjob_name(size_t id)
     {
     	time_t tt;
    +	struct tm tres;
     	struct tm* t;
     	WCHAR* str;
     	size_t len = 1024;
     	int rc;
     
     	tt = time(NULL);
    -	t = localtime(&tt);
    +	t = localtime_s(&tt, &tres);
     
     	str = calloc(len, sizeof(WCHAR));
     	if (!str)
    
  • channels/rdpdr/client/rdpdr_main.c+8 1 modified
    @@ -598,7 +598,14 @@ static BOOL isAutomountLocation(const char* path)
     	size_t x;
     	char buffer[MAX_PATH];
     	uid_t uid = getuid();
    -	const char* uname = getlogin();
    +	char uname[MAX_PATH] = { 0 };
    +
    +#ifndef getlogin_r
    +	strncpy(uname, getlogin(), sizeof(uname));
    +#else
    +	if (getlogin_r(uname, sizeof(uname)) != 0)
    +		return FALSE;
    +#endif
     
     	if (!path)
     		return FALSE;
    
  • channels/rdpei/client/rdpei_main.c+1 0 modified
    @@ -604,6 +604,7 @@ static UINT rdpei_plugin_terminated(IWTSPlugin* pPlugin)
     			IFCALL(mgr->DestroyListener, mgr, rdpei->listener);
     	}
     	free(rdpei->listener_callback);
    +	free(rdpei->contactPoints);
     	free(rdpei->context);
     	free(rdpei);
     	return CHANNEL_RC_OK;
    
  • channels/rdpei/rdpei_common.c+4 4 modified
    @@ -306,7 +306,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value)
     		value *= -1;
     	}
     
    -	if (value <= 0x1FUL)
    +	if (value <= 0x1FL)
     	{
     		byte = value & 0x1F;
     
    @@ -315,7 +315,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value)
     
     		Stream_Write_UINT8(s, byte);
     	}
    -	else if (value <= 0x1FFFUL)
    +	else if (value <= 0x1FFFL)
     	{
     		byte = (value >> 8) & 0x1F;
     
    @@ -326,7 +326,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value)
     		byte = (value & 0xFF);
     		Stream_Write_UINT8(s, byte);
     	}
    -	else if (value <= 0x1FFFFFUL)
    +	else if (value <= 0x1FFFFFL)
     	{
     		byte = (value >> 16) & 0x1F;
     
    @@ -339,7 +339,7 @@ BOOL rdpei_write_4byte_signed(wStream* s, INT32 value)
     		byte = (value & 0xFF);
     		Stream_Write_UINT8(s, byte);
     	}
    -	else if (value <= 0x1FFFFFFFUL)
    +	else if (value <= 0x1FFFFFFFL)
     	{
     		byte = (value >> 24) & 0x1F;
     
    
  • channels/remdesk/client/remdesk_main.c+3 0 modified
    @@ -843,8 +843,11 @@ static DWORD WINAPI remdesk_virtual_channel_client_thread(LPVOID arg)
     			if ((error = remdesk_process_receive(remdesk, data)))
     			{
     				WLog_ERR(TAG, "remdesk_process_receive failed with error %" PRIu32 "!", error);
    +				Stream_Free(data, TRUE);
     				break;
     			}
    +
    +			Stream_Free(data, TRUE);
     		}
     	}
     
    
  • channels/smartcard/client/smartcard_operations.c+48 2 modified
    @@ -921,15 +921,38 @@ static LONG smartcard_LocateCardsA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
     	ret.ReturnCode = SCardLocateCardsA(operation->hContext, call->mszCards, call->rgReaderStates,
     	                                   call->cReaders);
     	log_status_error(TAG, "SCardLocateCardsA", ret.ReturnCode);
    +	ret.cReaders = call->cReaders;
    +	ret.rgReaderStates = NULL;
    +
     	free(call->mszCards);
    +
    +	if (ret.cReaders > 0)
    +	{
    +		ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
    +
    +		if (!ret.rgReaderStates)
    +			return STATUS_NO_MEMORY;
    +	}
    +
    +	for (x = 0; x < ret.cReaders; x++)
    +	{
    +		ret.rgReaderStates[x].dwCurrentState = call->rgReaderStates[x].dwCurrentState;
    +		ret.rgReaderStates[x].dwEventState = call->rgReaderStates[x].dwEventState;
    +		ret.rgReaderStates[x].cbAtr = call->rgReaderStates[x].cbAtr;
    +		CopyMemory(&(ret.rgReaderStates[x].rgbAtr), &(call->rgReaderStates[x].rgbAtr),
    +		           sizeof(ret.rgReaderStates[x].rgbAtr));
    +	}
    +
    +	status = smartcard_pack_locate_cards_return(smartcard, irp->output, &ret);
    +
     	for (x = 0; x < call->cReaders; x++)
     	{
     		SCARD_READERSTATEA* state = &call->rgReaderStates[x];
     		free(state->szReader);
     	}
    +
     	free(call->rgReaderStates);
     
    -	status = smartcard_pack_locate_cards_return(smartcard, irp->output, &ret);
     	if (status != SCARD_S_SUCCESS)
     		return status;
     
    @@ -947,15 +970,38 @@ static LONG smartcard_LocateCardsW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
     	ret.ReturnCode = SCardLocateCardsW(operation->hContext, call->mszCards, call->rgReaderStates,
     	                                   call->cReaders);
     	log_status_error(TAG, "SCardLocateCardsW", ret.ReturnCode);
    +	ret.cReaders = call->cReaders;
    +	ret.rgReaderStates = NULL;
    +
     	free(call->mszCards);
    +
    +	if (ret.cReaders > 0)
    +	{
    +		ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
    +
    +		if (!ret.rgReaderStates)
    +			return STATUS_NO_MEMORY;
    +	}
    +
    +	for (x = 0; x < ret.cReaders; x++)
    +	{
    +		ret.rgReaderStates[x].dwCurrentState = call->rgReaderStates[x].dwCurrentState;
    +		ret.rgReaderStates[x].dwEventState = call->rgReaderStates[x].dwEventState;
    +		ret.rgReaderStates[x].cbAtr = call->rgReaderStates[x].cbAtr;
    +		CopyMemory(&(ret.rgReaderStates[x].rgbAtr), &(call->rgReaderStates[x].rgbAtr),
    +		           sizeof(ret.rgReaderStates[x].rgbAtr));
    +	}
    +
    +	status = smartcard_pack_locate_cards_return(smartcard, irp->output, &ret);
    +
     	for (x = 0; x < call->cReaders; x++)
     	{
     		SCARD_READERSTATEW* state = &call->rgReaderStates[x];
     		free(state->szReader);
     	}
    +
     	free(call->rgReaderStates);
     
    -	status = smartcard_pack_locate_cards_return(smartcard, irp->output, &ret);
     	if (status != SCARD_S_SUCCESS)
     		return status;
     
    
  • channels/smartcard/client/smartcard_pack.c+4 4 modified
    @@ -389,7 +389,7 @@ static char* smartcard_msz_dump_a(const char* msz, size_t len, char* buffer, siz
     
     static char* smartcard_msz_dump_w(const WCHAR* msz, size_t len, char* buffer, size_t bufferLen)
     {
    -	char* sz;
    +	char* sz = NULL;
     	ConvertFromUnicode(CP_UTF8, 0, msz, (int)len, &sz, 0, NULL, NULL);
     	return smartcard_msz_dump_a(sz, len, buffer, bufferLen);
     }
    @@ -466,7 +466,7 @@ static void smartcard_trace_context_and_string_call_w(const char* name,
                                                           const REDIR_SCARDCONTEXT* phContext,
                                                           const WCHAR* sz)
     {
    -	char* tmp;
    +	char* tmp = NULL;
     	if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
     		return;
     
    @@ -883,7 +883,7 @@ static void smartcard_trace_write_cache_a_call(SMARTCARD_DEVICE* smartcard,
     static void smartcard_trace_write_cache_w_call(SMARTCARD_DEVICE* smartcard,
                                                    const WriteCacheW_Call* call)
     {
    -	char* tmp;
    +	char* tmp = NULL;
     	char buffer[1024];
     	WINPR_UNUSED(smartcard);
     	if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
    @@ -931,7 +931,7 @@ static void smartcard_trace_read_cache_a_call(SMARTCARD_DEVICE* smartcard,
     static void smartcard_trace_read_cache_w_call(SMARTCARD_DEVICE* smartcard,
                                                   const ReadCacheW_Call* call)
     {
    -	char* tmp;
    +	char* tmp = NULL;
     	char buffer[1024];
     	WINPR_UNUSED(smartcard);
     	if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
    
  • channels/urbdrc/client/data_transfer.c+0 2 modified
    @@ -767,8 +767,6 @@ static void urb_isoch_transfer_cb(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callb
     			callback->channel->Write(callback->channel, Stream_GetPosition(out), Stream_Buffer(out),
     			                         NULL);
     	}
    -
    -	Stream_Free(out, TRUE);
     }
     
     static UINT urb_isoch_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s,
    
  • channels/urbdrc/client/libusb/libusb_udevice.c+24 14 modified
    @@ -296,7 +296,7 @@ static void func_bulk_transfer_cb(struct libusb_transfer* transfer)
     		user_data->cb(user_data->idev, user_data->callback, user_data->data, InterfaceId,
     		              user_data->noack, user_data->MessageId, RequestID, transfer->num_iso_packets,
     		              transfer->status, user_data->StartFrame, user_data->ErrorCount,
    -		              user_data->OutputBufferSize);
    +		              transfer->actual_length);
     		user_data->data = NULL;
     		HashTable_Remove(user_data->queue, (void*)(size_t)streamID);
     	}
    @@ -465,7 +465,7 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB
     
     static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting)
     {
    -	int error = 0, diff = 1;
    +	int error = 0, diff = 0;
     	UDEVICE* pdev = (UDEVICE*)idev;
     	URBDRC_PLUGIN* urbdrc;
     	MSUSB_CONFIG_DESCRIPTOR* MsConfig;
    @@ -480,21 +480,30 @@ static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BY
     	if (MsConfig)
     	{
     		MsInterfaces = MsConfig->MsInterfaces;
    -
    -		if ((MsInterfaces) && (MsInterfaces[InterfaceNumber]->AlternateSetting == AlternateSetting))
    +		if (MsInterfaces)
     		{
    -			diff = 0;
    -		}
    -	}
    +			WLog_Print(urbdrc->log, WLOG_INFO,
    +			           "select Interface(%" PRIu8 ") curr AlternateSetting(%" PRIu8
    +			           ") new AlternateSetting(" PRIu8 ")",
    +			           InterfaceNumber, MsInterfaces[InterfaceNumber]->AlternateSetting,
    +			           AlternateSetting);
     
    -	if (diff)
    -	{
    -		error = libusb_set_interface_alt_setting(pdev->libusb_handle, InterfaceNumber,
    -		                                         AlternateSetting);
    +			if (MsInterfaces[InterfaceNumber]->AlternateSetting != AlternateSetting)
    +			{
    +				diff = 1;
    +			}
    +		}
     
    -		if (error < 0)
    +		if (diff)
     		{
    -			WLog_Print(urbdrc->log, WLOG_ERROR, "Set interface altsetting get error num %d", error);
    +			error = libusb_set_interface_alt_setting(pdev->libusb_handle, InterfaceNumber,
    +			                                         AlternateSetting);
    +
    +			if (error < 0)
    +			{
    +				WLog_Print(urbdrc->log, WLOG_ERROR, "Set interface altsetting get error num %d",
    +				           error);
    +			}
     		}
     	}
     
    @@ -1168,6 +1177,7 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* c
     	user_data->streamID = streamID;
     #endif
     	libusb_set_iso_packet_lengths(iso_transfer, iso_packet_size);
    +
     	HashTable_Add(pdev->request_queue, (void*)(size_t)streamID, iso_transfer);
     	return libusb_submit_transfer(iso_transfer);
     }
    @@ -1292,7 +1302,6 @@ static int func_cancel_xact_request(URBDRC_PLUGIN* urbdrc, wHashTable* queue, ui
     		return -1;
     
     	status = libusb_cancel_transfer(transfer);
    -	HashTable_Remove(queue, (void*)(size_t)streamID);
     
     	if (status < 0)
     	{
    @@ -1348,6 +1357,7 @@ static int libusb_udev_cancel_transfer_request(IUDEVICE* idev, UINT32 RequestId)
     
     	urbdrc = (URBDRC_PLUGIN*)pdev->urbdrc;
     	cancelID = (id1) ? cancelID1 : cancelID2;
    +
     	transfer = HashTable_GetItemValue(pdev->request_queue, (void*)(size_t)cancelID);
     	return func_cancel_xact_request(urbdrc, pdev->request_queue, cancelID, transfer);
     }
    
  • client/Android/android_freerdp.c+1 1 modified
    @@ -56,7 +56,7 @@
     #define TAG CLIENT_TAG("android")
     
     /* Defines the JNI version supported by this library. */
    -#define FREERDP_JNI_VERSION "2.1.1"
    +#define FREERDP_JNI_VERSION "2.1.2"
     
     static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e)
     {
    
  • client/Android/Studio/build.gradle+1 1 modified
    @@ -29,7 +29,7 @@ def getVersionName = { ->
     
     ext {
         versionName = properties.get('VERSION_NAME', getVersionName())
    -    versionCode = properties.get('VERSION_CODE', 17)
    +    versionCode = properties.get('VERSION_CODE', 18)
     
         println '----------------- Project configuration -------------------'
         println 'VERSION_NAME:       ' + versionName
    
  • client/common/client.c+3 0 modified
    @@ -467,14 +467,17 @@ static DWORD client_cli_accept_certificate(rdpSettings* settings)
     		{
     			case 'y':
     			case 'Y':
    +				fgetc(stdin);
     				return 1;
     
     			case 't':
     			case 'T':
    +				fgetc(stdin);
     				return 2;
     
     			case 'n':
     			case 'N':
    +				fgetc(stdin);
     				return 0;
     
     			default:
    
  • client/common/CMakeLists.txt+2 1 modified
    @@ -30,7 +30,8 @@ set(${MODULE_PREFIX}_SRCS
     	cmdline.c
     	compatibility.c
     	compatibility.h
    -	file.c)
    +	file.c
    +	geometry.c)
     
     foreach(FREERDP_CHANNELS_CLIENT_SRC ${FREERDP_CHANNELS_CLIENT_SRCS})
     	get_filename_component(NINC ${FREERDP_CHANNELS_CLIENT_SRC} PATH)
    
  • client/common/geometry.c+42 0 added
    @@ -0,0 +1,42 @@
    +/**
    + * FreeRDP: A Remote Desktop Protocol Implementation
    + * Geometry tracking Virtual Channel Extension
    + *
    + * Copyright 2017 David Fort <contact@hardening-consulting.com>
    + *
    + * 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.
    + */
    +
    +#ifdef HAVE_CONFIG_H
    +#include "config.h"
    +#endif
    +
    +#include <freerdp/client/geometry.h>
    +#include <winpr/interlocked.h>
    +
    +void mappedGeometryRef(MAPPED_GEOMETRY* g)
    +{
    +	InterlockedIncrement(&g->refCounter);
    +}
    +
    +void mappedGeometryUnref(MAPPED_GEOMETRY* g)
    +{
    +	if (InterlockedDecrement(&g->refCounter))
    +		return;
    +
    +	g->MappedGeometryUpdate = NULL;
    +	g->MappedGeometryClear = NULL;
    +	g->custom = NULL;
    +	free(g->geometry.rects);
    +	free(g);
    +}
    
  • client/Wayland/wlf_input.c+12 3 modified
    @@ -30,7 +30,7 @@
     
     #define TAG CLIENT_TAG("wayland.input")
     
    -#define MAX_CONTACTS 10
    +#define MAX_CONTACTS 20
     
     typedef struct touch_contact
     {
    @@ -241,6 +241,9 @@ BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev)
     		}
     	}
     
    +	if (i == MAX_CONTACTS)
    +		return FALSE;
    +
     	WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y);
     
     	if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE))
    @@ -282,8 +285,6 @@ BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev)
     	y = ev->y;
     	touchId = ev->id;
     
    -	WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y);
    -
     	for (i = 0; i < MAX_CONTACTS; i++)
     	{
     		if (contacts[i].id == 0)
    @@ -296,6 +297,11 @@ BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev)
     		}
     	}
     
    +	if (i == MAX_CONTACTS)
    +		return FALSE;
    +
    +	WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y);
    +
     	if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE))
     		return FALSE;
     
    @@ -350,6 +356,9 @@ BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev)
     		}
     	}
     
    +	if (i == MAX_CONTACTS)
    +		return FALSE;
    +
     	WLog_DBG(TAG, "%s called | event_id: %u | x: %u / y: %u", __FUNCTION__, touchId, x, y);
     
     	if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE))
    
  • client/Wayland/wlfreerdp.c+25 11 modified
    @@ -62,6 +62,7 @@ static BOOL wl_begin_paint(rdpContext* context)
     
     static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw, INT32 ih)
     {
    +	BOOL res = FALSE;
     	rdpGdi* gdi;
     	char* data;
     	UINT32 x, y, w, h;
    @@ -76,6 +77,7 @@ static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw
     	if ((ix < 0) || (iy < 0) || (iw < 0) || (ih < 0))
     		return FALSE;
     
    +	EnterCriticalSection(&context_w->critical);
     	x = (UINT32)ix;
     	y = (UINT32)iy;
     	w = (UINT32)iw;
    @@ -84,16 +86,19 @@ static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw
     	data = UwacWindowGetDrawingBuffer(context_w->window);
     
     	if (!data || (rc != UWAC_SUCCESS))
    -		return FALSE;
    +		goto fail;
     
     	gdi = context_w->context.gdi;
     
     	if (!gdi)
    -		return FALSE;
    +		goto fail;
     
     	/* Ignore output if the surface size does not match. */
     	if (((INT64)x > geometry.width) || ((INT64)y > geometry.height))
    -		return TRUE;
    +	{
    +		res = TRUE;
    +		goto fail;
    +	}
     
     	area.left = x;
     	area.top = y;
    @@ -103,21 +108,24 @@ static BOOL wl_update_buffer(wlfContext* context_w, INT32 ix, INT32 iy, INT32 iw
     	if (!wlf_copy_image(gdi->primary_buffer, gdi->stride, gdi->width, gdi->height, data, stride,
     	                    geometry.width, geometry.height, &area,
     	                    context_w->context.settings->SmartSizing))
    -		return FALSE;
    +		goto fail;
     
     	if (!wlf_scale_coordinates(&context_w->context, &x, &y, FALSE))
    -		return FALSE;
    +		goto fail;
     
     	if (!wlf_scale_coordinates(&context_w->context, &w, &h, FALSE))
    -		return FALSE;
    +		goto fail;
     
     	if (UwacWindowAddDamage(context_w->window, x, y, w, h) != UWAC_SUCCESS)
    -		return FALSE;
    +		goto fail;
     
     	if (UwacWindowSubmitBuffer(context_w->window, false) != UWAC_SUCCESS)
    -		return FALSE;
    +		goto fail;
     
    -	return TRUE;
    +	res = TRUE;
    +fail:
    +	LeaveCriticalSection(&context_w->critical);
    +	return res;
     }
     
     static BOOL wl_end_paint(rdpContext* context)
    @@ -296,6 +304,7 @@ static void wl_post_disconnect(freerdp* instance)
     
     static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
     {
    +	BOOL rc;
     	UwacEvent event;
     	wlfContext* context;
     
    @@ -321,9 +330,11 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display)
     				break;
     
     			case UWAC_EVENT_FRAME_DONE:
    -				if (UwacWindowSubmitBuffer(context->window, false) != UWAC_SUCCESS)
    +				EnterCriticalSection(&context->critical);
    +				rc = UwacWindowSubmitBuffer(context->window, false);
    +				LeaveCriticalSection(&context->critical);
    +				if (rc != UWAC_SUCCESS)
     					return FALSE;
    -
     				break;
     
     			case UWAC_EVENT_POINTER_ENTER:
    @@ -552,6 +563,8 @@ static BOOL wlf_client_new(freerdp* instance, rdpContext* context)
     	if (!wfl->displayHandle)
     		return FALSE;
     
    +	InitializeCriticalSection(&wfl->critical);
    +
     	return TRUE;
     }
     
    @@ -567,6 +580,7 @@ static void wlf_client_free(freerdp* instance, rdpContext* context)
     
     	if (wlf->displayHandle)
     		CloseHandle(wlf->displayHandle);
    +	DeleteCriticalSection(&wlf->critical);
     }
     
     static int wfl_client_start(rdpContext* context)
    
  • client/Wayland/wlfreerdp.h+1 0 modified
    @@ -50,6 +50,7 @@ struct wlf_context
     	wfClipboard* clipboard;
     	wlfDispContext* disp;
     	wLog* log;
    +	CRITICAL_SECTION critical;
     };
     
     BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP);
    
  • client/X11/generate_argument_docbook.c+1 1 modified
    @@ -89,7 +89,7 @@ LPSTR tr_esc_str(LPCSTR arg, bool format)
     					strncpy(&tmp[cs], "</replaceable>", len);
     				else
     					/* coverity[buffer_size] */
    -					strncpy(&tmp[cs], "&lt;", len);
    +					strncpy(&tmp[cs], "&gt;", len);
     
     				cs += len;
     				break;
    
  • client/X11/xf_client.c+5 5 modified
    @@ -1120,7 +1120,7 @@ static void xf_button_map_init(xfContext* xfc)
     	x11_map[111] = 112;
     
     	/* query system for actual remapping */
    -	if (!xfc->context.settings->UnmapButtons)
    +	if (xfc->context.settings->UnmapButtons)
     	{
     		xf_get_x11_button_map(xfc, x11_map);
     	}
    @@ -1142,8 +1142,8 @@ static void xf_button_map_init(xfContext* xfc)
     			else
     			{
     				button_map* map = &xfc->button_map[pos++];
    -				map->button = physical + Button1;
    -				map->flags = get_flags_for_button(logical);
    +				map->button = logical;
    +				map->flags = get_flags_for_button(physical + Button1);
     			}
     		}
     	}
    @@ -1181,9 +1181,9 @@ static BOOL xf_pre_connect(freerdp* instance)
     
     	if (!settings->Username && !settings->CredentialsFromStdin && !settings->SmartcardLogon)
     	{
    -		char* login_name = getlogin();
    +		char login_name[MAX_PATH] = { 0 };
     
    -		if (login_name)
    +		if (getlogin_r(login_name, sizeof(login_name)) == 0)
     		{
     			settings->Username = _strdup(login_name);
     
    
  • client/X11/xf_event.c+3 3 modified
    @@ -374,12 +374,12 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window win
     }
     static BOOL xf_event_MotionNotify(xfContext* xfc, const XMotionEvent* event, BOOL app)
     {
    -	if (xfc->use_xinput)
    -		return TRUE;
    -
     	if (xfc->window)
     		xf_floatbar_set_root_y(xfc->window->floatbar, event->y);
     
    +	if (xfc->use_xinput)
    +		return TRUE;
    +
     	return xf_generic_MotionNotify(xfc, event->x, event->y, event->state, event->window, app);
     }
     
    
  • CMakeLists.txt+1 1 modified
    @@ -81,7 +81,7 @@ if ($ENV{BUILD_NUMBER})
     endif()
     set(WITH_LIBRARY_VERSIONING "ON")
     
    -set(RAW_VERSION_STRING "2.1.1")
    +set(RAW_VERSION_STRING "2.1.2")
     if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
     	file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
     elseif(USE_VERSION_FROM_GIT_TAG)
    
  • include/freerdp/scancode.h+6 1 modified
    @@ -166,7 +166,6 @@
     #define RDP_SCANCODE_TAB_JP MAKE_RDP_SCANCODE(0x7C, FALSE)        /* JP TAB */
     #define RDP_SCANCODE_BACKSLASH_JP MAKE_RDP_SCANCODE(0x7D, FALSE)  /* JP OEM_5 ('\') */
     #define RDP_SCANCODE_ABNT_C2 MAKE_RDP_SCANCODE(0x7E, FALSE)       /* VK_ABNT_C2, JP */
    -#define RDP_SCANCODE_ABNT_C2 MAKE_RDP_SCANCODE(0x7E, FALSE)       /* JP OEM_PA2 */
     #define RDP_SCANCODE_HANJA MAKE_RDP_SCANCODE(0x71, FALSE)         /* KR VK_HANJA */
     #define RDP_SCANCODE_HANGUL MAKE_RDP_SCANCODE(0x72, FALSE)        /* KR VK_HANGUL */
     
    @@ -229,4 +228,10 @@
     /* Misc. */
     #define RDP_SCANCODE_LAUNCH_MAIL MAKE_RDP_SCANCODE(0x6C, TRUE) /* VK_LAUNCH_MAIL */
     
    +#define RDP_SCANCODE_LAUNCH_MEDIA_SELECT                                                 \
    +	MAKE_RDP_SCANCODE(0x6D, TRUE)                              /* VK_LAUNCH_MEDIA_SELECT \
    +	                                                            */
    +#define RDP_SCANCODE_LAUNCH_APP1 MAKE_RDP_SCANCODE(0x6E, TRUE) /* VK_LAUNCH_APP1 */
    +#define RDP_SCANCODE_LAUNCH_APP2 MAKE_RDP_SCANCODE(0x6F, TRUE) /* VK_LAUNCH_APP2 */
    +
     #endif /* FREERDP_LOCALE_KEYBOARD_RDP_SCANCODE_H */
    
  • libfreerdp/cache/glyph.c+1 1 modified
    @@ -579,7 +579,7 @@ BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyp
     		return FALSE;
     	}
     
    -	if (index > glyphCache->glyphCache[id].number)
    +	if (index >= glyphCache->glyphCache[id].number)
     	{
     		WLog_ERR(TAG, "invalid glyph cache index: %" PRIu32 " in cache id: %" PRIu32 "", index, id);
     		return FALSE;
    
  • libfreerdp/codec/include/bitmap.c+12 0 modified
    @@ -201,6 +201,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
     
     				if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
     				{
    +					if (pbSrc >= pbEnd)
    +						return FALSE;
     					SRCREADPIXEL(fgPel, pbSrc);
     					SRCNEXTPIXEL(pbSrc);
     				}
    @@ -231,8 +233,12 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
     			case MEGA_MEGA_DITHERED_RUN:
     				runLength = ExtractRunLength(code, pbSrc, &advance);
     				pbSrc = pbSrc + advance;
    +				if (pbSrc >= pbEnd)
    +					return FALSE;
     				SRCREADPIXEL(pixelA, pbSrc);
     				SRCNEXTPIXEL(pbSrc);
    +				if (pbSrc >= pbEnd)
    +					return FALSE;
     				SRCREADPIXEL(pixelB, pbSrc);
     				SRCNEXTPIXEL(pbSrc);
     
    @@ -252,6 +258,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
     			case MEGA_MEGA_COLOR_RUN:
     				runLength = ExtractRunLength(code, pbSrc, &advance);
     				pbSrc = pbSrc + advance;
    +				if (pbSrc >= pbEnd)
    +					return FALSE;
     				SRCREADPIXEL(pixelA, pbSrc);
     				SRCNEXTPIXEL(pbSrc);
     
    @@ -272,6 +280,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
     				runLength = ExtractRunLength(code, pbSrc, &advance);
     				pbSrc = pbSrc + advance;
     
    +				if (pbSrc >= pbEnd)
    +					return FALSE;
     				if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
     				{
     					SRCREADPIXEL(fgPel, pbSrc);
    @@ -338,6 +348,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY
     					return FALSE;
     
     				UNROLL(runLength, {
    +					if (pbSrc >= pbEnd)
    +						return FALSE;
     					SRCREADPIXEL(temp, pbSrc);
     					SRCNEXTPIXEL(pbSrc);
     					DESTWRITEPIXEL(pbDest, temp);
    
  • libfreerdp/codec/interleaved.c+2 1 modified
    @@ -232,7 +232,8 @@ static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix)
     
     static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
     {
    -	*(UINT16*)_buf = _pix;
    +	_buf[0] = _pix & 0xFF;
    +	_buf[1] = (_pix >> 8) & 0xFF;
     }
     
     #undef DESTWRITEPIXEL
    
  • libfreerdp/common/assistance.c+76 0 modified
    @@ -361,6 +361,14 @@ static BOOL freerdp_assistance_parse_connection_string2(rdpAssistanceFile* file)
     			goto out_fail;
     		}
     
    +		if (p > q)
    +		{
    +			WLog_ERR(
    +			    TAG,
    +			    "Failed to parse ASSISTANCE file: ConnectionString2 invalid field order for KH");
    +			goto out_fail;
    +		}
    +
     		length = q - p;
     		free(file->RASpecificParams);
     		file->RASpecificParams = (char*)malloc(length + 1);
    @@ -388,6 +396,12 @@ static BOOL freerdp_assistance_parse_connection_string2(rdpAssistanceFile* file)
     			goto out_fail;
     		}
     
    +		if (p > q)
    +		{
    +			WLog_ERR(TAG, "Failed to parse ASSISTANCE file: ConnectionString2 invalid field "
    +			              "order for ID");
    +			return -1;
    +		}
     		length = q - p;
     		free(file->RASessionId);
     		file->RASessionId = (char*)malloc(length + 1);
    @@ -810,6 +824,13 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     				return -1;
     			}
     
    +			if (p > q)
    +			{
    +				WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field "
    +				              "order for USERNAME");
    +				return -1;
    +			}
    +
     			length = q - p;
     			file->Username = (char*)malloc(length + 1);
     
    @@ -834,6 +855,13 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     				return -1;
     			}
     
    +			if (p > q)
    +			{
    +				WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field "
    +				              "order for LHTICKET");
    +				return -1;
    +			}
    +
     			length = q - p;
     			file->LHTicket = (char*)malloc(length + 1);
     
    @@ -858,6 +886,13 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     				return -1;
     			}
     
    +			if (p > q)
    +			{
    +				WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field "
    +				              "order for RCTICKET");
    +				return -1;
    +			}
    +
     			length = q - p;
     			file->RCTicket = (char*)malloc(length + 1);
     
    @@ -882,6 +917,13 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     				return -1;
     			}
     
    +			if (p > q)
    +			{
    +				WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field "
    +				              "order for RCTICKETENCRYPTED");
    +				return -1;
    +			}
    +
     			length = q - p;
     
     			if ((length == 1) && (p[0] == '1'))
    @@ -902,6 +944,13 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     				return -1;
     			}
     
    +			if (p > q)
    +			{
    +				WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field "
    +				              "order for PassStub");
    +				return -1;
    +			}
    +
     			length = q - p;
     			file->PassStub = (char*)malloc(length + 1);
     
    @@ -926,6 +975,13 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     				return -1;
     			}
     
    +			if (p > q)
    +			{
    +				WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field "
    +				              "order for DtStart");
    +				return -1;
    +			}
    +
     			length = q - p;
     			r = (char*)malloc(length + 1);
     
    @@ -964,6 +1020,13 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     				return -1;
     			}
     
    +			if (p > q)
    +			{
    +				WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field "
    +				              "order for DtLength");
    +				return -1;
    +			}
    +
     			length = q - p;
     			r = (char*)malloc(length + 1);
     
    @@ -1002,6 +1065,13 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     				return -1;
     			}
     
    +			if (p > q)
    +			{
    +				WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field "
    +				              "order for L");
    +				return -1;
    +			}
    +
     			length = q - p;
     
     			if ((length == 1) && (p[0] == '1'))
    @@ -1061,6 +1131,12 @@ int freerdp_assistance_parse_file_buffer(rdpAssistanceFile* file, const char* bu
     			return -1;
     		}
     
    +		if (p > q)
    +		{
    +			WLog_ERR(TAG, "Failed to parse ASSISTANCE file: invalid field order for <E>");
    +			return -1;
    +		}
    +
     		q += sizeof("</E>") - 1;
     		length = q - p;
     		file->ConnectionString2 = (char*)malloc(length + 1);
    
  • libfreerdp/core/gateway/ntlm.c+3 3 modified
    @@ -160,7 +160,7 @@ BOOL ntlm_client_make_spn(rdpNtlm* ntlm, LPCTSTR ServiceClass, LPCTSTR hostname)
     		return TRUE;
     	}
     
    -	if (DsMakeSpn(ServiceClass, hostnameX, NULL, 0, NULL, &SpnLength, NULL) !=
    +	if (DsMakeSpn(ServiceClass, hostnameX, NULL, 0, hostnameX, &SpnLength, NULL) !=
     	    ERROR_BUFFER_OVERFLOW)
     		goto error;
     
    @@ -169,8 +169,8 @@ BOOL ntlm_client_make_spn(rdpNtlm* ntlm, LPCTSTR ServiceClass, LPCTSTR hostname)
     	if (!ntlm->ServicePrincipalName)
     		goto error;
     
    -	if (DsMakeSpn(ServiceClass, hostnameX, NULL, 0, NULL, &SpnLength, ntlm->ServicePrincipalName) !=
    -	    ERROR_SUCCESS)
    +	if (DsMakeSpn(ServiceClass, hostnameX, NULL, 0, hostnameX, &SpnLength,
    +	              ntlm->ServicePrincipalName) != ERROR_SUCCESS)
     		goto error;
     
     	status = TRUE;
    
  • libfreerdp/core/gateway/rdg.c+1 1 modified
    @@ -1167,7 +1167,7 @@ static BOOL rdg_tunnel_connect(rdpRdg* rdg)
     	return TRUE;
     }
     
    -BOOL rdg_connect(rdpRdg* rdg, int timeout, BOOL* rpcFallback)
    +BOOL rdg_connect(rdpRdg* rdg, DWORD timeout, BOOL* rpcFallback)
     {
     	BOOL status;
     	SOCKET outConnSocket = 0;
    
  • libfreerdp/core/gateway/rdg.h+1 1 modified
    @@ -44,7 +44,7 @@ FREERDP_LOCAL void rdg_free(rdpRdg* rdg);
     
     FREERDP_LOCAL BIO* rdg_get_front_bio_and_take_ownership(rdpRdg* rdg);
     
    -FREERDP_LOCAL BOOL rdg_connect(rdpRdg* rdg, int timeout, BOOL* rpcFallback);
    +FREERDP_LOCAL BOOL rdg_connect(rdpRdg* rdg, DWORD timeout, BOOL* rpcFallback);
     FREERDP_LOCAL DWORD rdg_get_event_handles(rdpRdg* rdg, HANDLE* events, DWORD count);
     
     #endif /* FREERDP_LIB_CORE_GATEWAY_RDG_H */
    
  • libfreerdp/core/gateway/rpc_bind.c+27 24 modified
    @@ -190,12 +190,13 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
     	if (!sbuffer)
     		goto fail;
     
    -	rpc_pdu_header_init(rpc, (rpcconn_hdr_t*)bind_pdu);
    -	bind_pdu->auth_length = (UINT16)sbuffer->cbBuffer;
    +	rpc_pdu_header_init(rpc, &bind_pdu->header);
    +	bind_pdu->header.auth_length = (UINT16)sbuffer->cbBuffer;
     	bind_pdu->auth_verifier.auth_value = sbuffer->pvBuffer;
    -	bind_pdu->ptype = PTYPE_BIND;
    -	bind_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_SUPPORT_HEADER_SIGN | PFC_CONC_MPX;
    -	bind_pdu->call_id = 2;
    +	bind_pdu->header.ptype = PTYPE_BIND;
    +	bind_pdu->header.pfc_flags =
    +	    PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_SUPPORT_HEADER_SIGN | PFC_CONC_MPX;
    +	bind_pdu->header.call_id = 2;
     	bind_pdu->max_xmit_frag = rpc->max_xmit_frag;
     	bind_pdu->max_recv_frag = rpc->max_recv_frag;
     	bind_pdu->assoc_group_id = 0;
    @@ -240,9 +241,9 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
     	bind_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
     	bind_pdu->auth_verifier.auth_reserved = 0x00;
     	bind_pdu->auth_verifier.auth_context_id = 0x00000000;
    -	offset += (8 + bind_pdu->auth_length);
    -	bind_pdu->frag_length = offset;
    -	buffer = (BYTE*)malloc(bind_pdu->frag_length);
    +	offset += (8 + bind_pdu->header.auth_length);
    +	bind_pdu->header.frag_length = offset;
    +	buffer = (BYTE*)malloc(bind_pdu->header.frag_length);
     
     	if (!buffer)
     		goto fail;
    @@ -256,10 +257,11 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
     	offset = 116;
     	rpc_offset_pad(&offset, bind_pdu->auth_verifier.auth_pad_length);
     	CopyMemory(&buffer[offset], &bind_pdu->auth_verifier.auth_type, 8);
    -	CopyMemory(&buffer[offset + 8], bind_pdu->auth_verifier.auth_value, bind_pdu->auth_length);
    -	offset += (8 + bind_pdu->auth_length);
    -	length = bind_pdu->frag_length;
    -	clientCall = rpc_client_call_new(bind_pdu->call_id, 0);
    +	CopyMemory(&buffer[offset + 8], bind_pdu->auth_verifier.auth_value,
    +	           bind_pdu->header.auth_length);
    +	offset += (8 + bind_pdu->header.auth_length);
    +	length = bind_pdu->header.frag_length;
    +	clientCall = rpc_client_call_new(bind_pdu->header.call_id, 0);
     
     	if (!clientCall)
     		goto fail;
    @@ -374,12 +376,12 @@ int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
     		return -1;
     	}
     
    -	rpc_pdu_header_init(rpc, (rpcconn_hdr_t*)auth_3_pdu);
    -	auth_3_pdu->auth_length = (UINT16)sbuffer->cbBuffer;
    +	rpc_pdu_header_init(rpc, &auth_3_pdu->header);
    +	auth_3_pdu->header.auth_length = (UINT16)sbuffer->cbBuffer;
     	auth_3_pdu->auth_verifier.auth_value = sbuffer->pvBuffer;
    -	auth_3_pdu->ptype = PTYPE_RPC_AUTH_3;
    -	auth_3_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
    -	auth_3_pdu->call_id = 2;
    +	auth_3_pdu->header.ptype = PTYPE_RPC_AUTH_3;
    +	auth_3_pdu->header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
    +	auth_3_pdu->header.call_id = 2;
     	auth_3_pdu->max_xmit_frag = rpc->max_xmit_frag;
     	auth_3_pdu->max_recv_frag = rpc->max_recv_frag;
     	offset = 20;
    @@ -388,9 +390,9 @@ int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
     	auth_3_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
     	auth_3_pdu->auth_verifier.auth_reserved = 0x00;
     	auth_3_pdu->auth_verifier.auth_context_id = 0x00000000;
    -	offset += (8 + auth_3_pdu->auth_length);
    -	auth_3_pdu->frag_length = offset;
    -	buffer = (BYTE*)malloc(auth_3_pdu->frag_length);
    +	offset += (8 + auth_3_pdu->header.auth_length);
    +	auth_3_pdu->header.frag_length = offset;
    +	buffer = (BYTE*)malloc(auth_3_pdu->header.frag_length);
     
     	if (!buffer)
     	{
    @@ -402,10 +404,11 @@ int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
     	offset = 20;
     	rpc_offset_pad(&offset, auth_3_pdu->auth_verifier.auth_pad_length);
     	CopyMemory(&buffer[offset], &auth_3_pdu->auth_verifier.auth_type, 8);
    -	CopyMemory(&buffer[offset + 8], auth_3_pdu->auth_verifier.auth_value, auth_3_pdu->auth_length);
    -	offset += (8 + auth_3_pdu->auth_length);
    -	length = auth_3_pdu->frag_length;
    -	clientCall = rpc_client_call_new(auth_3_pdu->call_id, 0);
    +	CopyMemory(&buffer[offset + 8], auth_3_pdu->auth_verifier.auth_value,
    +	           auth_3_pdu->header.auth_length);
    +	offset += (8 + auth_3_pdu->header.auth_length);
    +	length = auth_3_pdu->header.frag_length;
    +	clientCall = rpc_client_call_new(auth_3_pdu->header.call_id, 0);
     
     	if (ArrayList_Add(rpc->client->ClientCallList, clientCall) >= 0)
     	{
    
  • libfreerdp/core/gateway/rpc.c+7 7 modified
    @@ -139,14 +139,14 @@ void rpc_pdu_header_print(rpcconn_hdr_t* header)
     	}
     }
     
    -void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_hdr_t* header)
    +void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_common_hdr_t* header)
     {
    -	header->common.rpc_vers = rpc->rpc_vers;
    -	header->common.rpc_vers_minor = rpc->rpc_vers_minor;
    -	header->common.packed_drep[0] = rpc->packed_drep[0];
    -	header->common.packed_drep[1] = rpc->packed_drep[1];
    -	header->common.packed_drep[2] = rpc->packed_drep[2];
    -	header->common.packed_drep[3] = rpc->packed_drep[3];
    +	header->rpc_vers = rpc->rpc_vers;
    +	header->rpc_vers_minor = rpc->rpc_vers_minor;
    +	header->packed_drep[0] = rpc->packed_drep[0];
    +	header->packed_drep[1] = rpc->packed_drep[1];
    +	header->packed_drep[2] = rpc->packed_drep[2];
    +	header->packed_drep[3] = rpc->packed_drep[3];
     }
     
     UINT32 rpc_offset_align(UINT32* offset, UINT32 alignment)
    
  • libfreerdp/core/gateway/rpc_client.c+27 33 modified
    @@ -895,7 +895,7 @@ BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
     	SecBufferDesc Message;
     	RpcClientCall* clientCall = NULL;
     	rdpNtlm* ntlm;
    -	rpcconn_request_hdr_t* request_pdu = NULL;
    +	rpcconn_request_hdr_t request_pdu = { 0 };
     	RpcVirtualConnection* connection;
     	RpcInChannel* inChannel;
     	size_t length;
    @@ -931,25 +931,20 @@ BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
     	if (ntlm_client_query_auth_size(ntlm) < 0)
     		goto fail;
     
    -	request_pdu = (rpcconn_request_hdr_t*)calloc(1, sizeof(rpcconn_request_hdr_t));
    -
    -	if (!request_pdu)
    -		goto fail;
    -
     	size = ntlm_client_get_context_max_size(ntlm);
     
     	if (size < 0)
     		goto fail;
     
    -	rpc_pdu_header_init(rpc, (rpcconn_hdr_t*)request_pdu);
    -	request_pdu->ptype = PTYPE_REQUEST;
    -	request_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
    -	request_pdu->auth_length = (UINT16)size;
    -	request_pdu->call_id = rpc->CallId++;
    -	request_pdu->alloc_hint = length;
    -	request_pdu->p_cont_id = 0x0000;
    -	request_pdu->opnum = opnum;
    -	clientCall = rpc_client_call_new(request_pdu->call_id, request_pdu->opnum);
    +	rpc_pdu_header_init(rpc, &request_pdu.header);
    +	request_pdu.header.ptype = PTYPE_REQUEST;
    +	request_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
    +	request_pdu.header.auth_length = (UINT16)size;
    +	request_pdu.header.call_id = rpc->CallId++;
    +	request_pdu.alloc_hint = length;
    +	request_pdu.p_cont_id = 0x0000;
    +	request_pdu.opnum = opnum;
    +	clientCall = rpc_client_call_new(request_pdu.header.call_id, request_pdu.opnum);
     
     	if (!clientCall)
     		goto fail;
    @@ -960,34 +955,34 @@ BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
     		goto fail;
     	}
     
    -	if (request_pdu->opnum == TsProxySetupReceivePipeOpnum)
    -		rpc->PipeCallId = request_pdu->call_id;
    +	if (request_pdu.opnum == TsProxySetupReceivePipeOpnum)
    +		rpc->PipeCallId = request_pdu.header.call_id;
     
    -	request_pdu->stub_data = Stream_Buffer(s);
    +	request_pdu.stub_data = Stream_Buffer(s);
     	offset = 24;
     	stub_data_pad = rpc_offset_align(&offset, 8);
     	offset += length;
    -	request_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);
    -	request_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
    -	request_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
    -	request_pdu->auth_verifier.auth_reserved = 0x00;
    -	request_pdu->auth_verifier.auth_context_id = 0x00000000;
    -	offset += (8 + request_pdu->auth_length);
    -	request_pdu->frag_length = offset;
    -	buffer = (BYTE*)calloc(1, request_pdu->frag_length);
    +	request_pdu.auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);
    +	request_pdu.auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
    +	request_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
    +	request_pdu.auth_verifier.auth_reserved = 0x00;
    +	request_pdu.auth_verifier.auth_context_id = 0x00000000;
    +	offset += (8 + request_pdu.header.auth_length);
    +	request_pdu.header.frag_length = offset;
    +	buffer = (BYTE*)calloc(1, request_pdu.header.frag_length);
     
     	if (!buffer)
     		goto fail;
     
    -	CopyMemory(buffer, request_pdu, 24);
    +	CopyMemory(buffer, &request_pdu, 24);
     	offset = 24;
     	rpc_offset_pad(&offset, stub_data_pad);
    -	CopyMemory(&buffer[offset], request_pdu->stub_data, length);
    +	CopyMemory(&buffer[offset], request_pdu.stub_data, length);
     	offset += length;
    -	rpc_offset_pad(&offset, request_pdu->auth_verifier.auth_pad_length);
    -	CopyMemory(&buffer[offset], &request_pdu->auth_verifier.auth_type, 8);
    +	rpc_offset_pad(&offset, request_pdu.auth_verifier.auth_pad_length);
    +	CopyMemory(&buffer[offset], &request_pdu.auth_verifier.auth_type, 8);
     	offset += 8;
    -	Buffers[0].BufferType = SECBUFFER_DATA;  /* auth_data */
    +	Buffers[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY; /* auth_data */
     	Buffers[1].BufferType = SECBUFFER_TOKEN; /* signature */
     	Buffers[0].pvBuffer = buffer;
     	Buffers[0].cbBuffer = offset;
    @@ -1007,14 +1002,13 @@ BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum)
     	CopyMemory(&buffer[offset], Buffers[1].pvBuffer, Buffers[1].cbBuffer);
     	offset += Buffers[1].cbBuffer;
     
    -	if (rpc_in_channel_send_pdu(inChannel, buffer, request_pdu->frag_length) < 0)
    +	if (rpc_in_channel_send_pdu(inChannel, buffer, request_pdu.header.frag_length) < 0)
     		goto fail;
     
     	rc = TRUE;
     fail:
     	free(buffer);
     	free(Buffers[1].pvBuffer);
    -	free(request_pdu);
     	Stream_Free(s, TRUE);
     	return rc;
     }
    
  • libfreerdp/core/gateway/rpc.h+27 30 modified
    @@ -34,21 +34,23 @@ typedef struct rdp_rpc rdpRpc;
     
     #pragma pack(push, 1)
     
    -#define DEFINE_RPC_COMMON_FIELDS() \
    -	BYTE rpc_vers;                 \
    -	BYTE rpc_vers_minor;           \
    -	BYTE ptype;                    \
    -	BYTE pfc_flags;                \
    -	BYTE packed_drep[4];           \
    -	UINT16 frag_length;            \
    -	UINT16 auth_length;            \
    -	UINT32 call_id
    -
    -#define RPC_COMMON_FIELDS_LENGTH 16
    +typedef struct
    +{
    +	BYTE rpc_vers;
    +	BYTE rpc_vers_minor;
    +	BYTE ptype;
    +	BYTE pfc_flags;
    +	BYTE packed_drep[4];
    +	UINT16 frag_length;
    +	UINT16 auth_length;
    +	UINT32 call_id;
    +} rpcconn_common_hdr_t;
    +
    +#define RPC_COMMON_FIELDS_LENGTH sizeof(rpcconn_common_hdr_t)
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT16 Flags;
     	UINT16 NumberOfCommands;
    @@ -141,11 +143,6 @@ typedef struct _RPC_PDU
     
     #pragma pack(push, 1)
     
    -typedef struct
    -{
    -	DEFINE_RPC_COMMON_FIELDS();
    -} rpcconn_common_hdr_t;
    -
     typedef UINT16 p_context_id_t;
     typedef UINT16 p_reject_reason_t;
     
    @@ -314,7 +311,7 @@ typedef struct auth_verifier_co_s auth_verifier_co_t;
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT16 max_xmit_frag;
     	UINT16 max_recv_frag;
    @@ -328,7 +325,7 @@ typedef struct
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT16 max_xmit_frag;
     	UINT16 max_recv_frag;
    @@ -345,7 +342,7 @@ typedef struct
     /*  bind header */
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT16 max_xmit_frag;
     	UINT16 max_recv_frag;
    @@ -358,7 +355,7 @@ typedef struct
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT16 max_xmit_frag;
     	UINT16 max_recv_frag;
    @@ -375,7 +372,7 @@ typedef struct
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT16 max_xmit_frag;
     	UINT16 max_recv_frag;
    @@ -385,7 +382,7 @@ typedef struct
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	p_reject_reason_t provider_reject_reason;
     
    @@ -394,7 +391,7 @@ typedef struct
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	auth_verifier_co_t auth_verifier;
     
    @@ -460,7 +457,7 @@ typedef struct _RPC_FAULT_CODE RPC_FAULT_CODE;
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT32 alloc_hint;
     	p_context_id_t p_cont_id;
    @@ -479,14 +476,14 @@ typedef struct
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	auth_verifier_co_t auth_verifier;
     } rpcconn_orphaned_hdr_t;
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT32 alloc_hint;
     
    @@ -505,7 +502,7 @@ typedef struct
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     
     	UINT32 alloc_hint;
     	p_context_id_t p_cont_id;
    @@ -522,7 +519,7 @@ typedef struct
     
     typedef struct
     {
    -	DEFINE_RPC_COMMON_FIELDS();
    +	rpcconn_common_hdr_t header;
     } rpcconn_shutdown_hdr_t;
     
     typedef union {
    @@ -768,7 +765,7 @@ struct rdp_rpc
     };
     
     FREERDP_LOCAL void rpc_pdu_header_print(rpcconn_hdr_t* header);
    -FREERDP_LOCAL void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_hdr_t* header);
    +FREERDP_LOCAL void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_common_hdr_t* header);
     
     FREERDP_LOCAL UINT32 rpc_offset_align(UINT32* offset, UINT32 alignment);
     FREERDP_LOCAL UINT32 rpc_offset_pad(UINT32* offset, UINT32 pad);
    
  • libfreerdp/core/gateway/rts.c+54 52 modified
    @@ -67,19 +67,21 @@
      *
      */
     
    -static void rts_pdu_header_init(rpcconn_rts_hdr_t* header)
    +static rpcconn_rts_hdr_t rts_pdu_header_init(void)
     {
    -	ZeroMemory(header, sizeof(*header));
    -	header->rpc_vers = 5;
    -	header->rpc_vers_minor = 0;
    -	header->ptype = PTYPE_RTS;
    -	header->packed_drep[0] = 0x10;
    -	header->packed_drep[1] = 0x00;
    -	header->packed_drep[2] = 0x00;
    -	header->packed_drep[3] = 0x00;
    -	header->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
    -	header->auth_length = 0;
    -	header->call_id = 0;
    +	rpcconn_rts_hdr_t header = { 0 };
    +	header.header.rpc_vers = 5;
    +	header.header.rpc_vers_minor = 0;
    +	header.header.ptype = PTYPE_RTS;
    +	header.header.packed_drep[0] = 0x10;
    +	header.header.packed_drep[1] = 0x00;
    +	header.header.packed_drep[2] = 0x00;
    +	header.header.packed_drep[3] = 0x00;
    +	header.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
    +	header.header.auth_length = 0;
    +	header.header.call_id = 0;
    +
    +	return header;
     }
     
     static int rts_receive_window_size_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length,
    @@ -406,21 +408,21 @@ int rts_send_CONN_A1_pdu(rdpRpc* rpc)
     {
     	int status;
     	BYTE* buffer;
    -	rpcconn_rts_hdr_t header;
    +	rpcconn_rts_hdr_t header = rts_pdu_header_init();
     	UINT32 ReceiveWindowSize;
     	BYTE* OUTChannelCookie;
     	BYTE* VirtualConnectionCookie;
     	RpcVirtualConnection* connection = rpc->VirtualConnection;
     	RpcOutChannel* outChannel = connection->DefaultOutChannel;
    -	rts_pdu_header_init(&header);
    -	header.frag_length = 76;
    +
    +	header.header.frag_length = 76;
     	header.Flags = RTS_FLAG_NONE;
     	header.NumberOfCommands = 4;
     	WLog_DBG(TAG, "Sending CONN/A1 RTS PDU");
     	VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
     	OUTChannelCookie = (BYTE*)&(outChannel->common.Cookie);
     	ReceiveWindowSize = outChannel->ReceiveWindow;
    -	buffer = (BYTE*)malloc(header.frag_length);
    +	buffer = (BYTE*)malloc(header.header.frag_length);
     
     	if (!buffer)
     		return -1;
    @@ -432,7 +434,7 @@ int rts_send_CONN_A1_pdu(rdpRpc* rpc)
     	rts_cookie_command_write(&buffer[48], OUTChannelCookie); /* OUTChannelCookie (20 bytes) */
     	rts_receive_window_size_command_write(&buffer[68],
     	                                      ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */
    -	status = rpc_channel_write(&outChannel->common, buffer, header.frag_length);
    +	status = rpc_channel_write(&outChannel->common, buffer, header.header.frag_length);
     	free(buffer);
     	return (status > 0) ? 1 : -1;
     }
    @@ -453,21 +455,21 @@ int rts_send_CONN_B1_pdu(rdpRpc* rpc)
     	int status;
     	BYTE* buffer;
     	UINT32 length;
    -	rpcconn_rts_hdr_t header;
    +	rpcconn_rts_hdr_t header = rts_pdu_header_init();
     	BYTE* INChannelCookie;
     	BYTE* AssociationGroupId;
     	BYTE* VirtualConnectionCookie;
     	RpcVirtualConnection* connection = rpc->VirtualConnection;
     	RpcInChannel* inChannel = connection->DefaultInChannel;
    -	rts_pdu_header_init(&header);
    -	header.frag_length = 104;
    +
    +	header.header.frag_length = 104;
     	header.Flags = RTS_FLAG_NONE;
     	header.NumberOfCommands = 6;
     	WLog_DBG(TAG, "Sending CONN/B1 RTS PDU");
     	VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
     	INChannelCookie = (BYTE*)&(inChannel->common.Cookie);
     	AssociationGroupId = (BYTE*)&(connection->AssociationGroupId);
    -	buffer = (BYTE*)malloc(header.frag_length);
    +	buffer = (BYTE*)malloc(header.header.frag_length);
     
     	if (!buffer)
     		return -1;
    @@ -483,7 +485,7 @@ int rts_send_CONN_B1_pdu(rdpRpc* rpc)
     	                                   rpc->KeepAliveInterval); /* ClientKeepalive (8 bytes) */
     	rts_association_group_id_command_write(&buffer[84],
     	                                       AssociationGroupId); /* AssociationGroupId (20 bytes) */
    -	length = header.frag_length;
    +	length = header.header.frag_length;
     	status = rpc_channel_write(&inChannel->common, buffer, length);
     	free(buffer);
     	return (status > 0) ? 1 : -1;
    @@ -520,22 +522,22 @@ static int rts_send_keep_alive_pdu(rdpRpc* rpc)
     	int status;
     	BYTE* buffer;
     	UINT32 length;
    -	rpcconn_rts_hdr_t header;
    +	rpcconn_rts_hdr_t header = rts_pdu_header_init();
     	RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel;
    -	rts_pdu_header_init(&header);
    -	header.frag_length = 28;
    +
    +	header.header.frag_length = 28;
     	header.Flags = RTS_FLAG_OTHER_CMD;
     	header.NumberOfCommands = 1;
     	WLog_DBG(TAG, "Sending Keep-Alive RTS PDU");
    -	buffer = (BYTE*)malloc(header.frag_length);
    +	buffer = (BYTE*)malloc(header.header.frag_length);
     
     	if (!buffer)
     		return -1;
     
     	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
     	rts_client_keepalive_command_write(
     	    &buffer[20], rpc->CurrentKeepAliveInterval); /* ClientKeepAlive (8 bytes) */
    -	length = header.frag_length;
    +	length = header.header.frag_length;
     	status = rpc_channel_write(&inChannel->common, buffer, length);
     	free(buffer);
     	return (status > 0) ? 1 : -1;
    @@ -546,23 +548,23 @@ int rts_send_flow_control_ack_pdu(rdpRpc* rpc)
     	int status;
     	BYTE* buffer;
     	UINT32 length;
    -	rpcconn_rts_hdr_t header;
    +	rpcconn_rts_hdr_t header = rts_pdu_header_init();
     	UINT32 BytesReceived;
     	UINT32 AvailableWindow;
     	BYTE* ChannelCookie;
     	RpcVirtualConnection* connection = rpc->VirtualConnection;
     	RpcInChannel* inChannel = connection->DefaultInChannel;
     	RpcOutChannel* outChannel = connection->DefaultOutChannel;
    -	rts_pdu_header_init(&header);
    -	header.frag_length = 56;
    +
    +	header.header.frag_length = 56;
     	header.Flags = RTS_FLAG_OTHER_CMD;
     	header.NumberOfCommands = 2;
     	WLog_DBG(TAG, "Sending FlowControlAck RTS PDU");
     	BytesReceived = outChannel->BytesReceived;
     	AvailableWindow = outChannel->AvailableWindowAdvertised;
     	ChannelCookie = (BYTE*)&(outChannel->common.Cookie);
     	outChannel->ReceiverAvailableWindow = outChannel->AvailableWindowAdvertised;
    -	buffer = (BYTE*)malloc(header.frag_length);
    +	buffer = (BYTE*)malloc(header.header.frag_length);
     
     	if (!buffer)
     		return -1;
    @@ -571,7 +573,7 @@ int rts_send_flow_control_ack_pdu(rdpRpc* rpc)
     	rts_destination_command_write(&buffer[20], FDOutProxy); /* Destination Command (8 bytes) */
     	/* FlowControlAck Command (28 bytes) */
     	rts_flow_control_ack_command_write(&buffer[28], BytesReceived, AvailableWindow, ChannelCookie);
    -	length = header.frag_length;
    +	length = header.header.frag_length;
     	status = rpc_channel_write(&inChannel->common, buffer, length);
     	free(buffer);
     	return (status > 0) ? 1 : -1;
    @@ -640,20 +642,20 @@ static int rts_send_ping_pdu(rdpRpc* rpc)
     	int status;
     	BYTE* buffer;
     	UINT32 length;
    -	rpcconn_rts_hdr_t header;
    +	rpcconn_rts_hdr_t header = rts_pdu_header_init();
     	RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel;
    -	rts_pdu_header_init(&header);
    -	header.frag_length = 20;
    +
    +	header.header.frag_length = 20;
     	header.Flags = RTS_FLAG_PING;
     	header.NumberOfCommands = 0;
     	WLog_DBG(TAG, "Sending Ping RTS PDU");
    -	buffer = (BYTE*)malloc(header.frag_length);
    +	buffer = (BYTE*)malloc(header.header.frag_length);
     
     	if (!buffer)
     		return -1;
     
     	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
    -	length = header.frag_length;
    +	length = header.header.frag_length;
     	status = rpc_channel_write(&inChannel->common, buffer, length);
     	free(buffer);
     	return (status > 0) ? 1 : -1;
    @@ -737,17 +739,17 @@ static int rts_send_OUT_R2_A7_pdu(rdpRpc* rpc)
     {
     	int status;
     	BYTE* buffer;
    -	rpcconn_rts_hdr_t header;
    +	rpcconn_rts_hdr_t header = rts_pdu_header_init();
     	BYTE* SuccessorChannelCookie;
     	RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel;
     	RpcOutChannel* nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
    -	rts_pdu_header_init(&header);
    -	header.frag_length = 56;
    +
    +	header.header.frag_length = 56;
     	header.Flags = RTS_FLAG_OUT_CHANNEL;
     	header.NumberOfCommands = 3;
     	WLog_DBG(TAG, "Sending OUT_R2/A7 RTS PDU");
     	SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie);
    -	buffer = (BYTE*)malloc(header.frag_length);
    +	buffer = (BYTE*)malloc(header.header.frag_length);
     
     	if (!buffer)
     		return -1;
    @@ -757,7 +759,7 @@ static int rts_send_OUT_R2_A7_pdu(rdpRpc* rpc)
     	rts_cookie_command_write(&buffer[28],
     	                         SuccessorChannelCookie); /* SuccessorChannelCookie (20 bytes) */
     	rts_version_command_write(&buffer[48]);           /* Version (8 bytes) */
    -	status = rpc_channel_write(&inChannel->common, buffer, header.frag_length);
    +	status = rpc_channel_write(&inChannel->common, buffer, header.header.frag_length);
     	free(buffer);
     	return (status > 0) ? 1 : -1;
     }
    @@ -766,21 +768,21 @@ static int rts_send_OUT_R2_C1_pdu(rdpRpc* rpc)
     {
     	int status;
     	BYTE* buffer;
    -	rpcconn_rts_hdr_t header;
    +	rpcconn_rts_hdr_t header = rts_pdu_header_init();
     	RpcOutChannel* nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
    -	rts_pdu_header_init(&header);
    -	header.frag_length = 24;
    +
    +	header.header.frag_length = 24;
     	header.Flags = RTS_FLAG_PING;
     	header.NumberOfCommands = 1;
     	WLog_DBG(TAG, "Sending OUT_R2/C1 RTS PDU");
    -	buffer = (BYTE*)malloc(header.frag_length);
    +	buffer = (BYTE*)malloc(header.header.frag_length);
     
     	if (!buffer)
     		return -1;
     
     	CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */
     	rts_empty_command_write(&buffer[20]);     /* Empty command (4 bytes) */
    -	status = rpc_channel_write(&nextOutChannel->common, buffer, header.frag_length);
    +	status = rpc_channel_write(&nextOutChannel->common, buffer, header.header.frag_length);
     	free(buffer);
     	return (status > 0) ? 1 : -1;
     }
    @@ -789,24 +791,24 @@ int rts_send_OUT_R1_A3_pdu(rdpRpc* rpc)
     {
     	int status;
     	BYTE* buffer;
    -	rpcconn_rts_hdr_t header;
    +	rpcconn_rts_hdr_t header = rts_pdu_header_init();
     	UINT32 ReceiveWindowSize;
     	BYTE* VirtualConnectionCookie;
     	BYTE* PredecessorChannelCookie;
     	BYTE* SuccessorChannelCookie;
     	RpcVirtualConnection* connection = rpc->VirtualConnection;
     	RpcOutChannel* outChannel = connection->DefaultOutChannel;
     	RpcOutChannel* nextOutChannel = connection->NonDefaultOutChannel;
    -	rts_pdu_header_init(&header);
    -	header.frag_length = 96;
    +
    +	header.header.frag_length = 96;
     	header.Flags = RTS_FLAG_RECYCLE_CHANNEL;
     	header.NumberOfCommands = 5;
     	WLog_DBG(TAG, "Sending OUT_R1/A3 RTS PDU");
     	VirtualConnectionCookie = (BYTE*)&(connection->Cookie);
     	PredecessorChannelCookie = (BYTE*)&(outChannel->common.Cookie);
     	SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie);
     	ReceiveWindowSize = outChannel->ReceiveWindow;
    -	buffer = (BYTE*)malloc(header.frag_length);
    +	buffer = (BYTE*)malloc(header.header.frag_length);
     
     	if (!buffer)
     		return -1;
    @@ -821,7 +823,7 @@ int rts_send_OUT_R1_A3_pdu(rdpRpc* rpc)
     	                         SuccessorChannelCookie); /* SuccessorChannelCookie (20 bytes) */
     	rts_receive_window_size_command_write(&buffer[88],
     	                                      ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */
    -	status = rpc_channel_write(&nextOutChannel->common, buffer, header.frag_length);
    +	status = rpc_channel_write(&nextOutChannel->common, buffer, header.header.frag_length);
     	free(buffer);
     	return (status > 0) ? 1 : -1;
     }
    
  • libfreerdp/core/gateway/rts_signature.c+4 4 modified
    @@ -302,7 +302,7 @@ BOOL rts_match_pdu_signature(const RtsPduSignature* signature, const rpcconn_rts
     
     	buffer = (const BYTE*)rts;
     	offset = RTS_PDU_HEADER_LENGTH;
    -	length = rts->frag_length - offset;
    +	length = rts->header.frag_length - offset;
     
     	for (i = 0; i < rts->NumberOfCommands; i++)
     	{
    @@ -319,7 +319,7 @@ BOOL rts_match_pdu_signature(const RtsPduSignature* signature, const rpcconn_rts
     
     		CommandLength = (UINT32)status;
     		offset += CommandLength;
    -		length = rts->frag_length - offset;
    +		length = rts->header.frag_length - offset;
     	}
     
     	return TRUE;
    @@ -342,7 +342,7 @@ BOOL rts_extract_pdu_signature(RtsPduSignature* signature, const rpcconn_rts_hdr
     	signature->NumberOfCommands = rts->NumberOfCommands;
     	buffer = (BYTE*)rts;
     	offset = RTS_PDU_HEADER_LENGTH;
    -	length = rts->frag_length - offset;
    +	length = rts->header.frag_length - offset;
     
     	for (i = 0; i < rts->NumberOfCommands; i++)
     	{
    @@ -356,7 +356,7 @@ BOOL rts_extract_pdu_signature(RtsPduSignature* signature, const rpcconn_rts_hdr
     
     		CommandLength = (UINT32)status;
     		offset += CommandLength;
    -		length = rts->frag_length - offset;
    +		length = rts->header.frag_length - offset;
     	}
     
     	return TRUE;
    
  • libfreerdp/core/gateway/tsg.c+249 46 modified
    @@ -39,6 +39,19 @@
     
     #define TAG FREERDP_TAG("core.gateway.tsg")
     
    +#define TSG_PACKET_TYPE_HEADER 0x00004844
    +#define TSG_PACKET_TYPE_VERSIONCAPS 0x00005643
    +#define TSG_PACKET_TYPE_QUARCONFIGREQUEST 0x00005143
    +#define TSG_PACKET_TYPE_QUARREQUEST 0x00005152
    +#define TSG_PACKET_TYPE_RESPONSE 0x00005052
    +#define TSG_PACKET_TYPE_QUARENC_RESPONSE 0x00004552
    +#define TSG_CAPABILITY_TYPE_NAP 0x00000001
    +#define TSG_PACKET_TYPE_CAPS_RESPONSE 0x00004350
    +#define TSG_PACKET_TYPE_MSGREQUEST_PACKET 0x00004752
    +#define TSG_PACKET_TYPE_MESSAGE_PACKET 0x00004750
    +#define TSG_PACKET_TYPE_AUTH 0x00004054
    +#define TSG_PACKET_TYPE_REAUTH 0x00005250
    +
     typedef WCHAR* RESOURCENAME;
     
     typedef struct _tsendpointinfo
    @@ -218,6 +231,214 @@ struct rdp_tsg
     	TSG_PACKET_VERSIONCAPS packetVersionCaps;
     };
     
    +static const char* tsg_packet_id_to_string(UINT32 packetId)
    +{
    +	switch (packetId)
    +	{
    +		case TSG_PACKET_TYPE_HEADER:
    +			return "TSG_PACKET_TYPE_HEADER";
    +		case TSG_PACKET_TYPE_VERSIONCAPS:
    +			return "TSG_PACKET_TYPE_VERSIONCAPS";
    +		case TSG_PACKET_TYPE_QUARCONFIGREQUEST:
    +			return "TSG_PACKET_TYPE_QUARCONFIGREQUEST";
    +		case TSG_PACKET_TYPE_QUARREQUEST:
    +			return "TSG_PACKET_TYPE_QUARREQUEST";
    +		case TSG_PACKET_TYPE_RESPONSE:
    +			return "TSG_PACKET_TYPE_RESPONSE";
    +		case TSG_PACKET_TYPE_QUARENC_RESPONSE:
    +			return "TSG_PACKET_TYPE_QUARENC_RESPONSE";
    +		case TSG_CAPABILITY_TYPE_NAP:
    +			return "TSG_CAPABILITY_TYPE_NAP";
    +		case TSG_PACKET_TYPE_CAPS_RESPONSE:
    +			return "TSG_PACKET_TYPE_CAPS_RESPONSE";
    +		case TSG_PACKET_TYPE_MSGREQUEST_PACKET:
    +			return "TSG_PACKET_TYPE_MSGREQUEST_PACKET";
    +		case TSG_PACKET_TYPE_MESSAGE_PACKET:
    +			return "TSG_PACKET_TYPE_MESSAGE_PACKET";
    +		case TSG_PACKET_TYPE_AUTH:
    +			return "TSG_PACKET_TYPE_AUTH";
    +		case TSG_PACKET_TYPE_REAUTH:
    +			return "TSG_PACKET_TYPE_REAUTH";
    +		default:
    +			return "UNKNOWN";
    +	}
    +}
    +
    +static const char* tsg_state_to_string(TSG_STATE state)
    +{
    +	switch (state)
    +	{
    +		case TSG_STATE_INITIAL:
    +			return "TSG_STATE_INITIAL";
    +		case TSG_STATE_CONNECTED:
    +			return "TSG_STATE_CONNECTED";
    +		case TSG_STATE_AUTHORIZED:
    +			return "TSG_STATE_AUTHORIZED";
    +		case TSG_STATE_CHANNEL_CREATED:
    +			return "TSG_STATE_CHANNEL_CREATED";
    +		case TSG_STATE_PIPE_CREATED:
    +			return "TSG_STATE_PIPE_CREATED";
    +		case TSG_STATE_TUNNEL_CLOSE_PENDING:
    +			return "TSG_STATE_TUNNEL_CLOSE_PENDING";
    +		case TSG_STATE_CHANNEL_CLOSE_PENDING:
    +			return "TSG_STATE_CHANNEL_CLOSE_PENDING";
    +		case TSG_STATE_FINAL:
    +			return "TSG_STATE_FINAL";
    +		default:
    +			return "TSG_STATE_UNKNOWN";
    +	}
    +}
    +
    +static BOOL tsg_print(char** buffer, size_t* len, const char* fmt, ...)
    +{
    +	int rc;
    +	va_list ap;
    +	if (!buffer || !len || !fmt)
    +		return FALSE;
    +	va_start(ap, fmt);
    +	rc = vsnprintf(*buffer, *len, fmt, ap);
    +	va_end(ap);
    +	if ((rc < 0) || ((size_t)rc > *len))
    +		return FALSE;
    +	*len -= (size_t)rc;
    +	*buffer += (size_t)rc;
    +	return TRUE;
    +}
    +
    +static BOOL tsg_packet_header_to_string(char** buffer, size_t* length,
    +                                        const TSG_PACKET_HEADER* header)
    +{
    +	return tsg_print(buffer, length,
    +	                 "header { ComponentId=0x%04" PRIx16 ", PacketId=0x%04" PRIx16 " }",
    +	                 header->ComponentId, header->PacketId);
    +}
    +
    +static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length,
    +                                              const TSG_PACKET_CAPABILITIES* caps, UINT32 numCaps)
    +{
    +	UINT32 x;
    +
    +	if (!tsg_print(buffer, length, "capabilities { "))
    +		return FALSE;
    +
    +	for (x = 0; x < numCaps; x++)
    +	{
    +		const TSG_PACKET_CAPABILITIES* cur = &caps[x];
    +		switch (cur->capabilityType)
    +		{
    +			case TSG_CAPABILITY_TYPE_NAP:
    +				if (!tsg_print(buffer, length, "%s { capabilities=0x%08" PRIx32 " }",
    +				               tsg_packet_id_to_string(cur->capabilityType),
    +				               cur->tsgPacket.tsgCapNap.capabilities))
    +					return FALSE;
    +				break;
    +			default:
    +				if (!tsg_print(buffer, length, "TSG_UNKNOWN_CAPABILITY"))
    +					return FALSE;
    +				break;
    +		}
    +	}
    +	return tsg_print(buffer, length, " }");
    +}
    +
    +static BOOL tsg_packet_versioncaps_to_string(char** buffer, size_t* length,
    +                                             const TSG_PACKET_VERSIONCAPS* caps)
    +{
    +	if (!tsg_print(buffer, length, "versioncaps { "))
    +		return FALSE;
    +	if (!tsg_packet_header_to_string(buffer, length, &caps->tsgHeader))
    +		return FALSE;
    +
    +	if (!tsg_print(buffer, length, " "))
    +		return FALSE;
    +
    +	if (!tsg_packet_capabilities_to_string(buffer, length, caps->tsgCaps, caps->numCapabilities))
    +		return FALSE;
    +
    +	if (!tsg_print(buffer, length,
    +	               " numCapabilities=0x%08" PRIx32 ", majorVersion=0x%04" PRIx16
    +	               ", minorVersion=0x%04" PRIx16 ", quarantineCapabilities=0x%04" PRIx16,
    +	               caps->numCapabilities, caps->majorVersion, caps->minorVersion,
    +	               caps->quarantineCapabilities))
    +		return FALSE;
    +
    +	return tsg_print(buffer, length, " }");
    +}
    +
    +static const char* tsg_packet_to_string(const TSG_PACKET* packet)
    +{
    +	size_t len = 8192;
    +	static char sbuffer[8193] = { 0 };
    +	char* buffer = sbuffer;
    +
    +	if (!tsg_print(&buffer, &len, "TSG_PACKET { packetId=%s [0x%08" PRIx32 "], ",
    +	               tsg_packet_id_to_string(packet->packetId), packet->packetId))
    +		goto fail;
    +
    +	switch (packet->packetId)
    +	{
    +		case TSG_PACKET_TYPE_HEADER:
    +			if (!tsg_packet_header_to_string(&buffer, &len, packet->tsgPacket.packetHeader))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_VERSIONCAPS:
    +			if (!tsg_packet_versioncaps_to_string(&buffer, &len,
    +			                                      packet->tsgPacket.packetVersionCaps))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_QUARCONFIGREQUEST:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_QUARREQUEST:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_RESPONSE:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_QUARENC_RESPONSE:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_CAPABILITY_TYPE_NAP:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_CAPS_RESPONSE:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_MSGREQUEST_PACKET:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_MESSAGE_PACKET:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_AUTH:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		case TSG_PACKET_TYPE_REAUTH:
    +			if (!tsg_print(&buffer, &len, "TODO"))
    +				goto fail;
    +			break;
    +		default:
    +			if (!tsg_print(&buffer, &len, "INVALID"))
    +				goto fail;
    +			break;
    +	}
    +
    +	if (!tsg_print(&buffer, &len, " }"))
    +		goto fail;
    +
    +fail:
    +	return sbuffer;
    +}
    +
     static BOOL tsg_stream_align(wStream* s, size_t align)
     {
     	size_t pos;
    @@ -362,7 +583,7 @@ static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UI
      * );
      */
     
    -static BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg, PTSG_PACKET tsgPacket)
    +static BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg, const PTSG_PACKET tsgPacket)
     {
     	BOOL rc = FALSE;
     	BOOL write = TRUE;
    @@ -374,7 +595,7 @@ static BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg, PTSG_PACKET tsgPacket)
     		return FALSE;
     
     	rpc = tsg->rpc;
    -	WLog_DBG(TAG, "TsProxyCreateTunnelWriteRequest");
    +	WLog_DBG(TAG, "%s: %s", __FUNCTION__, tsg_packet_to_string(tsgPacket));
     	s = Stream_New(NULL, 108);
     
     	if (!s)
    @@ -506,7 +727,6 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu,
     	PTSG_PACKET_VERSIONCAPS versionCaps = NULL;
     	PTSG_PACKET_CAPS_RESPONSE packetCapsResponse = NULL;
     	PTSG_PACKET_QUARENC_RESPONSE packetQuarEncResponse = NULL;
    -	WLog_DBG(TAG, "TsProxyCreateTunnelReadResponse");
     
     	if (!pdu)
     		return FALSE;
    @@ -523,6 +743,8 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu,
     	Stream_Read_UINT32(pdu->s, packet->packetId); /* PacketId (4 bytes) */
     	Stream_Read_UINT32(pdu->s, SwitchValue);      /* SwitchValue (4 bytes) */
     
    +	WLog_DBG(TAG, "%s: %s", __FUNCTION__, tsg_packet_id_to_string(packet->packetId));
    +
     	if ((packet->packetId == TSG_PACKET_TYPE_CAPS_RESPONSE) &&
     	    (SwitchValue == TSG_PACKET_TYPE_CAPS_RESPONSE))
     	{
    @@ -885,7 +1107,6 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
     	UINT32 idleTimeout;
     	PTSG_PACKET packet = NULL;
     	PTSG_PACKET_RESPONSE packetResponse = NULL;
    -	WLog_DBG(TAG, "TsProxyAuthorizeTunnelReadResponse");
     
     	if (!pdu)
     		return FALSE;
    @@ -902,6 +1123,8 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
     	Stream_Read_UINT32(pdu->s, packet->packetId); /* PacketId (4 bytes) */
     	Stream_Read_UINT32(pdu->s, SwitchValue);      /* SwitchValue (4 bytes) */
     
    +	WLog_DBG(TAG, "%s: %s", __FUNCTION__, tsg_packet_id_to_string(packet->packetId));
    +
     	if (packet->packetId == E_PROXY_NAP_ACCESSDENIED)
     	{
     		WLog_ERR(TAG, "status: E_PROXY_NAP_ACCESSDENIED (0x%08X)", E_PROXY_NAP_ACCESSDENIED);
    @@ -1059,7 +1282,6 @@ static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
     	TSG_PACKET_MSG_RESPONSE packetMsgResponse = { 0 };
     	TSG_PACKET_STRING_MESSAGE packetStringMessage = { 0 };
     	TSG_PACKET_REAUTH_MESSAGE packetReauthMessage = { 0 };
    -	WLog_DBG(TAG, "TsProxyMakeTunnelCallReadResponse");
     
     	/* This is an asynchronous response */
     
    @@ -1073,6 +1295,8 @@ static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
     	Stream_Read_UINT32(pdu->s, packet.packetId); /* PacketId (4 bytes) */
     	Stream_Read_UINT32(pdu->s, SwitchValue);     /* SwitchValue (4 bytes) */
     
    +	WLog_DBG(TAG, "%s: %s", __FUNCTION__, tsg_packet_id_to_string(packet.packetId));
    +
     	if ((packet.packetId != TSG_PACKET_TYPE_MESSAGE_PACKET) ||
     	    (SwitchValue != TSG_PACKET_TYPE_MESSAGE_PACKET))
     	{
    @@ -1357,50 +1581,16 @@ static BOOL TsProxySetupReceivePipeWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* cha
     
     static BOOL tsg_transition_to_state(rdpTsg* tsg, TSG_STATE state)
     {
    -	const char* str = "TSG_STATE_UNKNOWN";
    -
    -	switch (state)
    -	{
    -		case TSG_STATE_INITIAL:
    -			str = "TSG_STATE_INITIAL";
    -			break;
    -
    -		case TSG_STATE_CONNECTED:
    -			str = "TSG_STATE_CONNECTED";
    -			break;
    -
    -		case TSG_STATE_AUTHORIZED:
    -			str = "TSG_STATE_AUTHORIZED";
    -			break;
    -
    -		case TSG_STATE_CHANNEL_CREATED:
    -			str = "TSG_STATE_CHANNEL_CREATED";
    -			break;
    -
    -		case TSG_STATE_PIPE_CREATED:
    -			str = "TSG_STATE_PIPE_CREATED";
    -			break;
    +	const char* oldState = tsg_state_to_string(tsg->state);
    +	const char* newState = tsg_state_to_string(state);
     
    -		case TSG_STATE_TUNNEL_CLOSE_PENDING:
    -			str = "TSG_STATE_TUNNEL_CLOSE_PENDING";
    -			break;
    -
    -		case TSG_STATE_CHANNEL_CLOSE_PENDING:
    -			str = "TSG_STATE_CHANNEL_CLOSE_PENDING";
    -			break;
    -
    -		case TSG_STATE_FINAL:
    -			str = "TSG_STATE_FINAL";
    -			break;
    -	}
    -
    -	WLog_DBG(TAG, "%s", str);
    +	WLog_DBG(TAG, "%s -> %s", oldState, newState);
     	return tsg_set_state(tsg, state);
     }
     
     BOOL tsg_proxy_begin(rdpTsg* tsg)
     {
    -	TSG_PACKET tsgPacket;
    +	TSG_PACKET tsgPacket = { 0 };
     	PTSG_CAPABILITY_NAP tsgCapNap;
     	PTSG_PACKET_VERSIONCAPS packetVersionCaps;
     
    @@ -1443,7 +1633,7 @@ BOOL tsg_proxy_begin(rdpTsg* tsg)
     
     static BOOL tsg_proxy_reauth(rdpTsg* tsg)
     {
    -	TSG_PACKET tsgPacket;
    +	TSG_PACKET tsgPacket = { 0 };
     	PTSG_PACKET_REAUTH packetReauth;
     	PTSG_PACKET_VERSIONCAPS packetVersionCaps;
     
    @@ -1815,8 +2005,9 @@ static BOOL tsg_set_machine_name(rdpTsg* tsg, const char* machineName)
     	return TRUE;
     }
     
    -BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, int timeout)
    +BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout)
     {
    +	UINT64 looptimeout = timeout * 1000ULL;
     	DWORD nCount;
     	HANDLE events[64];
     	rdpRpc* rpc = tsg->rpc;
    @@ -1847,7 +2038,19 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, int timeout)
     
     	while (tsg->state != TSG_STATE_PIPE_CREATED)
     	{
    -		WaitForMultipleObjects(nCount, events, FALSE, 250);
    +		const DWORD polltimeout = 250;
    +		DWORD status = WaitForMultipleObjects(nCount, events, FALSE, polltimeout);
    +		if (status == WAIT_TIMEOUT)
    +		{
    +			if (timeout > 0)
    +			{
    +				if (looptimeout < polltimeout)
    +					return FALSE;
    +				looptimeout -= polltimeout;
    +			}
    +		}
    +		else
    +			looptimeout = timeout * 1000ULL;
     
     		if (!tsg_check_event_handles(tsg))
     		{
    
  • libfreerdp/core/gateway/tsg.h+1 14 modified
    @@ -62,19 +62,6 @@ typedef enum _TSG_STATE TSG_STATE;
     
     #define TS_GATEWAY_TRANSPORT 0x5452
     
    -#define TSG_PACKET_TYPE_HEADER 0x00004844
    -#define TSG_PACKET_TYPE_VERSIONCAPS 0x00005643
    -#define TSG_PACKET_TYPE_QUARCONFIGREQUEST 0x00005143
    -#define TSG_PACKET_TYPE_QUARREQUEST 0x00005152
    -#define TSG_PACKET_TYPE_RESPONSE 0x00005052
    -#define TSG_PACKET_TYPE_QUARENC_RESPONSE 0x00004552
    -#define TSG_CAPABILITY_TYPE_NAP 0x00000001
    -#define TSG_PACKET_TYPE_CAPS_RESPONSE 0x00004350
    -#define TSG_PACKET_TYPE_MSGREQUEST_PACKET 0x00004752
    -#define TSG_PACKET_TYPE_MESSAGE_PACKET 0x00004750
    -#define TSG_PACKET_TYPE_AUTH 0x00004054
    -#define TSG_PACKET_TYPE_REAUTH 0x00005250
    -
     #define TSG_ASYNC_MESSAGE_CONSENT_MESSAGE 0x00000001
     #define TSG_ASYNC_MESSAGE_SERVICE_MESSAGE 0x00000002
     #define TSG_ASYNC_MESSAGE_REAUTH 0x00000003
    @@ -118,7 +105,7 @@ FREERDP_LOCAL void tsg_free(rdpTsg* tsg);
     
     FREERDP_LOCAL BOOL tsg_proxy_begin(rdpTsg* tsg);
     
    -FREERDP_LOCAL BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, int timeout);
    +FREERDP_LOCAL BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout);
     FREERDP_LOCAL BOOL tsg_disconnect(rdpTsg* tsg);
     
     FREERDP_LOCAL BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu);
    
  • libfreerdp/core/license.c+9 0 modified
    @@ -1252,6 +1252,9 @@ BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s)
     	if (!licenseStream)
     		goto out_free_blob;
     
    +	if (Stream_GetRemainingLength(licenseStream) < 8)
    +		goto out_free_stream;
    +
     	Stream_Read_UINT16(licenseStream, os_minor);
     	Stream_Read_UINT16(licenseStream, os_major);
     
    @@ -1266,6 +1269,8 @@ BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s)
     	Stream_Seek(licenseStream, cbScope);
     
     	/* CompanyName */
    +	if (Stream_GetRemainingLength(licenseStream) < 4)
    +		goto out_free_stream;
     	Stream_Read_UINT32(licenseStream, cbCompanyName);
     	if (Stream_GetRemainingLength(licenseStream) < cbCompanyName)
     		goto out_free_stream;
    @@ -1276,6 +1281,8 @@ BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s)
     	Stream_Seek(licenseStream, cbCompanyName);
     
     	/* productId */
    +	if (Stream_GetRemainingLength(licenseStream) < 4)
    +		goto out_free_stream;
     	Stream_Read_UINT32(licenseStream, cbProductId);
     	if (Stream_GetRemainingLength(licenseStream) < cbProductId)
     		goto out_free_stream;
    @@ -1286,6 +1293,8 @@ BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s)
     	Stream_Seek(licenseStream, cbProductId);
     
     	/* licenseInfo */
    +	if (Stream_GetRemainingLength(licenseStream) < 4)
    +		goto out_free_stream;
     	Stream_Read_UINT32(licenseStream, cbLicenseInfo);
     	if (Stream_GetRemainingLength(licenseStream) < cbLicenseInfo)
     		goto out_free_stream;
    
  • libfreerdp/core/orders.c+179 61 modified
    @@ -43,51 +43,144 @@
     
     #define TAG FREERDP_TAG("core.orders")
     
    -const BYTE PRIMARY_DRAWING_ORDER_FIELD_BYTES[] = { DSTBLT_ORDER_FIELD_BYTES,
    -	                                               PATBLT_ORDER_FIELD_BYTES,
    -	                                               SCRBLT_ORDER_FIELD_BYTES,
    -	                                               0,
    -	                                               0,
    -	                                               0,
    -	                                               0,
    -	                                               DRAW_NINE_GRID_ORDER_FIELD_BYTES,
    -	                                               MULTI_DRAW_NINE_GRID_ORDER_FIELD_BYTES,
    -	                                               LINE_TO_ORDER_FIELD_BYTES,
    -	                                               OPAQUE_RECT_ORDER_FIELD_BYTES,
    -	                                               SAVE_BITMAP_ORDER_FIELD_BYTES,
    -	                                               0,
    -	                                               MEMBLT_ORDER_FIELD_BYTES,
    -	                                               MEM3BLT_ORDER_FIELD_BYTES,
    -	                                               MULTI_DSTBLT_ORDER_FIELD_BYTES,
    -	                                               MULTI_PATBLT_ORDER_FIELD_BYTES,
    -	                                               MULTI_SCRBLT_ORDER_FIELD_BYTES,
    -	                                               MULTI_OPAQUE_RECT_ORDER_FIELD_BYTES,
    -	                                               FAST_INDEX_ORDER_FIELD_BYTES,
    -	                                               POLYGON_SC_ORDER_FIELD_BYTES,
    -	                                               POLYGON_CB_ORDER_FIELD_BYTES,
    -	                                               POLYLINE_ORDER_FIELD_BYTES,
    -	                                               0,
    -	                                               FAST_GLYPH_ORDER_FIELD_BYTES,
    -	                                               ELLIPSE_SC_ORDER_FIELD_BYTES,
    -	                                               ELLIPSE_CB_ORDER_FIELD_BYTES,
    -	                                               GLYPH_INDEX_ORDER_FIELD_BYTES };
    -
    -#define PRIMARY_DRAWING_ORDER_COUNT (ARRAYSIZE(PRIMARY_DRAWING_ORDER_FIELD_BYTES))
    -
    -static const BYTE CBR2_BPP[] = { 0, 0, 0, 8, 16, 24, 32 };
    -
    -static const BYTE BPP_CBR2[] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
    -	                             0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0 };
    -
    -static const BYTE CBR23_BPP[] = { 0, 0, 0, 8, 16, 24, 32 };
    -
    -static const BYTE BPP_CBR23[] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
    -	                              0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0 };
    -
    -static const BYTE BMF_BPP[] = { 0, 1, 0, 8, 16, 24, 32, 0 };
    -
    -static const BYTE BPP_BMF[] = { 0, 1, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0,
    -	                            0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0 };
    +BYTE get_primary_drawing_order_field_bytes(UINT32 orderType, BOOL* pValid)
    +{
    +	if (pValid)
    +		*pValid = TRUE;
    +	switch (orderType)
    +	{
    +		case 0:
    +			return DSTBLT_ORDER_FIELD_BYTES;
    +		case 1:
    +			return PATBLT_ORDER_FIELD_BYTES;
    +		case 2:
    +			return SCRBLT_ORDER_FIELD_BYTES;
    +		case 3:
    +			return 0;
    +		case 4:
    +			return 0;
    +		case 5:
    +			return 0;
    +		case 6:
    +			return 0;
    +		case 7:
    +			return DRAW_NINE_GRID_ORDER_FIELD_BYTES;
    +		case 8:
    +			return MULTI_DRAW_NINE_GRID_ORDER_FIELD_BYTES;
    +		case 9:
    +			return LINE_TO_ORDER_FIELD_BYTES;
    +		case 10:
    +			return OPAQUE_RECT_ORDER_FIELD_BYTES;
    +		case 11:
    +			return SAVE_BITMAP_ORDER_FIELD_BYTES;
    +		case 12:
    +			return 0;
    +		case 13:
    +			return MEMBLT_ORDER_FIELD_BYTES;
    +		case 14:
    +			return MEM3BLT_ORDER_FIELD_BYTES;
    +		case 15:
    +			return MULTI_DSTBLT_ORDER_FIELD_BYTES;
    +		case 16:
    +			return MULTI_PATBLT_ORDER_FIELD_BYTES;
    +		case 17:
    +			return MULTI_SCRBLT_ORDER_FIELD_BYTES;
    +		case 18:
    +			return MULTI_OPAQUE_RECT_ORDER_FIELD_BYTES;
    +		case 19:
    +			return FAST_INDEX_ORDER_FIELD_BYTES;
    +		case 20:
    +			return POLYGON_SC_ORDER_FIELD_BYTES;
    +		case 21:
    +			return POLYGON_CB_ORDER_FIELD_BYTES;
    +		case 22:
    +			return POLYLINE_ORDER_FIELD_BYTES;
    +		case 23:
    +			return 0;
    +		case 24:
    +			return FAST_GLYPH_ORDER_FIELD_BYTES;
    +		case 25:
    +			return ELLIPSE_SC_ORDER_FIELD_BYTES;
    +		case 26:
    +			return ELLIPSE_CB_ORDER_FIELD_BYTES;
    +		case 27:
    +			return GLYPH_INDEX_ORDER_FIELD_BYTES;
    +		default:
    +			if (pValid)
    +				*pValid = FALSE;
    +			WLog_WARN(TAG, "Invalid orderType 0x%08X received", orderType);
    +			return 0;
    +	}
    +}
    +
    +static BYTE get_cbr2_bpp(UINT32 bpp, BOOL* pValid)
    +{
    +	if (pValid)
    +		*pValid = TRUE;
    +	switch (bpp)
    +	{
    +		case 3:
    +			return 8;
    +		case 4:
    +			return 16;
    +		case 5:
    +			return 24;
    +		case 6:
    +			return 32;
    +		default:
    +			WLog_WARN(TAG, "Invalid bpp %" PRIu32, bpp);
    +			if (pValid)
    +				*pValid = FALSE;
    +			return 0;
    +	}
    +}
    +
    +static BYTE get_bmf_bpp(UINT32 bmf, BOOL* pValid)
    +{
    +	if (pValid)
    +		*pValid = TRUE;
    +	switch (bmf)
    +	{
    +		case 1:
    +			return 1;
    +		case 3:
    +			return 8;
    +		case 4:
    +			return 16;
    +		case 5:
    +			return 24;
    +		case 6:
    +			return 32;
    +		default:
    +			WLog_WARN(TAG, "Invalid bmf %" PRIu32, bmf);
    +			if (pValid)
    +				*pValid = FALSE;
    +			return 0;
    +	}
    +}
    +static BYTE get_bpp_bmf(UINT32 bpp, BOOL* pValid)
    +{
    +	if (pValid)
    +		*pValid = TRUE;
    +	switch (bpp)
    +	{
    +		case 1:
    +			return 1;
    +		case 8:
    +			return 3;
    +		case 16:
    +			return 4;
    +		case 24:
    +			return 5;
    +		case 32:
    +			return 6;
    +		default:
    +			WLog_WARN(TAG, "Invalid color depth %" PRIu32, bpp);
    +			if (pValid)
    +				*pValid = FALSE;
    +			return 0;
    +	}
    +}
     
     static BOOL check_order_activated(wLog* log, rdpSettings* settings, const char* orderName,
                                       BOOL condition)
    @@ -775,9 +868,11 @@ static INLINE BOOL update_read_brush(wStream* s, rdpBrush* brush, BYTE fieldFlag
     
     	if (brush->style & CACHED_BRUSH)
     	{
    +		BOOL rc;
     		brush->index = brush->hatch;
    -		brush->bpp = BMF_BPP[brush->style & 0x07];
    -
    +		brush->bpp = get_bmf_bpp(brush->style, &rc);
    +		if (!rc)
    +			return FALSE;
     		if (brush->bpp == 0)
     			brush->bpp = 1;
     	}
    @@ -819,9 +914,11 @@ static INLINE BOOL update_write_brush(wStream* s, rdpBrush* brush, BYTE fieldFla
     
     	if (brush->style & CACHED_BRUSH)
     	{
    +		BOOL rc;
     		brush->hatch = brush->index;
    -		brush->bpp = BMF_BPP[brush->style & 0x07];
    -
    +		brush->bpp = get_bmf_bpp(brush->style, &rc);
    +		if (!rc)
    +			return FALSE;
     		if (brush->bpp == 0)
     			brush->bpp = 1;
     	}
    @@ -1977,6 +2074,7 @@ BOOL update_write_cache_bitmap_order(wStream* s, const CACHE_BITMAP_ORDER* cache
     static CACHE_BITMAP_V2_ORDER* update_read_cache_bitmap_v2_order(rdpUpdate* update, wStream* s,
                                                                     BOOL compressed, UINT16 flags)
     {
    +	BOOL rc;
     	BYTE bitsPerPixelId;
     	CACHE_BITMAP_V2_ORDER* cache_bitmap_v2;
     
    @@ -1991,7 +2089,9 @@ static CACHE_BITMAP_V2_ORDER* update_read_cache_bitmap_v2_order(rdpUpdate* updat
     	cache_bitmap_v2->cacheId = flags & 0x0003;
     	cache_bitmap_v2->flags = (flags & 0xFF80) >> 7;
     	bitsPerPixelId = (flags & 0x0078) >> 3;
    -	cache_bitmap_v2->bitmapBpp = CBR2_BPP[bitsPerPixelId];
    +	cache_bitmap_v2->bitmapBpp = get_cbr2_bpp(bitsPerPixelId, &rc);
    +	if (!rc)
    +		goto fail;
     
     	if (cache_bitmap_v2->flags & CBR2_PERSISTENT_KEY_PRESENT)
     	{
    @@ -2070,13 +2170,16 @@ int update_approximate_cache_bitmap_v2_order(CACHE_BITMAP_V2_ORDER* cache_bitmap
     BOOL update_write_cache_bitmap_v2_order(wStream* s, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2,
                                             BOOL compressed, UINT16* flags)
     {
    +	BOOL rc;
     	BYTE bitsPerPixelId;
     
     	if (!Stream_EnsureRemainingCapacity(
     	        s, update_approximate_cache_bitmap_v2_order(cache_bitmap_v2, compressed, flags)))
     		return FALSE;
     
    -	bitsPerPixelId = BPP_CBR2[cache_bitmap_v2->bitmapBpp];
    +	bitsPerPixelId = get_bpp_bmf(cache_bitmap_v2->bitmapBpp, &rc);
    +	if (!rc)
    +		return FALSE;
     	*flags = (cache_bitmap_v2->cacheId & 0x0003) | (bitsPerPixelId << 3) |
     	         ((cache_bitmap_v2->flags << 7) & 0xFF80);
     
    @@ -2138,6 +2241,7 @@ BOOL update_write_cache_bitmap_v2_order(wStream* s, CACHE_BITMAP_V2_ORDER* cache
     static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* update, wStream* s,
                                                                     UINT16 flags)
     {
    +	BOOL rc;
     	BYTE bitsPerPixelId;
     	BITMAP_DATA_EX* bitmapData;
     	UINT32 new_len;
    @@ -2155,7 +2259,9 @@ static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* updat
     	cache_bitmap_v3->cacheId = flags & 0x00000003;
     	cache_bitmap_v3->flags = (flags & 0x0000FF80) >> 7;
     	bitsPerPixelId = (flags & 0x00000078) >> 3;
    -	cache_bitmap_v3->bpp = CBR23_BPP[bitsPerPixelId];
    +	cache_bitmap_v3->bpp = get_cbr2_bpp(bitsPerPixelId, &rc);
    +	if (!rc)
    +		goto fail;
     
     	if (Stream_GetRemainingLength(s) < 21)
     		goto fail;
    @@ -2203,6 +2309,7 @@ int update_approximate_cache_bitmap_v3_order(CACHE_BITMAP_V3_ORDER* cache_bitmap
     BOOL update_write_cache_bitmap_v3_order(wStream* s, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3,
                                             UINT16* flags)
     {
    +	BOOL rc;
     	BYTE bitsPerPixelId;
     	BITMAP_DATA_EX* bitmapData;
     
    @@ -2211,7 +2318,9 @@ BOOL update_write_cache_bitmap_v3_order(wStream* s, CACHE_BITMAP_V3_ORDER* cache
     		return FALSE;
     
     	bitmapData = &cache_bitmap_v3->bitmapData;
    -	bitsPerPixelId = BPP_CBR23[cache_bitmap_v3->bpp];
    +	bitsPerPixelId = get_bpp_bmf(cache_bitmap_v3->bpp, &rc);
    +	if (!rc)
    +		return FALSE;
     	*flags = (cache_bitmap_v3->cacheId & 0x00000003) |
     	         ((cache_bitmap_v3->flags << 7) & 0x0000FF80) | ((bitsPerPixelId << 3) & 0x00000078);
     	Stream_Write_UINT16(s, cache_bitmap_v3->cacheIndex); /* cacheIndex (2 bytes) */
    @@ -2535,6 +2644,7 @@ static BOOL update_compress_brush(wStream* s, const BYTE* input, BYTE bpp)
     static CACHE_BRUSH_ORDER* update_read_cache_brush_order(rdpUpdate* update, wStream* s, UINT16 flags)
     {
     	int i;
    +	BOOL rc;
     	BYTE iBitmapFormat;
     	BOOL compressed = FALSE;
     	CACHE_BRUSH_ORDER* cache_brush = calloc(1, sizeof(CACHE_BRUSH_ORDER));
    @@ -2548,10 +2658,10 @@ static CACHE_BRUSH_ORDER* update_read_cache_brush_order(rdpUpdate* update, wStre
     	Stream_Read_UINT8(s, cache_brush->index); /* cacheEntry (1 byte) */
     	Stream_Read_UINT8(s, iBitmapFormat);      /* iBitmapFormat (1 byte) */
     
    -	if (iBitmapFormat >= ARRAYSIZE(BMF_BPP))
    +	cache_brush->bpp = get_bmf_bpp(iBitmapFormat, &rc);
    +	if (!rc)
     		goto fail;
     
    -	cache_brush->bpp = BMF_BPP[iBitmapFormat];
     	Stream_Read_UINT8(s, cache_brush->cx);     /* cx (1 byte) */
     	Stream_Read_UINT8(s, cache_brush->cy);     /* cy (1 byte) */
     	Stream_Read_UINT8(s, cache_brush->style);  /* style (1 byte) */
    @@ -2622,13 +2732,16 @@ BOOL update_write_cache_brush_order(wStream* s, const CACHE_BRUSH_ORDER* cache_b
     {
     	int i;
     	BYTE iBitmapFormat;
    +	BOOL rc;
     	BOOL compressed = FALSE;
     
     	if (!Stream_EnsureRemainingCapacity(s,
     	                                    update_approximate_cache_brush_order(cache_brush, flags)))
     		return FALSE;
     
    -	iBitmapFormat = BPP_BMF[cache_brush->bpp];
    +	iBitmapFormat = get_bpp_bmf(cache_brush->bpp, &rc);
    +	if (!rc)
    +		return FALSE;
     	Stream_Write_UINT8(s, cache_brush->index);  /* cacheEntry (1 byte) */
     	Stream_Write_UINT8(s, iBitmapFormat);       /* iBitmapFormat (1 byte) */
     	Stream_Write_UINT8(s, cache_brush->cx);     /* cx (1 byte) */
    @@ -3240,6 +3353,7 @@ static BOOL read_primary_order(wLog* log, const char* orderName, wStream* s,
     
     static BOOL update_recv_primary_order(rdpUpdate* update, wStream* s, BYTE flags)
     {
    +	BYTE field;
     	BOOL rc = FALSE;
     	rdpContext* context = update->context;
     	rdpPrimaryUpdate* primary = update->primary;
    @@ -3263,8 +3377,11 @@ static BOOL update_recv_primary_order(rdpUpdate* update, wStream* s, BYTE flags)
     	if (!check_primary_order_supported(update->log, settings, orderInfo->orderType, orderName))
     		return FALSE;
     
    -	if (!update_read_field_flags(s, &(orderInfo->fieldFlags), flags,
    -	                             PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType]))
    +	field = get_primary_drawing_order_field_bytes(orderInfo->orderType, &rc);
    +	if (!rc)
    +		return FALSE;
    +
    +	if (!update_read_field_flags(s, &(orderInfo->fieldFlags), flags, field))
     	{
     		WLog_Print(update->log, WLOG_ERROR, "update_read_field_flags() failed");
     		return FALSE;
    @@ -3506,7 +3623,7 @@ static BOOL update_recv_secondary_order(rdpUpdate* update, wStream* s, BYTE flag
     	Stream_Read_UINT16(s, orderLength); /* orderLength (2 bytes) */
     	Stream_Read_UINT16(s, extraFlags);  /* extraFlags (2 bytes) */
     	Stream_Read_UINT8(s, orderType);    /* orderType (1 byte) */
    -	if (Stream_GetRemainingLength(s) < orderLength + 7)
    +	if (Stream_GetRemainingLength(s) < orderLength + 7U)
     	{
     		WLog_Print(update->log, WLOG_ERROR, "Stream_GetRemainingLength(s) %" PRIuz " < %" PRIu16,
     		           Stream_GetRemainingLength(s), orderLength + 7);
    @@ -3645,12 +3762,13 @@ static BOOL update_recv_secondary_order(rdpUpdate* update, wStream* s, BYTE flag
     		           name, end - start);
     		return FALSE;
     	}
    -	diff = start - end;
    +	diff = end - start;
     	if (diff > 0)
     	{
     		WLog_Print(update->log, WLOG_DEBUG,
     		           "SECONDARY_ORDER %s: read %" PRIuz "bytes short, skipping", name, diff);
    -		Stream_Seek(s, diff);
    +		if (!Stream_SafeSeek(s, diff))
    +			return FALSE;
     	}
     	return rc;
     }
    
  • libfreerdp/core/orders.h+1 1 modified
    @@ -189,7 +189,7 @@
     
     #define CG_GLYPH_UNICODE_PRESENT 0x0010
     
    -FREERDP_LOCAL extern const BYTE PRIMARY_DRAWING_ORDER_FIELD_BYTES[];
    +FREERDP_LOCAL BYTE get_primary_drawing_order_field_bytes(UINT32 orderType, BOOL* pValid);
     
     FREERDP_LOCAL BOOL update_recv_order(rdpUpdate* update, wStream* s);
     
    
  • libfreerdp/core/rdp.c+1 1 modified
    @@ -167,7 +167,7 @@ BOOL rdp_read_share_control_header(wStream* s, UINT16* tpktLength, UINT16* remai
     		return TRUE;
     	}
     
    -	if ((len < 4) || ((len - 2) > Stream_GetRemainingLength(s)))
    +	if ((len < 4U) || ((len - 2U) > Stream_GetRemainingLength(s)))
     		return FALSE;
     
     	if (tpktLength)
    
  • libfreerdp/core/security.c+20 8 modified
    @@ -394,6 +394,8 @@ BOOL security_salted_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32 length,
     	BYTE md5_digest[WINPR_MD5_DIGEST_LENGTH];
     	BYTE sha1_digest[WINPR_SHA1_DIGEST_LENGTH];
     	BOOL result = FALSE;
    +
    +	EnterCriticalSection(&rdp->critical);
     	security_UINT32_le(length_le, length); /* length must be little-endian */
     
     	if (encryption)
    @@ -456,6 +458,7 @@ BOOL security_salted_mac_signature(rdpRdp* rdp, const BYTE* data, UINT32 length,
     	memcpy(output, md5_digest, 8);
     	result = TRUE;
     out:
    +	LeaveCriticalSection(&rdp->critical);
     	winpr_Digest_Free(sha1);
     	winpr_Digest_Free(md5);
     	return result;
    @@ -636,12 +639,14 @@ BOOL security_establish_keys(const BYTE* client_random, rdpRdp* rdp)
     		rdp->rc4_key_len = 16;
     	}
     
    +	EnterCriticalSection(&rdp->critical);
     	memcpy(rdp->decrypt_update_key, rdp->decrypt_key, 16);
     	memcpy(rdp->encrypt_update_key, rdp->encrypt_key, 16);
     	rdp->decrypt_use_count = 0;
     	rdp->decrypt_checksum_use_count = 0;
     	rdp->encrypt_use_count = 0;
     	rdp->encrypt_checksum_use_count = 0;
    +	LeaveCriticalSection(&rdp->critical);
     	return TRUE;
     }
     
    @@ -741,29 +746,34 @@ BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp)
     
     BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp)
     {
    +	BOOL rc = FALSE;
    +	EnterCriticalSection(&rdp->critical);
     	if (rdp->rc4_decrypt_key == NULL)
    -		return FALSE;
    +		goto fail;
     
     	if (rdp->decrypt_use_count >= 4096)
     	{
     		if (!security_key_update(rdp->decrypt_key, rdp->decrypt_update_key, rdp->rc4_key_len, rdp))
    -			return FALSE;
    +			goto fail;
     
     		winpr_RC4_Free(rdp->rc4_decrypt_key);
     		rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len);
     
     		if (!rdp->rc4_decrypt_key)
    -			return FALSE;
    +			goto fail;
     
     		rdp->decrypt_use_count = 0;
     	}
     
     	if (!winpr_RC4_Update(rdp->rc4_decrypt_key, length, data, data))
    -		return FALSE;
    +		goto fail;
     
     	rdp->decrypt_use_count += 1;
     	rdp->decrypt_checksum_use_count++;
    -	return TRUE;
    +	rc = TRUE;
    +fail:
    +	LeaveCriticalSection(&rdp->critical);
    +	return rc;
     }
     
     BOOL security_hmac_signature(const BYTE* data, size_t length, BYTE* output, rdpRdp* rdp)
    @@ -772,7 +782,9 @@ BOOL security_hmac_signature(const BYTE* data, size_t length, BYTE* output, rdpR
     	BYTE use_count_le[4];
     	WINPR_HMAC_CTX* hmac;
     	BOOL result = FALSE;
    +	EnterCriticalSection(&rdp->critical);
     	security_UINT32_le(use_count_le, rdp->encrypt_use_count);
    +	LeaveCriticalSection(&rdp->critical);
     
     	if (!(hmac = winpr_HMAC_New()))
     		return FALSE;
    @@ -831,7 +843,9 @@ BOOL security_fips_check_signature(const BYTE* data, size_t length, const BYTE*
     	BYTE use_count_le[4];
     	WINPR_HMAC_CTX* hmac;
     	BOOL result = FALSE;
    -	security_UINT32_le(use_count_le, rdp->decrypt_use_count);
    +	EnterCriticalSection(&rdp->critical);
    +	security_UINT32_le(use_count_le, rdp->decrypt_use_count++);
    +	LeaveCriticalSection(&rdp->critical);
     
     	if (!(hmac = winpr_HMAC_New()))
     		return FALSE;
    @@ -848,8 +862,6 @@ BOOL security_fips_check_signature(const BYTE* data, size_t length, const BYTE*
     	if (!winpr_HMAC_Final(hmac, buf, WINPR_SHA1_DIGEST_LENGTH))
     		goto out;
     
    -	rdp->decrypt_use_count++;
    -
     	if (!memcmp(sig, buf, 8))
     		result = TRUE;
     
    
  • libfreerdp/core/tcp.c+1 1 modified
    @@ -1060,7 +1060,7 @@ static BOOL freerdp_tcp_set_keep_alive_mode(const rdpSettings* settings, int soc
     }
     
     int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* hostname, int port,
    -                        int timeout)
    +                        DWORD timeout)
     {
     	int sockfd;
     	UINT32 optval;
    
  • libfreerdp/core/tcp.h+1 1 modified
    @@ -64,7 +64,7 @@ FREERDP_LOCAL BIO_METHOD* BIO_s_simple_socket(void);
     FREERDP_LOCAL BIO_METHOD* BIO_s_buffered_socket(void);
     
     FREERDP_LOCAL int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings,
    -                                      const char* hostname, int port, int timeout);
    +                                      const char* hostname, int port, DWORD timeout);
     
     FREERDP_LOCAL char* freerdp_tcp_get_peer_address(SOCKET sockfd);
     
    
  • libfreerdp/core/transport.c+1 1 modified
    @@ -354,7 +354,7 @@ BOOL transport_connect_nla(rdpTransport* transport)
     	return TRUE;
     }
     
    -BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, int timeout)
    +BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port, DWORD timeout)
     {
     	int sockfd;
     	BOOL status = FALSE;
    
  • libfreerdp/core/transport.h+1 1 modified
    @@ -81,7 +81,7 @@ struct rdp_transport
     
     FREERDP_LOCAL wStream* transport_send_stream_init(rdpTransport* transport, int size);
     FREERDP_LOCAL BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 port,
    -                                     int timeout);
    +                                     DWORD timeout);
     FREERDP_LOCAL BOOL transport_attach(rdpTransport* transport, int sockfd);
     FREERDP_LOCAL BOOL transport_disconnect(rdpTransport* transport);
     FREERDP_LOCAL BOOL transport_connect_rdp(rdpTransport* transport);
    
  • libfreerdp/core/update.c+2 2 modified
    @@ -1087,7 +1087,7 @@ static int update_prepare_order_info(rdpContext* context, ORDER_INFO* orderInfo,
     	orderInfo->controlFlags = ORDER_STANDARD;
     	orderInfo->controlFlags |= ORDER_TYPE_CHANGE;
     	length += 1;
    -	length += PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType];
    +	length += get_primary_drawing_order_field_bytes(orderInfo->orderType, NULL);
     	length += update_prepare_bounds(context, orderInfo);
     	return length;
     }
    @@ -1105,7 +1105,7 @@ static int update_write_order_info(rdpContext* context, wStream* s, ORDER_INFO*
     		Stream_Write_UINT8(s, orderInfo->orderType); /* orderType (1 byte) */
     
     	update_write_field_flags(s, orderInfo->fieldFlags, orderInfo->controlFlags,
    -	                         PRIMARY_DRAWING_ORDER_FIELD_BYTES[orderInfo->orderType]);
    +	                         get_primary_drawing_order_field_bytes(orderInfo->orderType, NULL));
     	update_write_bounds(s, orderInfo);
     	Stream_SetPosition(s, position);
     	return 0;
    
  • libfreerdp/crypto/crypto.c+8 1 modified
    @@ -105,11 +105,18 @@ static int crypto_rsa_common(const BYTE* input, int length, UINT32 key_length, c
     	BIGNUM* exp = NULL;
     	BIGNUM* x = NULL;
     	BIGNUM* y = NULL;
    -	size_t bufferSize = 2 * key_length + exponent_size;
    +	size_t bufferSize;
     
     	if (!input || (length < 0) || (exponent_size < 0) || !modulus || !exponent || !output)
     		return -1;
     
    +	if (exponent_size > SIZE_MAX / 2)
    +		return -1;
    +
    +	if (key_length >= SIZE_MAX / 2 - exponent_size)
    +		return -1;
    +
    +	bufferSize = 2ULL * key_length + exponent_size;
     	if (length > bufferSize)
     		bufferSize = length;
     
    
  • libfreerdp/gdi/gfx.c+4 1 modified
    @@ -141,7 +141,10 @@ static UINT gdi_OutputUpdate(rdpGdi* gdi, gdiGfxSurface* surface)
     		if (!freerdp_image_scale(gdi->primary_buffer, gdi->dstFormat, gdi->stride, nXDst, nYDst,
     		                         dwidth, dheight, surface->data, surface->format, surface->scanline,
     		                         nXSrc, nYSrc, swidth, sheight))
    -			return CHANNEL_RC_NULL_DATA;
    +		{
    +			rc = CHANNEL_RC_NULL_DATA;
    +			goto fail;
    +		}
     
     		gdi_InvalidateRegion(gdi->primary->hdc, (INT32)nXDst, (INT32)nYDst, (INT32)dwidth,
     		                     (INT32)dheight);
    
  • libfreerdp/gdi/graphics.c+1 0 modified
    @@ -93,6 +93,7 @@ static BOOL gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
     	if (!gdi_bitmap->bitmap)
     	{
     		gdi_DeleteDC(gdi_bitmap->hdc);
    +		gdi_bitmap->hdc = NULL;
     		return FALSE;
     	}
     
    
  • libfreerdp/utils/pcap.c+9 13 modified
    @@ -170,22 +170,17 @@ rdpPcap* pcap_open(char* name, BOOL write)
     {
     	rdpPcap* pcap;
     
    -	FILE* pcap_fp = fopen(name, write ? "w+b" : "rb");
    -
    -	if (pcap_fp == NULL)
    -	{
    -		WLog_ERR(TAG, "opening pcap dump");
    -		return NULL;
    -	}
    -
     	pcap = (rdpPcap*)calloc(1, sizeof(rdpPcap));
     	if (!pcap)
    -		goto fail_close;
    +		goto fail;
     
     	pcap->name = name;
     	pcap->write = write;
     	pcap->record_count = 0;
    -	pcap->fp = pcap_fp;
    +	pcap->fp = fopen(name, write ? "w+b" : "rb");
    +
    +	if (pcap->fp == NULL)
    +		goto fail;
     
     	if (write)
     	{
    @@ -211,9 +206,7 @@ rdpPcap* pcap_open(char* name, BOOL write)
     	return pcap;
     
     fail:
    -	free(pcap);
    -fail_close:
    -	fclose(pcap_fp);
    +	pcap_close(pcap);
     	return NULL;
     }
     
    @@ -231,6 +224,9 @@ void pcap_flush(rdpPcap* pcap)
     
     void pcap_close(rdpPcap* pcap)
     {
    +	if (!pcap)
    +		return;
    +
     	pcap_flush(pcap);
     
     	if (pcap->fp != NULL)
    
  • scripts/create_release_taball.sh+50 0 added
    @@ -0,0 +1,50 @@
    +#!/bin/bash -e
    +
    +function run {
    +	echo "[RUN] $@"
    +	"$@"
    +	RES=$?
    +	if [[ $RES -ne 0 ]];
    +	then
    +		echo "[ERROR] $@ retured $RES"
    +		exit 1
    +	fi
    +}
    +
    +if [ -z ${TAG:-} ];then
    +	echo "No TAG set - trying to detect"
    +	TAG=$(git describe --tags)
    +	echo "Is the TAG ${TAG} ok (YES|NO)?"
    +	read answ
    +	case "$answ" in
    +		YES):
    +			;;
    +		*)
    +			echo 'stopping here'
    +			exit 1
    +	esac
    +fi
    +
    +TMPDIR=$(mktemp -d -t release-${TAG}-XXXXXXXXXX)
    +
    +run git archive --prefix=freerdp-${TAG}/ --format=tar.gz -o ${TMPDIR}/freerdp-${TAG}.tar.gz ${TAG}
    +run tar xzvf ${TMPDIR}/freerdp-${TAG}.tar.gz -C ${TMPDIR}
    +run echo ${TAG} > ${TMPDIR}/freerdp-${TAG}/.source_version
    +
    +pushd .
    +cd  $TMPDIR
    +run tar czvf freerdp-${TAG}.tar.gz freerdp-${TAG}
    +run md5sum freerdp-${TAG}.tar.gz > freerdp-${TAG}.tar.gz.md5
    +run sha1sum freerdp-${TAG}.tar.gz > freerdp-${TAG}.tar.gz.sha1
    +run sha256sum freerdp-${TAG}.tar.gz > freerdp-${TAG}.tar.gz.sha256
    +
    +run zip freerdp-${TAG}.zip freerdp-${TAG}
    +run md5sum freerdp-${TAG}.zip > freerdp-${TAG}.zip.md5
    +run sha1sum freerdp-${TAG}.zip > freerdp-${TAG}.zip.sha1
    +run sha256sum freerdp-${TAG}.zip > freerdp-${TAG}.zip.sha256
    +popd
    +
    +run mv ${TMPDIR}/freerdp-${TAG}.tar.gz* .
    +run mv ${TMPDIR}/freerdp-${TAG}.zip* .
    +run rm -rf ${TMPDIR}
    +exit 0
    
  • server/proxy/modules/capture/cap_config.c+97 0 added
    @@ -0,0 +1,97 @@
    +/**
    + * FreeRDP: A Remote Desktop Protocol Implementation
    + * FreeRDP Proxy Server Session Capture Module
    + *
    + * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
    + *
    + * 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.
    + */
    +
    +#include <winpr/environment.h>
    +#include <freerdp/types.h>
    +#include <errno.h>
    +
    +#include "cap_config.h"
    +
    +BOOL capture_plugin_init_config(captureConfig* config)
    +{
    +	const char* name = "PROXY_CAPTURE_TARGET";
    +	char* tmp = NULL;
    +	DWORD nSize = GetEnvironmentVariableA(name, NULL, 0);
    +
    +	if (nSize > 0)
    +	{
    +		char* colon;
    +		int addrLen;
    +		unsigned long port;
    +
    +		tmp = (LPSTR)malloc(nSize);
    +		if (!tmp)
    +			return FALSE;
    +
    +		if (GetEnvironmentVariableA(name, tmp, nSize) != nSize - 1)
    +		{
    +			free(tmp);
    +			return FALSE;
    +		}
    +
    +		colon = strchr(tmp, ':');
    +
    +		if (!colon)
    +		{
    +			free(tmp);
    +			return FALSE;
    +		}
    +
    +		addrLen = (int)(colon - tmp);
    +		config->host = malloc(addrLen + 1);
    +		if (!config->host)
    +		{
    +			free(tmp);
    +			return FALSE;
    +		}
    +
    +		strncpy(config->host, tmp, addrLen);
    +		config->host[addrLen] = '\0';
    +
    +		port = strtoul(colon + 1, NULL, 0);
    +
    +		if ((errno != 0) || (port > UINT16_MAX))
    +		{
    +			free(config->host);
    +			config->host = NULL;
    +
    +			free(tmp);
    +			return FALSE;
    +		}
    +
    +		config->port = port;
    +		free(tmp);
    +	}
    +	else
    +	{
    +		config->host = _strdup("127.0.0.1");
    +		if (!config->host)
    +			return FALSE;
    +
    +		config->port = 8889;
    +	}
    +
    +	return TRUE;
    +}
    +
    +void capture_plugin_config_free_internal(captureConfig* config)
    +{
    +	free(config->host);
    +	config->host = NULL;
    +}
    
  • server/proxy/modules/capture/cap_config.h+29 0 added
    @@ -0,0 +1,29 @@
    +/**
    + * FreeRDP: A Remote Desktop Protocol Implementation
    + * FreeRDP Proxy Server Session Capture Module
    + *
    + * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
    + *
    + * 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.
    + */
    +
    +#include <freerdp/types.h>
    +
    +typedef struct capture_config
    +{
    +	UINT16 port;
    +	char* host;
    +} captureConfig;
    +
    +BOOL capture_plugin_init_config(captureConfig* config);
    +void capture_plugin_config_free_internal(captureConfig* config);
    
  • server/proxy/modules/capture/cap_main.c+288 0 added
    @@ -0,0 +1,288 @@
    +/**
    + * FreeRDP: A Remote Desktop Protocol Implementation
    + * FreeRDP Proxy Server Session Capture Module
    + *
    + * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
    + *
    + * 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.
    + */
    +
    +#define TAG MODULE_TAG("capture")
    +
    +#define PLUGIN_NAME "capture"
    +#define PLUGIN_DESC "stream egfx connections over tcp"
    +
    +#include <errno.h>
    +#include <winpr/image.h>
    +#include <freerdp/gdi/gdi.h>
    +#include <winpr/winsock.h>
    +
    +#include "pf_log.h"
    +#include "modules_api.h"
    +#include "pf_context.h"
    +#include "cap_config.h"
    +#include "cap_protocol.h"
    +
    +#define BUFSIZE 8092
    +
    +static proxyPluginsManager* g_plugins_manager = NULL;
    +static captureConfig config = { 0 };
    +
    +static SOCKET capture_plugin_init_socket(void)
    +{
    +	int status;
    +	int sockfd;
    +	struct sockaddr_in addr = { 0 };
    +	sockfd = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    +
    +	if (sockfd == -1)
    +		return -1;
    +
    +	addr.sin_family = AF_INET;
    +	addr.sin_port = htons(config.port);
    +	inet_pton(AF_INET, config.host, &(addr.sin_addr));
    +
    +	status = _connect(sockfd, (const struct sockaddr*)&addr, sizeof(addr));
    +	if (status < 0)
    +	{
    +		close(sockfd);
    +		return -1;
    +	}
    +
    +	return sockfd;
    +}
    +
    +static BOOL capture_plugin_send_data(SOCKET sockfd, const BYTE* buffer, size_t len)
    +{
    +	size_t chunk_len;
    +	int nsent;
    +
    +	if (!buffer)
    +		return FALSE;
    +
    +	while (len > 0)
    +	{
    +		chunk_len = len > BUFSIZE ? BUFSIZE : len;
    +		nsent = _send(sockfd, (const char*)buffer, chunk_len, 0);
    +		if (nsent == -1)
    +			return FALSE;
    +
    +		buffer += nsent;
    +		len -= nsent;
    +	}
    +
    +	return TRUE;
    +}
    +
    +static BOOL capture_plugin_send_packet(SOCKET sockfd, wStream* packet)
    +{
    +	size_t len;
    +	BYTE* buffer;
    +	BOOL result = FALSE;
    +
    +	if (!packet)
    +		return FALSE;
    +
    +	buffer = Stream_Buffer(packet);
    +	len = Stream_Capacity(packet);
    +
    +	if (!capture_plugin_send_data(sockfd, buffer, len))
    +	{
    +		WLog_ERR(TAG, "error while transmitting frame: errno=%d", errno);
    +		goto error;
    +	}
    +
    +	result = TRUE;
    +
    +error:
    +	Stream_Free(packet, TRUE);
    +	return result;
    +}
    +
    +static SOCKET capture_plugin_get_socket(proxyData* pdata)
    +{
    +	void* custom;
    +
    +	custom = g_plugins_manager->GetPluginData(PLUGIN_NAME, pdata);
    +	if (!custom)
    +		return -1;
    +
    +	return (SOCKET)custom;
    +}
    +
    +static BOOL capture_plugin_session_end(proxyData* pdata)
    +{
    +	SOCKET socket;
    +	BOOL ret;
    +	wStream* s;
    +
    +	socket = capture_plugin_get_socket(pdata);
    +	if (socket == -1)
    +		return FALSE;
    +
    +	s = capture_plugin_packet_new(SESSION_END_PDU_BASE_SIZE, MESSAGE_TYPE_SESSION_END);
    +	if (!s)
    +		return FALSE;
    +
    +	ret = capture_plugin_send_packet(socket, s);
    +
    +	closesocket(socket);
    +	return ret;
    +}
    +
    +static BOOL capture_plugin_send_frame(pClientContext* pc, SOCKET socket, const BYTE* buffer)
    +{
    +	size_t frame_size;
    +	BOOL ret = FALSE;
    +	wStream* s = NULL;
    +	BYTE* bmp_header = NULL;
    +	rdpSettings* settings = pc->context.settings;
    +
    +	frame_size = settings->DesktopWidth * settings->DesktopHeight * (settings->ColorDepth / 8);
    +	bmp_header = winpr_bitmap_construct_header(settings->DesktopWidth, settings->DesktopHeight,
    +	                                           settings->ColorDepth);
    +
    +	if (!bmp_header)
    +		return FALSE;
    +
    +	/*
    +	 * capture frame packet indicates a packet that contains a frame buffer. payload length is
    +	 * marked as 0, and receiving side must read `frame_size` bytes, a constant size of
    +	 * width*height*(bpp/8) from the socket, to receive the full frame buffer.
    +	 */
    +	s = capture_plugin_packet_new(0, MESSAGE_TYPE_CAPTURED_FRAME);
    +	if (!s)
    +		goto error;
    +
    +	if (!capture_plugin_send_packet(socket, s))
    +		goto error;
    +
    +	ret = capture_plugin_send_data(socket, bmp_header, WINPR_IMAGE_BMP_HEADER_LEN);
    +	if (!ret)
    +		goto error;
    +
    +	ret = capture_plugin_send_data(socket, buffer, frame_size);
    +
    +error:
    +	free(bmp_header);
    +	return ret;
    +}
    +
    +static BOOL capture_plugin_client_end_paint(proxyData* pdata)
    +{
    +	pClientContext* pc = pdata->pc;
    +	rdpGdi* gdi = pc->context.gdi;
    +	SOCKET socket;
    +
    +	if (gdi->suppressOutput)
    +		return TRUE;
    +
    +	if (gdi->primary->hdc->hwnd->ninvalid < 1)
    +		return TRUE;
    +
    +	socket = capture_plugin_get_socket(pdata);
    +	if (socket == -1)
    +		return FALSE;
    +
    +	if (!capture_plugin_send_frame(pc, socket, gdi->primary_buffer))
    +	{
    +		WLog_ERR(TAG, "capture_plugin_send_frame failed!");
    +		return FALSE;
    +	}
    +
    +	gdi->primary->hdc->hwnd->invalid->null = TRUE;
    +	gdi->primary->hdc->hwnd->ninvalid = 0;
    +	return TRUE;
    +}
    +
    +static BOOL capture_plugin_client_post_connect(proxyData* pdata)
    +{
    +	SOCKET socket;
    +	wStream* s;
    +	pClientContext* pc = pdata->pc;
    +	rdpSettings* settings = pc->context.settings;
    +
    +	socket = capture_plugin_init_socket();
    +	if (socket == -1)
    +	{
    +		WLog_ERR(TAG, "failed to establish a connection");
    +		return FALSE;
    +	}
    +
    +	g_plugins_manager->SetPluginData(PLUGIN_NAME, pdata, (void*)socket);
    +
    +	s = capture_plugin_create_session_info_packet(settings);
    +	if (!s)
    +		return FALSE;
    +
    +	return capture_plugin_send_packet(socket, s);
    +}
    +
    +static BOOL capture_plugin_server_post_connect(proxyData* pdata)
    +{
    +	pServerContext* ps = pdata->ps;
    +	proxyConfig* config = pdata->config;
    +	rdpSettings* settings = ps->context.settings;
    +
    +	if (!config->GFX || !config->SessionCapture)
    +	{
    +		WLog_ERR(TAG, "config options 'GFX' and 'SessionCapture' options must be set to true!");
    +		return FALSE;
    +	}
    +
    +	if (!settings->SupportGraphicsPipeline)
    +	{
    +		WLog_ERR(TAG, "session capture is only supported for GFX clients, denying connection");
    +		return FALSE;
    +	}
    +
    +	return TRUE;
    +}
    +
    +static BOOL capture_plugin_unload(void)
    +{
    +	capture_plugin_config_free_internal(&config);
    +	return TRUE;
    +}
    +
    +static proxyPlugin demo_plugin = {
    +	PLUGIN_NAME,                        /* name */
    +	PLUGIN_DESC,                        /* description */
    +	capture_plugin_unload,              /* PluginUnload */
    +	NULL,                               /* ClientPreConnect */
    +	capture_plugin_client_post_connect, /* ClientPostConnect */
    +	NULL,                               /* ClientLoginFailure */
    +	capture_plugin_client_end_paint,    /* ClientEndPaint */
    +	capture_plugin_server_post_connect, /* ServerPostConnect */
    +	NULL,                               /* ServerChannelsInit */
    +	NULL,                               /* ServerChannelsFree */
    +	capture_plugin_session_end,         /* Session End */
    +	NULL,                               /* KeyboardEvent */
    +	NULL,                               /* MouseEvent */
    +	NULL,                               /* ClientChannelData */
    +	NULL,                               /* ServerChannelData */
    +};
    +
    +BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager)
    +{
    +	g_plugins_manager = plugins_manager;
    +
    +	if (!capture_plugin_init_config(&config))
    +	{
    +		WLog_ERR(TAG, "failed to load config");
    +		return FALSE;
    +	}
    +
    +	WLog_INFO(TAG, "host: %s, port: %" PRIu16 "", config.host, config.port);
    +	return plugins_manager->RegisterPlugin(&demo_plugin);
    +}
    
  • server/proxy/modules/capture/cap_protocol.c+57 0 added
    @@ -0,0 +1,57 @@
    +/**
    + * FreeRDP: A Remote Desktop Protocol Implementation
    + * FreeRDP Proxy Server Session Capture Module
    + *
    + * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
    + *
    + * 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.
    + */
    +
    +#include "cap_protocol.h"
    +
    +wStream* capture_plugin_packet_new(UINT32 payload_size, UINT16 type)
    +{
    +	wStream* stream = Stream_New(NULL, HEADER_SIZE + payload_size);
    +
    +	if (!stream)
    +		return NULL;
    +
    +	Stream_Write_UINT32(stream, payload_size);
    +	Stream_Write_UINT16(stream, type);
    +	return stream;
    +}
    +
    +wStream* capture_plugin_create_session_info_packet(rdpSettings* settings)
    +{
    +	UINT16 username_length;
    +	wStream* s = NULL;
    +
    +	if (!settings || !settings->Username)
    +		return NULL;
    +
    +	username_length = strlen(settings->Username);
    +	if (username_length == 0)
    +		return NULL;
    +
    +	s = capture_plugin_packet_new(SESSION_INFO_PDU_BASE_SIZE + username_length,
    +	                              MESSAGE_TYPE_SESSION_INFO);
    +	if (!s)
    +		return NULL;
    +
    +	Stream_Write_UINT16(s, username_length);              /* username length (2 bytes) */
    +	Stream_Write(s, settings->Username, username_length); /* username */
    +	Stream_Write_UINT32(s, settings->DesktopWidth);       /* desktop width (4 bytes) */
    +	Stream_Write_UINT32(s, settings->DesktopHeight);      /* desktop height (4 bytes) */
    +	Stream_Write_UINT32(s, settings->ColorDepth);         /* color depth (4 bytes) */
    +	return s;
    +}
    
  • server/proxy/modules/capture/cap_protocol.h+35 0 added
    @@ -0,0 +1,35 @@
    +/**
    + * FreeRDP: A Remote Desktop Protocol Implementation
    + * FreeRDP Proxy Server Session Capture Module
    + *
    + * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
    + *
    + * 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.
    + */
    +
    +#include <winpr/stream.h>
    +#include <freerdp/settings.h>
    +
    +/* protocol message sizes */
    +#define HEADER_SIZE 6
    +#define SESSION_INFO_PDU_BASE_SIZE 14
    +#define SESSION_END_PDU_BASE_SIZE 0
    +#define CAPTURED_FRAME_PDU_BASE_SIZE 0
    +
    +/* protocol message types */
    +#define MESSAGE_TYPE_SESSION_INFO 1
    +#define MESSAGE_TYPE_CAPTURED_FRAME 2
    +#define MESSAGE_TYPE_SESSION_END 3
    +
    +wStream* capture_plugin_packet_new(UINT32 payload_size, UINT16 type);
    +wStream* capture_plugin_create_session_info_packet(rdpSettings* settings);
    
  • server/proxy/modules/capture/CMakeLists.txt+33 0 added
    @@ -0,0 +1,33 @@
    +#
    +# FreeRDP: A Remote Desktop Protocol Implementation
    +# FreeRDP Proxy Server Capture Module
    +#
    +# Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
    +#
    +# 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.
    +#
    +
    +set(PLUGIN_NAME "proxy-capture-plugin")
    +
    +add_library(${PLUGIN_NAME} MODULE
    +	cap_main.c
    +	cap_config.c
    +	cap_config.h
    +	cap_protocol.c
    +	cap_protocol.h
    +)
    +
    +set_target_properties(${PLUGIN_NAME} PROPERTIES PREFIX "")
    +set_target_properties(${PLUGIN_NAME} PROPERTIES NO_SONAME 1)
    +set_target_properties(${PLUGIN_NAME} PROPERTIES
    +LIBRARY_OUTPUT_DIRECTORY "${FREERDP_PROXY_PLUGINDIR}")
    
  • server/shadow/Mac/mac_shadow.c+8 3 modified
    @@ -370,6 +370,7 @@ static void (^mac_capture_stream_handler)(
       int width;
       int height;
       int nSrcStep;
    +  BOOL empty;
       BYTE* pSrcData;
       RECTANGLE_16 surfaceRect;
       const RECTANGLE_16* extents;
    @@ -381,14 +382,17 @@ static void (^mac_capture_stream_handler)(
       if (count < 1)
     	  return;
     
    +  EnterCriticalSection(&(surface->lock));
       mac_shadow_capture_get_dirty_region(subsystem);
       surfaceRect.left = 0;
       surfaceRect.top = 0;
       surfaceRect.right = surface->width;
       surfaceRect.bottom = surface->height;
       region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
    +  empty = region16_is_empty(&(surface->invalidRegion));
    +  LeaveCriticalSection(&(surface->lock));
     
    -  if (!region16_is_empty(&(surface->invalidRegion)))
    +  if (!empty)
       {
     	  extents = region16_extents(&(surface->invalidRegion));
     	  x = extents->left;
    @@ -410,13 +414,12 @@ static void (^mac_capture_stream_handler)(
     			                 pSrcData, PIXEL_FORMAT_BGRX32, nSrcStep, x, y, NULL,
     			                 FREERDP_FLIP_NONE);
     	  }
    +	  LeaveCriticalSection(&(surface->lock));
     
     	  IOSurfaceUnlock(frameSurface, kIOSurfaceLockReadOnly, NULL);
     	  ArrayList_Lock(server->clients);
     	  count = ArrayList_Count(server->clients);
    -	  EnterCriticalSection(&(surface->lock));
     	  shadow_subsystem_frame_update(&subsystem->common);
    -	  LeaveCriticalSection(&(surface->lock));
     
     	  if (count == 1)
     	  {
    @@ -430,7 +433,9 @@ static void (^mac_capture_stream_handler)(
     	  }
     
     	  ArrayList_Unlock(server->clients);
    +	  EnterCriticalSection(&(surface->lock));
     	  region16_clear(&(surface->invalidRegion));
    +	  LeaveCriticalSection(&(surface->lock));
       }
     
       if (status != kCGDisplayStreamFrameStatusFrameComplete)
    
  • server/shadow/shadow_client.c+3 2 modified
    @@ -1331,12 +1331,12 @@ static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GF
     	region16_copy(&invalidRegion, &(client->invalidRegion));
     	region16_clear(&(client->invalidRegion));
     	LeaveCriticalSection(&(client->lock));
    +
    +	EnterCriticalSection(&surface->lock);
     	rects = region16_rects(&(surface->invalidRegion), &numRects);
     
     	for (index = 0; index < numRects; index++)
    -	{
     		region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]);
    -	}
     
     	surfaceRect.left = 0;
     	surfaceRect.top = 0;
    @@ -1410,6 +1410,7 @@ static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GF
     	}
     
     out:
    +	LeaveCriticalSection(&surface->lock);
     	region16_uninit(&invalidRegion);
     	return ret;
     }
    
  • server/shadow/shadow_server.c+6 1 modified
    @@ -586,14 +586,19 @@ int shadow_server_start(rdpShadowServer* server)
     		char** list = CommandLineParseCommaSeparatedValuesEx(NULL, server->ipcSocket, &count);
     		if (!list || (count <= 1))
     		{
    -			free(list);
     			if (server->ipcSocket == NULL)
     			{
     				if (!open_port(server, NULL))
    +				{
    +					free(list);
     					return -1;
    +				}
     			}
     			else
    +			{
    +				free(list);
     				return -1;
    +			}
     		}
     
     		for (x = 1; x < count; x++)
    
  • server/shadow/X11/x11_shadow.c+69 70 modified
    @@ -128,90 +128,69 @@ static int x11_shadow_pam_conv(int num_msg, const struct pam_message** msg,
     	return pam_status;
     }
     
    -static int x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO* info)
    +static BOOL x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO* info)
     {
    -	if (PathFileExistsA("/etc/pam.d/lightdm"))
    -	{
    -		info->service_name = _strdup("lightdm");
    -	}
    -	else if (PathFileExistsA("/etc/pam.d/gdm"))
    -	{
    -		info->service_name = _strdup("gdm");
    -	}
    -	else if (PathFileExistsA("/etc/pam.d/xdm"))
    -	{
    -		info->service_name = _strdup("xdm");
    -	}
    -	else if (PathFileExistsA("/etc/pam.d/login"))
    -	{
    -		info->service_name = _strdup("login");
    -	}
    -	else if (PathFileExistsA("/etc/pam.d/sshd"))
    -	{
    -		info->service_name = _strdup("sshd");
    -	}
    -	else
    +	size_t x;
    +	const char* base = "/etc/pam.d";
    +	const char* hints[] = { "lightdm", "gdm", "xdm", "login", "sshd" };
    +
    +	for (x = 0; x < ARRAYSIZE(hints); x++)
     	{
    -		return -1;
    -	}
    +		char path[MAX_PATH];
    +		const char* hint = hints[x];
     
    -	if (!info->service_name)
    -		return -1;
    +		_snprintf(path, sizeof(path), "%s/%s", base, hint);
    +		if (PathFileExistsA(path))
    +		{
     
    -	return 1;
    +			info->service_name = _strdup(hint);
    +			return info->service_name != NULL;
    +		}
    +	}
    +	WLog_WARN(TAG, "Could not determine PAM service name");
    +	return FALSE;
     }
     
     static int x11_shadow_pam_authenticate(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
                                            const char* user, const char* domain, const char* password)
     {
     	int pam_status;
    -	SHADOW_PAM_AUTH_INFO* info;
    +	SHADOW_PAM_AUTH_INFO info = { 0 };
     	WINPR_UNUSED(subsystem);
     	WINPR_UNUSED(client);
    -	info = calloc(1, sizeof(SHADOW_PAM_AUTH_INFO));
     
    -	if (!info)
    -		return PAM_CONV_ERR;
    -
    -	if (x11_shadow_pam_get_service_name(info) < 0)
    -	{
    -		free(info);
    +	if (!x11_shadow_pam_get_service_name(&info))
     		return -1;
    -	}
     
    -	info->appdata.user = user;
    -	info->appdata.domain = domain;
    -	info->appdata.password = password;
    -	info->pamc.conv = &x11_shadow_pam_conv;
    -	info->pamc.appdata_ptr = &(info->appdata);
    -	pam_status = pam_start(info->service_name, 0, &(info->pamc), &(info->handle));
    +	info.appdata.user = user;
    +	info.appdata.domain = domain;
    +	info.appdata.password = password;
    +	info.pamc.conv = &x11_shadow_pam_conv;
    +	info.pamc.appdata_ptr = &info.appdata;
    +	pam_status = pam_start(info.service_name, 0, &info.pamc, &info.handle);
     
     	if (pam_status != PAM_SUCCESS)
     	{
    -		WLog_ERR(TAG, "pam_start failure: %s", pam_strerror(info->handle, pam_status));
    -		free(info);
    +		WLog_ERR(TAG, "pam_start failure: %s", pam_strerror(info.handle, pam_status));
     		return -1;
     	}
     
    -	pam_status = pam_authenticate(info->handle, 0);
    +	pam_status = pam_authenticate(info.handle, 0);
     
     	if (pam_status != PAM_SUCCESS)
     	{
    -		WLog_ERR(TAG, "pam_authenticate failure: %s", pam_strerror(info->handle, pam_status));
    -		free(info);
    +		WLog_ERR(TAG, "pam_authenticate failure: %s", pam_strerror(info.handle, pam_status));
     		return -1;
     	}
     
    -	pam_status = pam_acct_mgmt(info->handle, 0);
    +	pam_status = pam_acct_mgmt(info.handle, 0);
     
     	if (pam_status != PAM_SUCCESS)
     	{
    -		WLog_ERR(TAG, "pam_acct_mgmt failure: %s", pam_strerror(info->handle, pam_status));
    -		free(info);
    +		WLog_ERR(TAG, "pam_acct_mgmt failure: %s", pam_strerror(info.handle, pam_status));
     		return -1;
     	}
     
    -	free(info);
     	return 1;
     }
     
    @@ -757,6 +736,7 @@ static int x11_shadow_error_handler_for_capture(Display* display, XErrorEvent* e
     
     static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
     {
    +	int rc = 0;
     	int count;
     	int status;
     	int x, y;
    @@ -774,10 +754,13 @@ static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
     	if (count < 1)
     		return 1;
     
    +	EnterCriticalSection(&surface->lock);
     	surfaceRect.left = 0;
     	surfaceRect.top = 0;
     	surfaceRect.right = surface->width;
     	surfaceRect.bottom = surface->height;
    +	LeaveCriticalSection(&surface->lock);
    +
     	XLockDisplay(subsystem->display);
     	/*
     	 * Ignore BadMatch error during image capture. The screen size may be
    @@ -790,15 +773,26 @@ static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
     		image = subsystem->fb_image;
     		XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap,
     		          subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0);
    +
    +		EnterCriticalSection(&surface->lock);
     		status = shadow_capture_compare(surface->data, surface->scanline, surface->width,
     		                                surface->height, (BYTE*)&(image->data[surface->width * 4]),
     		                                image->bytes_per_line, &invalidRect);
    +		LeaveCriticalSection(&surface->lock);
     	}
     	else
     	{
    +		EnterCriticalSection(&surface->lock);
     		image = XGetImage(subsystem->display, subsystem->root_window, surface->x, surface->y,
     		                  surface->width, surface->height, AllPlanes, ZPixmap);
     
    +		if (image)
    +		{
    +			status = shadow_capture_compare(surface->data, surface->scanline, surface->width,
    +			                                surface->height, (BYTE*)image->data,
    +			                                image->bytes_per_line, &invalidRect);
    +		}
    +		LeaveCriticalSection(&surface->lock);
     		if (!image)
     		{
     			/*
    @@ -807,10 +801,6 @@ static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
     			 */
     			goto fail_capture;
     		}
    -
    -		status = shadow_capture_compare(surface->data, surface->scanline, surface->width,
    -		                                surface->height, (BYTE*)image->data, image->bytes_per_line,
    -		                                &invalidRect);
     	}
     
     	/* Restore the default error handler */
    @@ -820,25 +810,32 @@ static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
     
     	if (status)
     	{
    +		BOOL empty;
    +		EnterCriticalSection(&surface->lock);
     		region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
     		region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
    +		empty = region16_is_empty(&(surface->invalidRegion));
    +		LeaveCriticalSection(&surface->lock);
     
    -		if (!region16_is_empty(&(surface->invalidRegion)))
    +		if (!empty)
     		{
    +			BOOL success;
    +			EnterCriticalSection(&surface->lock);
     			extents = region16_extents(&(surface->invalidRegion));
     			x = extents->left;
     			y = extents->top;
     			width = extents->right - extents->left;
     			height = extents->bottom - extents->top;
    -
    -			if (!freerdp_image_copy(surface->data, surface->format, surface->scanline, x, y, width,
    -			                        height, (BYTE*)image->data, PIXEL_FORMAT_BGRX32,
    -			                        image->bytes_per_line, x, y, NULL, FREERDP_FLIP_NONE))
    +			success = freerdp_image_copy(surface->data, surface->format, surface->scanline, x, y,
    +			                             width, height, (BYTE*)image->data, PIXEL_FORMAT_BGRX32,
    +			                             image->bytes_per_line, x, y, NULL, FREERDP_FLIP_NONE);
    +			LeaveCriticalSection(&surface->lock);
    +			if (!success)
     				goto fail_capture;
     
     			// x11_shadow_blend_cursor(subsystem);
     			count = ArrayList_Count(server->clients);
    -			shadow_subsystem_frame_update((rdpShadowSubsystem*)subsystem);
    +			shadow_subsystem_frame_update(&subsystem->common);
     
     			if (count == 1)
     			{
    @@ -850,23 +847,25 @@ static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
     					    shadow_encoder_preferred_fps(client->encoder);
     			}
     
    +			EnterCriticalSection(&surface->lock);
     			region16_clear(&(surface->invalidRegion));
    +			LeaveCriticalSection(&surface->lock);
     		}
     	}
     
    -	if (!subsystem->use_xshm)
    -		XDestroyImage(image);
    -
    -	return 1;
    +	rc = 1;
     fail_capture:
    -
     	if (!subsystem->use_xshm && image)
     		XDestroyImage(image);
     
    -	XSetErrorHandler(NULL);
    -	XSync(subsystem->display, False);
    -	XUnlockDisplay(subsystem->display);
    -	return 0;
    +	if (rc != 1)
    +	{
    +		XSetErrorHandler(NULL);
    +		XSync(subsystem->display, False);
    +		XUnlockDisplay(subsystem->display);
    +	}
    +
    +	return rc;
     }
     
     static int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage* message)
    
  • uwac/libuwac/uwac-os.c+10 1 modified
    @@ -34,7 +34,7 @@
     #endif
     
     /* uClibc and uClibc-ng don't provide O_TMPFILE */
    -#ifndef O_TMPFILE
    +#if !defined(O_TMPFILE) && !defined(__FreeBSD__)
     #define O_TMPFILE (020000000 | O_DIRECTORY)
     #endif
     
    @@ -230,7 +230,16 @@ int uwac_create_anonymous_file(off_t size)
     		return -1;
     	}
     
    +#ifdef O_TMPFILE
     	fd = open(path, O_TMPFILE | O_RDWR | O_EXCL, 0600);
    +#else
    +	/*
    +	 * Some platforms (e.g. FreeBSD) won't support O_TMPFILE and can't
    +	 * reasonably emulate it at first blush.  Opt to make them rely on
    +	 * the create_tmpfile_cloexec() path instead.
    +	 */
    +	fd = -1;
    +#endif
     
     	if (fd < 0)
     	{
    
  • uwac/libuwac/uwac-priv.h+2 1 modified
    @@ -235,7 +235,8 @@ struct uwac_window
     
     	struct wl_region* opaque_region;
     	struct wl_region* input_region;
    -	UwacBuffer *drawingBuffer, *pendingBuffer;
    +	SSIZE_T drawingBufferIdx;
    +	SSIZE_T pendingBufferIdx;
     	struct wl_surface* surface;
     	struct wl_shell_surface* shell_surface;
     	struct xdg_surface* xdg_surface;
    
  • uwac/libuwac/uwac-window.c+59 27 modified
    @@ -136,13 +136,13 @@ static void xdg_handle_toplevel_configure(void* data, struct xdg_toplevel* xdg_t
     		{
     			assert(
     			    uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
    -			window->drawingBuffer = window->pendingBuffer = NULL;
    +			window->drawingBufferIdx = window->pendingBufferIdx = -1;
     			return;
     		}
     
    -		window->drawingBuffer = &window->buffers[0];
    -		if (window->pendingBuffer != NULL)
    -			window->pendingBuffer = window->drawingBuffer;
    +		window->drawingBufferIdx = 0;
    +		if (window->pendingBufferIdx != -1)
    +			window->pendingBufferIdx = window->drawingBufferIdx;
     	}
     	else
     	{
    @@ -219,13 +219,13 @@ static void ivi_handle_configure(void* data, struct ivi_surface* surface, int32_
     		{
     			assert(
     			    uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
    -			window->drawingBuffer = window->pendingBuffer = NULL;
    +			window->drawingBufferIdx = window->pendingBufferIdx = -1;
     			return;
     		}
     
    -		window->drawingBuffer = &window->buffers[0];
    -		if (window->pendingBuffer != NULL)
    -			window->pendingBuffer = window->drawingBuffer;
    +		window->drawingBufferIdx = 0;
    +		if (window->pendingBufferIdx != -1)
    +			window->pendingBufferIdx = window->drawingBufferIdx;
     	}
     	else
     	{
    @@ -277,13 +277,13 @@ static void shell_configure(void* data, struct wl_shell_surface* surface, uint32
     		{
     			assert(
     			    uwacErrorHandler(window->display, ret, "failed to reallocate a wayland buffers\n"));
    -			window->drawingBuffer = window->pendingBuffer = NULL;
    +			window->drawingBufferIdx = window->pendingBufferIdx = -1;
     			return;
     		}
     
    -		window->drawingBuffer = &window->buffers[0];
    -		if (window->pendingBuffer != NULL)
    -			window->pendingBuffer = window->drawingBuffer;
    +		window->drawingBufferIdx = 0;
    +		if (window->pendingBufferIdx != -1)
    +			window->pendingBufferIdx = window->drawingBufferIdx;
     	}
     	else
     	{
    @@ -364,15 +364,21 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32
     	return ret;
     }
     
    -static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w)
    +static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w, SSIZE_T* index)
     {
    -	int i, ret;
    +	SSIZE_T i;
    +	int ret;
    +
    +	if (index)
    +		*index = -1;
     
     	for (i = 0; i < w->nbuffers; i++)
     	{
     		if (!w->buffers[i].used)
     		{
     			w->buffers[i].used = true;
    +			if (index)
    +				*index = i;
     			return &w->buffers[i];
     		}
     	}
    @@ -386,6 +392,8 @@ static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w)
     	}
     
     	w->buffers[i].used = true;
    +	if (index)
    +		*index = i;
     	return &w->buffers[i];
     }
     
    @@ -457,7 +465,8 @@ UwacWindow* UwacCreateWindowShm(UwacDisplay* display, uint32_t width, uint32_t h
     	}
     
     	w->buffers[0].used = true;
    -	w->drawingBuffer = &w->buffers[0];
    +	w->drawingBufferIdx = 0;
    +	w->pendingBufferIdx = -1;
     	w->surface = wl_compositor_create_surface(display->compositor);
     
     	if (!w->surface)
    @@ -603,7 +612,16 @@ UwacReturnCode UwacWindowSetInputRegion(UwacWindow* window, uint32_t x, uint32_t
     
     void* UwacWindowGetDrawingBuffer(UwacWindow* window)
     {
    -	return window->drawingBuffer->data;
    +	UwacBuffer* buffer;
    +
    +	if (window->drawingBufferIdx < 0)
    +		return NULL;
    +
    +	buffer = &window->buffers[window->drawingBufferIdx];
    +	if (!buffer)
    +		return NULL;
    +
    +	return buffer->data;
     }
     
     static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t time);
    @@ -654,7 +672,7 @@ static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t tim
     	UwacFrameDoneEvent* event;
     
     	wl_callback_destroy(callback);
    -	window->pendingBuffer = NULL;
    +	window->pendingBufferIdx = -1;
     	event = (UwacFrameDoneEvent*)UwacDisplayNewEvent(window->display, UWAC_EVENT_FRAME_DONE);
     
     	if (event)
    @@ -677,13 +695,20 @@ UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, u
                                        uint32_t height)
     {
     	RECTANGLE_16 box;
    +	UwacBuffer* buf;
     
     	box.left = x;
     	box.top = y;
     	box.right = x + width;
     	box.bottom = y + height;
     
    -	UwacBuffer* buf = window->drawingBuffer;
    +	if (window->drawingBufferIdx < 0)
    +		return UWAC_ERROR_INTERNAL;
    +
    +	buf = &window->buffers[window->drawingBufferIdx];
    +	if (!buf)
    +		return UWAC_ERROR_INTERNAL;
    +
     	if (!region16_union_rect(&buf->damage, &buf->damage, &box))
     		return UWAC_ERROR_INTERNAL;
     
    @@ -695,7 +720,7 @@ UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, u
     UwacReturnCode UwacWindowGetDrawingBufferGeometry(UwacWindow* window, UwacSize* geometry,
                                                       size_t* stride)
     {
    -	if (!window || !window->drawingBuffer)
    +	if (!window || (window->drawingBufferIdx < 0))
     		return UWAC_ERROR_INTERNAL;
     
     	if (geometry)
    @@ -712,22 +737,29 @@ UwacReturnCode UwacWindowGetDrawingBufferGeometry(UwacWindow* window, UwacSize*
     
     UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window, bool copyContentForNextFrame)
     {
    -	UwacBuffer* drawingBuffer = window->drawingBuffer;
    +	UwacBuffer* currentDrawingBuffer;
    +	UwacBuffer* nextDrawingBuffer;
    +	UwacBuffer* pendingBuffer;
    +
    +	if (window->drawingBufferIdx < 0)
    +		return UWAC_ERROR_INTERNAL;
    +
    +	currentDrawingBuffer = &window->buffers[window->drawingBufferIdx];
     
    -	if (window->pendingBuffer || !drawingBuffer->dirty)
    +	if ((window->pendingBufferIdx >= 0) || !currentDrawingBuffer->dirty)
     		return UWAC_SUCCESS;
     
    -	window->pendingBuffer = drawingBuffer;
    -	window->drawingBuffer = UwacWindowFindFreeBuffer(window);
    +	window->pendingBufferIdx = window->drawingBufferIdx;
    +	nextDrawingBuffer = UwacWindowFindFreeBuffer(window, &window->drawingBufferIdx);
    +	pendingBuffer = &window->buffers[window->pendingBufferIdx];
     
    -	if (!window->drawingBuffer)
    +	if ((!nextDrawingBuffer) || (window->drawingBufferIdx < 0))
     		return UWAC_ERROR_NOMEMORY;
     
     	if (copyContentForNextFrame)
    -		memcpy(window->drawingBuffer->data, window->pendingBuffer->data,
    -		       window->stride * window->height);
    +		memcpy(nextDrawingBuffer->data, pendingBuffer->data, window->stride * window->height);
     
    -	UwacSubmitBufferPtr(window, drawingBuffer);
    +	UwacSubmitBufferPtr(window, pendingBuffer);
     	return UWAC_SUCCESS;
     }
     
    
  • winpr/CMakeLists.txt+1 1 modified
    @@ -51,7 +51,7 @@ if (NOT WIN32)
     endif()
     
     # Soname versioning
    -set(RAW_VERSION_STRING "2.1.1")
    +set(RAW_VERSION_STRING "2.1.2")
     if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
     	file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
     elseif(USE_VERSION_FROM_GIT_TAG)
    
  • winpr/include/winpr/image.h+3 0 modified
    @@ -66,6 +66,8 @@ typedef struct _WINPR_BITMAP_CORE_HEADER WINPR_BITMAP_CORE_HEADER;
     #define WINPR_IMAGE_BITMAP 0
     #define WINPR_IMAGE_PNG 1
     
    +#define WINPR_IMAGE_BMP_HEADER_LEN 54
    +
     struct _wImage
     {
     	int type;
    @@ -85,6 +87,7 @@ extern "C"
     
     	WINPR_API int winpr_bitmap_write(const char* filename, const BYTE* data, int width, int height,
     	                                 int bpp);
    +	WINPR_API BYTE* winpr_bitmap_construct_header(int width, int height, int bpp);
     
     	WINPR_API int winpr_image_write(wImage* image, const char* filename);
     	WINPR_API int winpr_image_read(wImage* image, const char* filename);
    
  • winpr/libwinpr/sspicli/sspicli.c+9 4 modified
    @@ -201,18 +201,23 @@ BOOL LogonUserExW(LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword
     BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
     {
     	size_t length;
    -	char* login;
    +	char login[MAX_PATH];
     
     	switch (NameFormat)
     	{
     		case NameSamCompatible:
    -			login = getlogin();
    +#ifndef getlogin_r
    +			strncpy(login, getlogin(), sizeof(login));
    +#else
    +			if (getlogin_r(login, sizeof(login)) != 0)
    +				return FALSE;
    +#endif
     			length = strlen(login);
     
     			if (*nSize >= length)
     			{
     				CopyMemory(lpNameBuffer, login, length + 1);
    -				return 1;
    +				return TRUE;
     			}
     			else
     			{
    @@ -235,7 +240,7 @@ BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG
     			break;
     	}
     
    -	return 0;
    +	return FALSE;
     }
     
     BOOL GetUserNameExW(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
    
  • winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c+129 46 modified
    @@ -39,13 +39,50 @@
     #include "../../log.h"
     #define TAG WINPR_TAG("sspi.NTLM")
     
    -static const char* const AV_PAIR_STRINGS[] = {
    -	"MsvAvEOL",           "MsvAvNbComputerName", "MsvAvNbDomainName", "MsvAvDnsComputerName",
    -	"MsvAvDnsDomainName", "MsvAvDnsTreeName",    "MsvAvFlags",        "MsvAvTimestamp",
    -	"MsvAvRestrictions",  "MsvAvTargetName",     "MsvChannelBindings"
    -};
    +static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset);
     
    -static BOOL ntlm_av_pair_check(NTLM_AV_PAIR* pAvPair, size_t cbAvPair);
    +static BOOL ntlm_av_pair_check_data(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair, size_t size)
    +{
    +	size_t offset;
    +	if (!pAvPair || cbAvPair < sizeof(NTLM_AV_PAIR) + size)
    +		return FALSE;
    +	if (!ntlm_av_pair_get_next_offset(pAvPair, cbAvPair, &offset))
    +		return FALSE;
    +	return cbAvPair >= offset;
    +}
    +
    +static const char* get_av_pair_string(UINT16 pair)
    +{
    +	switch (pair)
    +	{
    +		case MsvAvEOL:
    +			return "MsvAvEOL";
    +		case MsvAvNbComputerName:
    +			return "MsvAvNbComputerName";
    +		case MsvAvNbDomainName:
    +			return "MsvAvNbDomainName";
    +		case MsvAvDnsComputerName:
    +			return "MsvAvDnsComputerName";
    +		case MsvAvDnsDomainName:
    +			return "MsvAvDnsDomainName";
    +		case MsvAvDnsTreeName:
    +			return "MsvAvDnsTreeName";
    +		case MsvAvFlags:
    +			return "MsvAvFlags";
    +		case MsvAvTimestamp:
    +			return "MsvAvTimestamp";
    +		case MsvAvSingleHost:
    +			return "MsvAvSingleHost";
    +		case MsvAvTargetName:
    +			return "MsvAvTargetName";
    +		case MsvChannelBindings:
    +			return "MsvChannelBindings";
    +		default:
    +			return "UNKNOWN";
    +	}
    +}
    +
    +static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair);
     static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvPairList);
     
     static INLINE void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id)
    @@ -70,13 +107,19 @@ static BOOL ntlm_av_pair_list_init(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairLis
     	return TRUE;
     }
     
    -static INLINE UINT16 ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair)
    +static INLINE BOOL ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair, size_t size, UINT16* pair)
     {
     	UINT16 AvId;
    +	if (!pAvPair || !pair)
    +		return FALSE;
    +
    +	if (size < sizeof(NTLM_AV_PAIR))
    +		return FALSE;
     
     	Data_Read_UINT16(&pAvPair->AvId, AvId);
     
    -	return AvId;
    +	*pair = AvId;
    +	return TRUE;
     }
     
     ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
    @@ -91,17 +134,24 @@ ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
     	return ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR);
     }
     
    -static INLINE SIZE_T ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair)
    +static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pAvLen)
     {
     	UINT16 AvLen;
    +	if (!pAvPair)
    +		return FALSE;
    +
    +	if (size < sizeof(NTLM_AV_PAIR))
    +		return FALSE;
     
     	Data_Read_UINT16(&pAvPair->AvLen, AvLen);
     
    -	return AvLen;
    +	*pAvLen = AvLen;
    +	return TRUE;
     }
     
     void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
     {
    +	UINT16 pair;
     	size_t cbAvPair = cbAvPairList;
     	NTLM_AV_PAIR* pAvPair = pAvPairList;
     
    @@ -110,13 +160,13 @@ void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList)
     
     	WLog_INFO(TAG, "AV_PAIRs =");
     
    -	while (pAvPair && ntlm_av_pair_get_id(pAvPair) != MsvAvEOL)
    +	while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL))
     	{
    -		WLog_INFO(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "",
    -		          AV_PAIR_STRINGS[ntlm_av_pair_get_id(pAvPair)], ntlm_av_pair_get_id(pAvPair),
    -		          ntlm_av_pair_get_len(pAvPair));
    -		winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair),
    -		              ntlm_av_pair_get_len(pAvPair));
    +		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);
     
     		pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair);
     	}
    @@ -133,16 +183,21 @@ PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair)
     	return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR);
     }
     
    -static size_t ntlm_av_pair_get_next_offset(NTLM_AV_PAIR* pAvPair)
    +static BOOL ntlm_av_pair_get_next_offset(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pOffset)
     {
    -	return ntlm_av_pair_get_len(pAvPair) + sizeof(NTLM_AV_PAIR);
    +	size_t avLen;
    +	if (!pOffset)
    +		return FALSE;
    +
    +	if (!ntlm_av_pair_get_len(pAvPair, size, &avLen))
    +		return FALSE;
    +	*pOffset = avLen + sizeof(NTLM_AV_PAIR);
    +	return TRUE;
     }
     
    -static BOOL ntlm_av_pair_check(NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
    +static BOOL ntlm_av_pair_check(const NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
     {
    -	if (!pAvPair || cbAvPair < sizeof(NTLM_AV_PAIR))
    -		return FALSE;
    -	return cbAvPair >= ntlm_av_pair_get_next_offset(pAvPair);
    +	return ntlm_av_pair_check_data(pAvPair, cbAvPair, 0);
     }
     
     static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair)
    @@ -154,24 +209,25 @@ static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPair, size_t* pcbAvPair)
     	if (!ntlm_av_pair_check(pAvPair, *pcbAvPair))
     		return NULL;
     
    -	offset = ntlm_av_pair_get_next_offset(pAvPair);
    +	if (!ntlm_av_pair_get_next_offset(pAvPair, *pcbAvPair, &offset))
    +		return NULL;
    +
     	*pcbAvPair -= offset;
     	return (NTLM_AV_PAIR*)((PBYTE)pAvPair + offset);
     }
     
     NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId,
                                    size_t* pcbAvPairListRemaining)
     {
    +	UINT16 id;
     	size_t cbAvPair = cbAvPairList;
     	NTLM_AV_PAIR* pAvPair = pAvPairList;
     
     	if (!ntlm_av_pair_check(pAvPair, cbAvPair))
     		pAvPair = NULL;
     
    -	while (pAvPair)
    +	while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &id))
     	{
    -		UINT16 id = ntlm_av_pair_get_id(pAvPair);
    -
     		if (id == AvId)
     			break;
     		if (id == MsvAvEOL)
    @@ -218,11 +274,20 @@ static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTL
     static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList,
                                       NTLM_AV_PAIR* pAvPair, size_t cbAvPair)
     {
    +	UINT16 pair;
    +	size_t avLen;
    +
     	if (!ntlm_av_pair_check(pAvPair, cbAvPair))
     		return FALSE;
     
    -	return ntlm_av_pair_add(pAvPairList, cbAvPairList, ntlm_av_pair_get_id(pAvPair),
    -	                        ntlm_av_pair_get_value_pointer(pAvPair), ntlm_av_pair_get_len(pAvPair));
    +	if (!ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair))
    +		return FALSE;
    +
    +	if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen))
    +		return FALSE;
    +
    +	return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair,
    +	                        ntlm_av_pair_get_value_pointer(pAvPair), avLen);
     }
     
     static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
    @@ -500,32 +565,47 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
     
     	if (AvNbDomainName)
     	{
    +		size_t avLen;
    +		if (!ntlm_av_pair_get_len(AvNbDomainName, cbAvNbDomainName, &avLen))
    +			goto fail;
     		AvPairsCount++; /* MsvAvNbDomainName */
    -		AvPairsValueLength += ntlm_av_pair_get_len(AvNbDomainName);
    +		AvPairsValueLength += avLen;
     	}
     
     	if (AvNbComputerName)
     	{
    +		size_t avLen;
    +		if (!ntlm_av_pair_get_len(AvNbComputerName, cbAvNbComputerName, &avLen))
    +			goto fail;
     		AvPairsCount++; /* MsvAvNbComputerName */
    -		AvPairsValueLength += ntlm_av_pair_get_len(AvNbComputerName);
    +		AvPairsValueLength += avLen;
     	}
     
     	if (AvDnsDomainName)
     	{
    +		size_t avLen;
    +		if (!ntlm_av_pair_get_len(AvDnsDomainName, cbAvDnsDomainName, &avLen))
    +			goto fail;
     		AvPairsCount++; /* MsvAvDnsDomainName */
    -		AvPairsValueLength += ntlm_av_pair_get_len(AvDnsDomainName);
    +		AvPairsValueLength += avLen;
     	}
     
     	if (AvDnsComputerName)
     	{
    +		size_t avLen;
    +		if (!ntlm_av_pair_get_len(AvDnsComputerName, cbAvDnsComputerName, &avLen))
    +			goto fail;
     		AvPairsCount++; /* MsvAvDnsComputerName */
    -		AvPairsValueLength += ntlm_av_pair_get_len(AvDnsComputerName);
    +		AvPairsValueLength += avLen;
     	}
     
     	if (AvDnsTreeName)
     	{
    +		size_t avLen;
    +		if (!ntlm_av_pair_get_len(AvDnsTreeName, cbAvDnsTreeName, &avLen))
    +			goto fail;
     		AvPairsCount++; /* MsvAvDnsTreeName */
    -		AvPairsValueLength += ntlm_av_pair_get_len(AvDnsTreeName);
    +		AvPairsValueLength += avLen;
     	}
     
     	AvPairsCount++; /* MsvAvTimestamp */
    @@ -572,54 +652,54 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
     		size += 8; /* unknown 8-byte padding */
     
     	if (!sspi_SecBufferAlloc(&context->AuthenticateTargetInfo, size))
    -		return -1;
    +		goto fail;
     
     	AuthenticateTargetInfo = (NTLM_AV_PAIR*)context->AuthenticateTargetInfo.pvBuffer;
     	cbAuthenticateTargetInfo = context->AuthenticateTargetInfo.cbBuffer;
     
     	if (!ntlm_av_pair_list_init(AuthenticateTargetInfo, cbAuthenticateTargetInfo))
    -		return -1;
    +		goto fail;
     
     	if (AvNbDomainName)
     	{
     		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvNbDomainName,
     		                           cbAvNbDomainName))
    -			return -1;
    +			goto fail;
     	}
     
     	if (AvNbComputerName)
     	{
     		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
     		                           AvNbComputerName, cbAvNbComputerName))
    -			return -1;
    +			goto fail;
     	}
     
     	if (AvDnsDomainName)
     	{
     		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
     		                           AvDnsDomainName, cbAvDnsDomainName))
    -			return -1;
    +			goto fail;
     	}
     
     	if (AvDnsComputerName)
     	{
     		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo,
     		                           AvDnsComputerName, cbAvDnsComputerName))
    -			return -1;
    +			goto fail;
     	}
     
     	if (AvDnsTreeName)
     	{
     		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvDnsTreeName,
     		                           cbAvDnsTreeName))
    -			return -1;
    +			goto fail;
     	}
     
     	if (AvTimestamp)
     	{
     		if (!ntlm_av_pair_add_copy(AuthenticateTargetInfo, cbAuthenticateTargetInfo, AvTimestamp,
     		                           cbAvTimestamp))
    -			return -1;
    +			goto fail;
     	}
     
     	if (context->UseMIC)
    @@ -629,28 +709,28 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
     
     		if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvFlags,
     		                      (PBYTE)&flags, 4))
    -			return -1;
    +			goto fail;
     	}
     
     	if (context->SendSingleHostData)
     	{
     		if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost,
     		                      (PBYTE)&context->SingleHostData, context->SingleHostData.Size))
    -			return -1;
    +			goto fail;
     	}
     
     	if (!context->SuppressExtendedProtection)
     	{
     		if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvChannelBindings,
     		                      context->ChannelBindingsHash, 16))
    -			return -1;
    +			goto fail;
     
     		if (context->ServicePrincipalName.Length > 0)
     		{
     			if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvTargetName,
     			                      (PBYTE)context->ServicePrincipalName.Buffer,
     			                      context->ServicePrincipalName.Length))
    -				return -1;
    +				goto fail;
     		}
     	}
     
    @@ -660,10 +740,13 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
     		AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, cbChallengeTargetInfo, MsvAvEOL, NULL);
     
     		if (!AvEOL)
    -			return -1;
    +			goto fail;
     
     		ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR));
     	}
     
     	return 1;
    +fail:
    +	sspi_SecBufferFree(&context->AuthenticateTargetInfo);
    +	return -1;
     }
    
  • winpr/libwinpr/sspi/NTLM/ntlm.c+24 16 modified
    @@ -961,7 +961,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContex
     static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
                                                          PSecBufferDesc pMessage, ULONG MessageSeqNo)
     {
    -	int index;
    +	ULONG index;
     	int length;
     	void* data;
     	UINT32 SeqNo;
    @@ -977,12 +977,14 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULON
     	SeqNo = MessageSeqNo;
     	context = (NTLM_CONTEXT*)sspi_SecureHandleGetLowerPointer(phContext);
     
    -	for (index = 0; index < (int)pMessage->cBuffers; index++)
    +	for (index = 0; index < pMessage->cBuffers; index++)
     	{
    -		if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
    -			data_buffer = &pMessage->pBuffers[index];
    -		else if (pMessage->pBuffers[index].BufferType == SECBUFFER_TOKEN)
    -			signature_buffer = &pMessage->pBuffers[index];
    +		SecBuffer* cur = &pMessage->pBuffers[index];
    +
    +		if (cur->BufferType & SECBUFFER_DATA)
    +			data_buffer = cur;
    +		else if (cur->BufferType & SECBUFFER_TOKEN)
    +			signature_buffer = cur;
     	}
     
     	if (!data_buffer)
    @@ -1019,11 +1021,14 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULON
     	}
     
     	/* Encrypt message using with RC4, result overwrites original buffer */
    -
    -	if (context->confidentiality)
    -		winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*)data, (BYTE*)data_buffer->pvBuffer);
    -	else
    -		CopyMemory(data_buffer->pvBuffer, data, length);
    +	if ((data_buffer->BufferType & SECBUFFER_READONLY) == 0)
    +	{
    +		if (context->confidentiality)
    +			winpr_RC4_Update(context->SendRc4Seal, length, (BYTE*)data,
    +			                 (BYTE*)data_buffer->pvBuffer);
    +		else
    +			CopyMemory(data_buffer->pvBuffer, data, length);
    +	}
     
     #ifdef WITH_DEBUG_NTLM
     	WLog_DBG(TAG, "Data Buffer (length = %d)", length);
    @@ -1034,11 +1039,14 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULON
     	free(data);
     	/* RC4-encrypt first 8 bytes of digest */
     	winpr_RC4_Update(context->SendRc4Seal, 8, digest, checksum);
    -	signature = (BYTE*)signature_buffer->pvBuffer;
    -	/* Concatenate version, ciphertext and sequence number to build signature */
    -	Data_Write_UINT32(signature, version);
    -	CopyMemory(&signature[4], (void*)checksum, 8);
    -	Data_Write_UINT32(&signature[12], SeqNo);
    +	if ((signature_buffer->BufferType & SECBUFFER_READONLY) == 0)
    +	{
    +		signature = (BYTE*)signature_buffer->pvBuffer;
    +		/* Concatenate version, ciphertext and sequence number to build signature */
    +		Data_Write_UINT32(signature, version);
    +		CopyMemory(&signature[4], (void*)checksum, 8);
    +		Data_Write_UINT32(&signature[12], SeqNo);
    +	}
     	context->SendSeqNum++;
     #ifdef WITH_DEBUG_NTLM
     	WLog_DBG(TAG, "Signature (length = %" PRIu32 ")", signature_buffer->cbBuffer);
    
  • winpr/libwinpr/sspi/NTLM/ntlm_message.c+1 1 modified
    @@ -544,9 +544,9 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf
     	winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8);
     #endif
     	context->state = NTLM_STATE_AUTHENTICATE;
    -	ntlm_free_message_fields_buffer(&(message->TargetName));
     	status = SEC_I_CONTINUE_NEEDED;
     fail:
    +	ntlm_free_message_fields_buffer(&(message->TargetName));
     	Stream_Free(s, FALSE);
     	return status;
     }
    
  • winpr/libwinpr/sysinfo/sysinfo.c+4 2 modified
    @@ -213,11 +213,12 @@ void GetNativeSystemInfo(LPSYSTEM_INFO lpSystemInfo)
     void GetSystemTime(LPSYSTEMTIME lpSystemTime)
     {
     	time_t ct = 0;
    +	struct tm tres;
     	struct tm* stm = NULL;
     	WORD wMilliseconds = 0;
     	ct = time(NULL);
     	wMilliseconds = (WORD)(GetTickCount() % 1000);
    -	stm = gmtime(&ct);
    +	stm = gmtime_r(&ct, &tres);
     	ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
     
     	if (stm)
    @@ -242,11 +243,12 @@ BOOL SetSystemTime(CONST SYSTEMTIME* lpSystemTime)
     VOID GetLocalTime(LPSYSTEMTIME lpSystemTime)
     {
     	time_t ct = 0;
    +	struct tm tres;
     	struct tm* ltm = NULL;
     	WORD wMilliseconds = 0;
     	ct = time(NULL);
     	wMilliseconds = (WORD)(GetTickCount() % 1000);
    -	ltm = localtime(&ct);
    +	ltm = localtime_r(&ct, &tres);
     	ZeroMemory(lpSystemTime, sizeof(SYSTEMTIME));
     
     	if (ltm)
    
  • winpr/libwinpr/timezone/timezone.c+5 1 modified
    @@ -339,12 +339,16 @@ winpr_get_current_time_zone_rule(const TIME_ZONE_RULE_ENTRY* rules, UINT32 count
     DWORD GetTimeZoneInformation(LPTIME_ZONE_INFORMATION lpTimeZoneInformation)
     {
     	time_t t;
    +	struct tm tres;
     	struct tm* local_time;
     	TIME_ZONE_ENTRY* dtz;
     	LPTIME_ZONE_INFORMATION tz = lpTimeZoneInformation;
     	lpTimeZoneInformation->StandardBias = 0;
     	time(&t);
    -	local_time = localtime(&t);
    +	local_time = localtime_r(&t, &tres);
    +	if (!local_time)
    +		goto out_error;
    +
     	memset(tz, 0, sizeof(TIME_ZONE_INFORMATION));
     #ifdef HAVE_TM_GMTOFF
     	{
    
  • winpr/libwinpr/utils/collections/MessageQueue.c+3 2 modified
    @@ -100,12 +100,13 @@ BOOL MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message)
     	}
     
     	CopyMemory(&(queue->array[queue->tail]), message, sizeof(wMessage));
    -	queue->tail = (queue->tail + 1) % queue->capacity;
    -	queue->size++;
     
     	message = &(queue->array[queue->tail]);
     	message->time = GetTickCount64();
     
    +	queue->tail = (queue->tail + 1) % queue->capacity;
    +	queue->size++;
    +
     	if (queue->size > 0)
     		SetEvent(queue->event);
     
    
  • winpr/libwinpr/utils/image.c+39 23 modified
    @@ -100,24 +100,18 @@ static BOOL readBitmapInfoHeader(wStream* s, WINPR_BITMAP_INFO_HEADER* bi)
     	return TRUE;
     }
     
    -/**
    - * Refer to "Compressed Image File Formats: JPEG, PNG, GIF, XBM, BMP" book
    - */
    -
    -int winpr_bitmap_write(const char* filename, const BYTE* data, int width, int height, int bpp)
    +BYTE* winpr_bitmap_construct_header(int width, int height, int bpp)
     {
    -	FILE* fp;
     	WINPR_BITMAP_FILE_HEADER bf;
     	WINPR_BITMAP_INFO_HEADER bi;
    -	wStream* s;
    -	int ret = -1;
    -	fp = fopen(filename, "w+b");
    +	wStream s;
    +	BYTE* buffer = NULL;
     
    -	if (!fp)
    -	{
    -		WLog_ERR(TAG, "failed to open file %s", filename);
    -		return -1;
    -	}
    +	buffer = malloc(WINPR_IMAGE_BMP_HEADER_LEN);
    +	if (!buffer)
    +		return NULL;
    +
    +	Stream_StaticInit(&s, buffer, WINPR_IMAGE_BMP_HEADER_LEN);
     
     	bf.bfType[0] = 'B';
     	bf.bfType[1] = 'M';
    @@ -136,27 +130,49 @@ int winpr_bitmap_write(const char* filename, const BYTE* data, int width, int he
     	bi.biClrUsed = 0;
     	bi.biClrImportant = 0;
     	bi.biSize = sizeof(WINPR_BITMAP_INFO_HEADER);
    -	s = Stream_New(NULL, sizeof(WINPR_BITMAP_FILE_HEADER) + sizeof(WINPR_BITMAP_INFO_HEADER));
     
    -	if (!s)
    +	if (!writeBitmapFileHeader(&s, &bf))
     		goto fail;
     
    -	if (!writeBitmapFileHeader(s, &bf))
    +	if (!writeBitmapInfoHeader(&s, &bi))
     		goto fail;
     
    -	if (!writeBitmapInfoHeader(s, &bi))
    -		goto fail;
    +	return buffer;
    +fail:
    +	return NULL;
    +}
    +
    +/**
    + * Refer to "Compressed Image File Formats: JPEG, PNG, GIF, XBM, BMP" book
    + */
    +
    +int winpr_bitmap_write(const char* filename, const BYTE* data, int width, int height, int bpp)
    +{
    +	FILE* fp;
    +	BYTE* bmp_header = NULL;
    +	UINT32 img_size = width * height * (bpp / 8);
    +
    +	int ret = -1;
    +	fp = fopen(filename, "w+b");
    +
    +	if (!fp)
    +	{
    +		WLog_ERR(TAG, "failed to open file %s", filename);
    +		return -1;
    +	}
     
    -	Stream_SealLength(s);
    +	bmp_header = winpr_bitmap_construct_header(width, height, bpp);
    +	if (!bmp_header)
    +		return -1;
     
    -	if (fwrite(Stream_Buffer(s), Stream_Length(s), 1, fp) != 1 ||
    -	    fwrite((void*)data, bi.biSizeImage, 1, fp) != 1)
    +	if (fwrite(bmp_header, WINPR_IMAGE_BMP_HEADER_LEN, 1, fp) != 1 ||
    +	    fwrite((void*)data, img_size, 1, fp) != 1)
     		goto fail;
     
     	ret = 1;
     fail:
     	fclose(fp);
    -	Stream_Free(s, TRUE);
    +	free(bmp_header);
     	return ret;
     }
     
    
  • winpr/libwinpr/utils/trio/trio.c+3 3 modified
    @@ -2729,7 +2729,7 @@ TRIO_PRIVATE void TrioWriteString TRIO_ARGS5((self, string, flags, width, precis
                                                  trio_class_t* self, TRIO_CONST char* string,
                                                  trio_flags_t flags, int width, int precision)
     {
    -	int length;
    +	int length = 0;
     	int ch;
     
     	assert(VALID(self));
    @@ -2747,7 +2747,7 @@ TRIO_PRIVATE void TrioWriteString TRIO_ARGS5((self, string, flags, width, precis
     	}
     	else
     	{
    -		if (precision == 0)
    +		if (precision <= 0)
     		{
     			length = trio_length(string);
     		}
    @@ -4754,7 +4754,7 @@ TRIO_PUBLIC trio_pointer_t trio_register TRIO_ARGS2((callback, name), trio_callb
     		}
     
     		/* Bail out if namespace is too long */
    -		if (trio_length(name) >= MAX_USER_NAME)
    +		if (trio_length_max(name, MAX_USER_NAME) >= MAX_USER_NAME)
     			return NULL;
     
     		/* Bail out if namespace already is registered */
    
  • winpr/libwinpr/utils/trio/triostr.c+2 1 modified
    @@ -25,6 +25,7 @@
     #include <assert.h>
     #include <stdlib.h>
     #include <string.h>
    +#include <limits.h>
     #include <ctype.h>
     #include "triodef.h"
     #include "triostr.h"
    @@ -328,7 +329,7 @@ TRIO_PUBLIC_STRING void trio_destroy TRIO_ARGS1((string), char* string)
     
     TRIO_PUBLIC_STRING size_t trio_length TRIO_ARGS1((string), TRIO_CONST char* string)
     {
    -	return strlen(string);
    +	return trio_length_max(string, INT_MAX);
     }
     
     #endif
    
6d86e20e1e7c

Fixed double free

https://github.com/freerdp/freerdpakallabethMay 25, 2020via osv
1 file changed · +6 1
  • server/shadow/shadow_server.c+6 1 modified
    @@ -586,14 +586,19 @@ int shadow_server_start(rdpShadowServer* server)
     		char** list = CommandLineParseCommaSeparatedValuesEx(NULL, server->ipcSocket, &count);
     		if (!list || (count <= 1))
     		{
    -			free(list);
     			if (server->ipcSocket == NULL)
     			{
     				if (!open_port(server, NULL))
    +				{
    +					free(list);
     					return -1;
    +				}
     			}
     			else
    +			{
    +				free(list);
     				return -1;
    +			}
     		}
     
     		for (x = 1; x < count; x++)
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

8

News mentions

0

No linked articles in our index yet.