diff --git a/channels/cliprdr/client/CMakeLists.txt b/channels/cliprdr/client/CMakeLists.txt index 6081bee8c..4511e080c 100644 --- a/channels/cliprdr/client/CMakeLists.txt +++ b/channels/cliprdr/client/CMakeLists.txt @@ -21,7 +21,10 @@ set(${MODULE_PREFIX}_SRCS cliprdr_format.c cliprdr_format.h cliprdr_main.c - cliprdr_main.h) + cliprdr_main.h + ../cliprdr_common.h + ../cliprdr_common.c + ) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx") diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index 8a4282d37..151aef188 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -33,6 +33,7 @@ #include "cliprdr_main.h" #include "cliprdr_format.h" +#include "../cliprdr_common.h" /** * Function description @@ -41,13 +42,6 @@ */ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 dataLen, UINT16 msgFlags) { - UINT32 index; - size_t position; - BOOL asciiNames; - int formatNameLength; - char* szFormatName; - WCHAR* wszFormatName; - CLIPRDR_FORMAT* formats = NULL; CLIPRDR_FORMAT_LIST formatList; CliprdrClientContext* context = cliprdr_get_client_interface(cliprdr); UINT error = CHANNEL_RC_OK; @@ -58,165 +52,12 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data return ERROR_INTERNAL_ERROR; } - asciiNames = (msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; - formatList.msgType = CB_FORMAT_LIST; formatList.msgFlags = msgFlags; formatList.dataLen = dataLen; - index = 0; - formatList.numFormats = 0; - position = Stream_GetPosition(s); - - if (!formatList.dataLen) - { - /* empty format list */ - formatList.formats = NULL; - formatList.numFormats = 0; - } - else if (!cliprdr->useLongFormatNames) - { - formatList.numFormats = (dataLen / 36); - - if ((formatList.numFormats * 36) != dataLen) - { - WLog_ERR(TAG, "Invalid short format list length: %"PRIu32"", dataLen); - return ERROR_INTERNAL_ERROR; - } - - if (formatList.numFormats) - formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); - - if (!formats) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - formatList.formats = formats; - - while (dataLen) - { - Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ - dataLen -= 4; - - formats[index].formatName = NULL; - - /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing - * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters - * or 16 Unicode characters)" - * However, both Windows RDSH and mstsc violate this specs as seen in the following - * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] - * These are 16 unicode charaters - *without* terminating null ! - */ - - if (asciiNames) - { - szFormatName = (char*) Stream_Pointer(s); - - if (szFormatName[0]) - { - /* ensure null termination */ - formats[index].formatName = (char*) malloc(32 + 1); - if (!formats[index].formatName) - { - WLog_ERR(TAG, "malloc failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - CopyMemory(formats[index].formatName, szFormatName, 32); - formats[index].formatName[32] = '\0'; - } - } - else - { - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (wszFormatName[0]) - { - /* ConvertFromUnicode always returns a null-terminated - * string on success, even if the source string isn't. - */ - if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, - &(formats[index].formatName), 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert short clipboard format name"); - error = ERROR_INTERNAL_ERROR; - goto error_out; - } - } - } - - Stream_Seek(s, 32); - dataLen -= 32; - index++; - } - } - else - { - while (dataLen) - { - Stream_Seek(s, 4); /* formatId (4 bytes) */ - dataLen -= 4; - - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (!wszFormatName[0]) - formatNameLength = 0; - else - formatNameLength = _wcslen(wszFormatName); - - Stream_Seek(s, (formatNameLength + 1) * 2); - dataLen -= ((formatNameLength + 1) * 2); - - formatList.numFormats++; - } - - dataLen = formatList.dataLen; - Stream_SetPosition(s, position); - - if (formatList.numFormats) - formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, sizeof(CLIPRDR_FORMAT)); - - if (!formats) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - formatList.formats = formats; - - while (dataLen) - { - Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ - dataLen -= 4; - - formats[index].formatName = NULL; - - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (!wszFormatName[0]) - formatNameLength = 0; - else - formatNameLength = _wcslen(wszFormatName); - - if (formatNameLength) - { - if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, - &(formats[index].formatName), 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert long clipboard format name"); - error = ERROR_INTERNAL_ERROR; - goto error_out; - } - } - - Stream_Seek(s, (formatNameLength + 1) * 2); - dataLen -= ((formatNameLength + 1) * 2); - - index++; - } - } + if ((error = cliprdr_read_format_list(s, &formatList, cliprdr->useLongFormatNames))) + goto error_out; WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %"PRIu32"", formatList.numFormats); @@ -228,15 +69,7 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data } error_out: - if (formats) - { - for (index = 0; index < formatList.numFormats; index++) - { - free(formats[index].formatName); - } - - free(formats); - } + cliprdr_free_format_list(&formatList); return error; } @@ -293,7 +126,8 @@ UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN formatDataRequest.msgFlags = msgFlags; formatDataRequest.dataLen = dataLen; - Stream_Read_UINT32(s, formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */ + if ((error = cliprdr_read_format_data_request(s, &formatDataRequest))) + return error; context->lastRequestedFormatId = formatDataRequest.requestedFormatId; IFCALLRET(context->ServerFormatDataRequest, error, context, &formatDataRequest); @@ -325,10 +159,9 @@ UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE; formatDataResponse.msgFlags = msgFlags; formatDataResponse.dataLen = dataLen; - formatDataResponse.requestedFormatData = NULL; - if (dataLen) - formatDataResponse.requestedFormatData = (BYTE*) Stream_Pointer(s); + if ((error = cliprdr_read_format_data_response(s, &formatDataResponse))) + return error; IFCALLRET(context->ServerFormatDataResponse, error, context, &formatDataResponse); if (error) diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 351271e59..49f16e6d6 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -33,6 +33,7 @@ #include "cliprdr_main.h" #include "cliprdr_format.h" +#include "../cliprdr_common.h" #ifdef WITH_DEBUG_CLIPRDR static const char* const CB_MSG_TYPE_STRINGS[] = @@ -316,28 +317,12 @@ static UINT cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, return ERROR_INTERNAL_ERROR; } - if (Stream_GetRemainingLength(s) < 24) - { - WLog_ERR(TAG, "not enough remaining data"); - return ERROR_INVALID_DATA; - } - request.msgType = CB_FILECONTENTS_REQUEST; request.msgFlags = flags; request.dataLen = length; - request.haveClipDataId = FALSE; - Stream_Read_UINT32(s, request.streamId); /* streamId (4 bytes) */ - Stream_Read_UINT32(s, request.listIndex); /* listIndex (4 bytes) */ - Stream_Read_UINT32(s, request.dwFlags); /* dwFlags (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Read_UINT32(s, request.cbRequested); /* cbRequested (4 bytes) */ - if (Stream_GetRemainingLength(s) >= 4) - { - Stream_Read_UINT32(s, request.clipDataId); /* clipDataId (4 bytes) */ - request.haveClipDataId = TRUE; - } + if ((error = cliprdr_read_file_contents_request(s, &request))) + return error; IFCALLRET(context->ServerFileContentsRequest, error, context, &request); @@ -366,18 +351,13 @@ static UINT cliprdr_process_filecontents_response(cliprdrPlugin* cliprdr, return ERROR_INTERNAL_ERROR; } - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough remaining data"); - return ERROR_INVALID_DATA; - } - response.msgType = CB_FILECONTENTS_RESPONSE; response.msgFlags = flags; response.dataLen = length; - Stream_Read_UINT32(s, response.streamId); /* streamId (4 bytes) */ - response.cbRequested = length - 4; - response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ + + if ((error = cliprdr_read_file_contents_response(s, &response))) + return error; + IFCALLRET(context->ServerFileContentsResponse, error, context, &response); if (error) @@ -442,16 +422,13 @@ static UINT cliprdr_process_unlock_clipdata(cliprdrPlugin* cliprdr, wStream* s, return ERROR_INTERNAL_ERROR; } - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough remaining data"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_unlock_clipdata(s, &unlockClipboardData))) + return error; unlockClipboardData.msgType = CB_UNLOCK_CLIPDATA; unlockClipboardData.msgFlags = flags; unlockClipboardData.dataLen = length; - Stream_Read_UINT32(s, unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */ + IFCALLRET(context->ServerUnlockClipboardData, error, context, &unlockClipboardData); @@ -797,6 +774,7 @@ static UINT cliprdr_client_format_list_response(CliprdrClientContext* context, static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context, const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) { + UINT error = CHANNEL_RC_OK; wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4); @@ -807,11 +785,17 @@ static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, lockClipboardData->clipDataId); /* clipDataId (4 bytes) */ + if ((error = cliprdr_write_lock_clipdata(s, lockClipboardData))) + goto fail; + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientLockClipboardData: clipDataId: 0x%08"PRIX32"", lockClipboardData->clipDataId); return cliprdr_packet_send(cliprdr, s); + +fail: + Stream_Free(s, TRUE); + return error; } /** @@ -822,6 +806,7 @@ static UINT cliprdr_client_lock_clipboard_data(CliprdrClientContext* context, static UINT cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) { + UINT error = CHANNEL_RC_OK; wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4); @@ -832,11 +817,18 @@ static UINT cliprdr_client_unlock_clipboard_data(CliprdrClientContext* context, return ERROR_INTERNAL_ERROR; } + if ((error = cliprdr_write_unlock_clipdata(s, unlockClipboardData))) + goto fail; + Stream_Write_UINT32(s, unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */ WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientUnlockClipboardData: clipDataId: 0x%08"PRIX32"", unlockClipboardData->clipDataId); return cliprdr_packet_send(cliprdr, s); + +fail: + Stream_Free(s, TRUE); + return error; } /** @@ -897,8 +889,10 @@ static UINT cliprdr_client_format_data_response(CliprdrClientContext* context, static UINT cliprdr_client_file_contents_request(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { + UINT error = CHANNEL_RC_OK; wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; + s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, 28); if (!s) @@ -907,20 +901,17 @@ static UINT cliprdr_client_file_contents_request(CliprdrClientContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, fileContentsRequest->streamId); /* streamId (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->listIndex); /* listIndex (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->dwFlags); /* dwFlags (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->cbRequested); /* cbRequested (4 bytes) */ - - if (fileContentsRequest->haveClipDataId) - Stream_Write_UINT32(s, fileContentsRequest->clipDataId); /* clipDataId (4 bytes) */ + if ((error = cliprdr_write_file_contents_request(s, fileContentsRequest))) + goto fail; WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsRequest: streamId: 0x%08"PRIX32"", fileContentsRequest->streamId); return cliprdr_packet_send(cliprdr, s); + +fail: + Stream_Free(s, TRUE); + return error; } /** @@ -931,6 +922,7 @@ static UINT cliprdr_client_file_contents_request(CliprdrClientContext* context, static UINT cliprdr_client_file_contents_response(CliprdrClientContext* context, const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) { + UINT error = CHANNEL_RC_OK; wStream* s; cliprdrPlugin* cliprdr = (cliprdrPlugin*) context->handle; s = cliprdr_packet_new(CB_FILECONTENTS_RESPONSE, fileContentsResponse->msgFlags, @@ -942,18 +934,17 @@ static UINT cliprdr_client_file_contents_response(CliprdrClientContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, fileContentsResponse->streamId); /* streamId (4 bytes) */ - /** - * requestedFileContentsData: - * FILECONTENTS_SIZE: file size as UINT64 - * FILECONTENTS_RANGE: file data from requested range - */ - Stream_Write(s, fileContentsResponse->requestedData, - fileContentsResponse->cbRequested); + if ((error = cliprdr_write_file_contents_response(s, fileContentsResponse))) + goto fail; + WLog_Print(cliprdr->log, WLOG_DEBUG, "ClientFileContentsResponse: streamId: 0x%08"PRIX32"", fileContentsResponse->streamId); return cliprdr_packet_send(cliprdr, s); + +fail: + Stream_Free(s, TRUE); + return error; } /** diff --git a/channels/cliprdr/cliprdr_common.c b/channels/cliprdr/cliprdr_common.c new file mode 100644 index 000000000..469f0df1e --- /dev/null +++ b/channels/cliprdr/cliprdr_common.c @@ -0,0 +1,372 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Cliprdr common + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2019 Kobi Mizrachi + * + * 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 +#include +#include + +#define TAG CHANNELS_TAG("cliprdr.common") + +#include "cliprdr_common.h" + +static BOOL cliprdr_validate_file_contents_request(const CLIPRDR_FILE_CONTENTS_REQUEST* request) +{ + /* + * [MS-RDPECLIP] 2.2.5.3 File Contents Request PDU (CLIPRDR_FILECONTENTS_REQUEST). + * + * A request for the size of the file identified by the lindex field. The size MUST be + * returned as a 64-bit, unsigned integer. The cbRequested field MUST be set to + * 0x00000008 and both the nPositionLow and nPositionHigh fields MUST be + * set to 0x00000000. + */ + + if (request->dwFlags & FILECONTENTS_SIZE) + { + if (request->cbRequested != sizeof(UINT64)) + { + WLog_ERR(TAG, "[%s]: cbRequested must be %"PRIu32", got %"PRIu32"", __FUNCTION__, + sizeof(UINT64), request->cbRequested); + return FALSE; + } + + if (request->nPositionHigh != 0 || request->nPositionLow != 0) + { + WLog_ERR(TAG, "[%s]: nPositionHigh and nPositionLow must be set to 0", __FUNCTION__); + return FALSE; + } + } + + return TRUE; +} + +UINT cliprdr_write_file_contents_request(wStream* s, const CLIPRDR_FILE_CONTENTS_REQUEST* request) +{ + Stream_Write_UINT32(s, request->streamId); /* streamId (4 bytes) */ + Stream_Write_UINT32(s, request->listIndex); /* listIndex (4 bytes) */ + Stream_Write_UINT32(s, request->dwFlags); /* dwFlags (4 bytes) */ + Stream_Write_UINT32(s, request->nPositionLow); /* nPositionLow (4 bytes) */ + Stream_Write_UINT32(s, request->nPositionHigh); /* nPositionHigh (4 bytes) */ + Stream_Write_UINT32(s, request->cbRequested); /* cbRequested (4 bytes) */ + + if (request->haveClipDataId) + Stream_Write_UINT32(s, request->clipDataId); /* clipDataId (4 bytes) */ + + return CHANNEL_RC_OK; +} + +static INLINE UINT cliprdr_write_lock_unlock_clipdata(wStream* s, UINT32 clipDataId) +{ + Stream_Write_UINT32(s, clipDataId); + return CHANNEL_RC_OK; +} + +UINT cliprdr_write_lock_clipdata(wStream* s, const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +{ + return cliprdr_write_lock_unlock_clipdata(s, lockClipboardData->clipDataId); +} + +UINT cliprdr_write_unlock_clipdata(wStream* s, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + return cliprdr_write_lock_unlock_clipdata(s, unlockClipboardData->clipDataId); +} + +UINT cliprdr_write_file_contents_response(wStream* s, const CLIPRDR_FILE_CONTENTS_RESPONSE* response) +{ + Stream_Write_UINT32(s, response->streamId); /* streamId (4 bytes) */ + Stream_Write(s, response->requestedData, response->cbRequested); + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_unlock_clipdata(wStream* s, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "not enough remaining data"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */ + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_format_data_request(wStream* s, CLIPRDR_FORMAT_DATA_REQUEST* request) +{ + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "not enough data in stream!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, request->requestedFormatId); /* requestedFormatId (4 bytes) */ + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_format_data_response(wStream* s, CLIPRDR_FORMAT_DATA_RESPONSE* response) +{ + response->requestedFormatData = NULL; + + if (Stream_GetRemainingLength(s) < response->dataLen) + { + WLog_ERR(TAG, "not enough data in stream!"); + return ERROR_INVALID_DATA; + } + + if (response->dataLen) + response->requestedFormatData = Stream_Pointer(s); + + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_file_contents_request(wStream* s, CLIPRDR_FILE_CONTENTS_REQUEST* request) +{ + if (!cliprdr_validate_file_contents_request(request)) + return ERROR_BAD_ARGUMENTS; + + if (Stream_GetRemainingLength(s) < 24) + { + WLog_ERR(TAG, "not enough remaining data"); + return ERROR_INVALID_DATA; + } + + request->haveClipDataId = FALSE; + Stream_Read_UINT32(s, request->streamId); /* streamId (4 bytes) */ + Stream_Read_UINT32(s, request->listIndex); /* listIndex (4 bytes) */ + Stream_Read_UINT32(s, request->dwFlags); /* dwFlags (4 bytes) */ + Stream_Read_UINT32(s, request->nPositionLow); /* nPositionLow (4 bytes) */ + Stream_Read_UINT32(s, request->nPositionHigh); /* nPositionHigh (4 bytes) */ + Stream_Read_UINT32(s, request->cbRequested); /* cbRequested (4 bytes) */ + + if (Stream_GetRemainingLength(s) >= 4) + { + Stream_Read_UINT32(s, request->clipDataId); /* clipDataId (4 bytes) */ + request->haveClipDataId = TRUE; + } + + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_file_contents_response(wStream* s, CLIPRDR_FILE_CONTENTS_RESPONSE* response) +{ + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "not enough remaining data"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, response->streamId); /* streamId (4 bytes) */ + response->requestedData = Stream_Pointer(s); /* requestedFileContentsData */ + response->cbRequested = response->dataLen - 4; + return CHANNEL_RC_OK; +} + +UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL useLongFormatNames) +{ + UINT32 index; + size_t position; + BOOL asciiNames; + int formatNameLength; + char* szFormatName; + WCHAR* wszFormatName; + UINT32 dataLen = formatList->dataLen; + CLIPRDR_FORMAT* formats = NULL; + UINT error = CHANNEL_RC_OK; + + asciiNames = (formatList->msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; + + index = 0; + formatList->numFormats = 0; + position = Stream_GetPosition(s); + + if (!formatList->dataLen) + { + /* empty format list */ + formatList->formats = NULL; + formatList->numFormats = 0; + } + else if (!useLongFormatNames) + { + formatList->numFormats = (dataLen / 36); + + if ((formatList->numFormats * 36) != dataLen) + { + WLog_ERR(TAG, "Invalid short format list length: %"PRIu32"", dataLen); + return ERROR_INTERNAL_ERROR; + } + + if (formatList->numFormats) + formats = (CLIPRDR_FORMAT*) calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT)); + + if (!formats) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + formatList->formats = formats; + + while (dataLen) + { + Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ + dataLen -= 4; + + formats[index].formatName = NULL; + + /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing + * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters + * or 16 Unicode characters)" + * However, both Windows RDSH and mstsc violate this specs as seen in the following + * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] + * These are 16 unicode charaters - *without* terminating null ! + */ + + if (asciiNames) + { + szFormatName = (char*) Stream_Pointer(s); + + if (szFormatName[0]) + { + /* ensure null termination */ + formats[index].formatName = (char*) malloc(32 + 1); + if (!formats[index].formatName) + { + WLog_ERR(TAG, "malloc failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto error_out; + } + CopyMemory(formats[index].formatName, szFormatName, 32); + formats[index].formatName[32] = '\0'; + } + } + else + { + wszFormatName = (WCHAR*) Stream_Pointer(s); + + if (wszFormatName[0]) + { + /* ConvertFromUnicode always returns a null-terminated + * string on success, even if the source string isn't. + */ + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert short clipboard format name"); + error = ERROR_INTERNAL_ERROR; + goto error_out; + } + } + } + + Stream_Seek(s, 32); + dataLen -= 32; + index++; + } + } + else + { + while (dataLen) + { + Stream_Seek(s, 4); /* formatId (4 bytes) */ + dataLen -= 4; + + wszFormatName = (WCHAR*) Stream_Pointer(s); + + if (!wszFormatName[0]) + formatNameLength = 0; + else + formatNameLength = _wcslen(wszFormatName); + + Stream_Seek(s, (formatNameLength + 1) * 2); + dataLen -= ((formatNameLength + 1) * 2); + + formatList->numFormats++; + } + + dataLen = formatList->dataLen; + Stream_SetPosition(s, position); + + if (formatList->numFormats) + formats = (CLIPRDR_FORMAT*) calloc(formatList->numFormats, sizeof(CLIPRDR_FORMAT)); + + if (!formats) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + formatList->formats = formats; + + while (dataLen) + { + Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ + dataLen -= 4; + + formats[index].formatName = NULL; + + wszFormatName = (WCHAR*) Stream_Pointer(s); + + if (!wszFormatName[0]) + formatNameLength = 0; + else + formatNameLength = _wcslen(wszFormatName); + + if (formatNameLength) + { + if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, + &(formats[index].formatName), 0, NULL, NULL) < 1) + { + WLog_ERR(TAG, "failed to convert long clipboard format name"); + error = ERROR_INTERNAL_ERROR; + goto error_out; + } + } + + Stream_Seek(s, (formatNameLength + 1) * 2); + dataLen -= ((formatNameLength + 1) * 2); + + index++; + } + } + + return error; + +error_out: + cliprdr_free_format_list(formatList); + return error; +} + +void cliprdr_free_format_list(CLIPRDR_FORMAT_LIST* formatList) +{ + UINT index = 0; + + if (formatList == NULL) + return; + + if (formatList->formats) + { + for (index = 0; index < formatList->numFormats; index++) + { + free(formatList->formats[index].formatName); + } + + free(formatList->formats); + } +} diff --git a/channels/cliprdr/cliprdr_common.h b/channels/cliprdr/cliprdr_common.h new file mode 100644 index 000000000..b966ae618 --- /dev/null +++ b/channels/cliprdr/cliprdr_common.h @@ -0,0 +1,47 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Cliprdr common + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2019 Kobi Mizrachi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_RDPECLIP_COMMON_H +#define FREERDP_CHANNEL_RDPECLIP_COMMON_H + +#include +#include + +#include +#include + +FREERDP_LOCAL UINT cliprdr_write_lock_clipdata(wStream* s, const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData); +FREERDP_LOCAL UINT cliprdr_write_unlock_clipdata(wStream* s, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData); +FREERDP_LOCAL UINT cliprdr_write_file_contents_request(wStream* s, const CLIPRDR_FILE_CONTENTS_REQUEST* request); +FREERDP_LOCAL UINT cliprdr_write_file_contents_response(wStream* s, const CLIPRDR_FILE_CONTENTS_RESPONSE* response); + +FREERDP_LOCAL UINT cliprdr_read_lock_clipdata(wStream* s, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData); +FREERDP_LOCAL UINT cliprdr_read_unlock_clipdata(wStream* s, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData); +FREERDP_LOCAL UINT cliprdr_read_format_data_request(wStream* s, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest); +FREERDP_LOCAL UINT cliprdr_read_format_data_response(wStream* s, CLIPRDR_FORMAT_DATA_RESPONSE* response); +FREERDP_LOCAL UINT cliprdr_read_file_contents_request(wStream* s, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest); +FREERDP_LOCAL UINT cliprdr_read_file_contents_response(wStream* s, CLIPRDR_FILE_CONTENTS_RESPONSE* response); +FREERDP_LOCAL UINT cliprdr_read_format_list(wStream* s, CLIPRDR_FORMAT_LIST* formatList, BOOL useLongFormatNames); + +FREERDP_LOCAL void cliprdr_free_format_list(CLIPRDR_FORMAT_LIST* formatList); + +#endif /* FREERDP_CHANNEL_RDPECLIP_COMMON_H */ diff --git a/channels/cliprdr/server/CMakeLists.txt b/channels/cliprdr/server/CMakeLists.txt index 911c7a4ad..32ffbaa15 100644 --- a/channels/cliprdr/server/CMakeLists.txt +++ b/channels/cliprdr/server/CMakeLists.txt @@ -19,7 +19,10 @@ define_channel_server("cliprdr") set(${MODULE_PREFIX}_SRCS cliprdr_main.c - cliprdr_main.h) + cliprdr_main.h + ../cliprdr_common.h + ../cliprdr_common.c + ) add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c index 176db4d75..c4dc1a4f3 100644 --- a/channels/cliprdr/server/cliprdr_main.c +++ b/channels/cliprdr/server/cliprdr_main.c @@ -29,6 +29,7 @@ #include #include "cliprdr_main.h" +#include "../cliprdr_common.h" /** * Initialization Sequence\n @@ -384,6 +385,7 @@ static UINT cliprdr_server_format_list_response(CliprdrServerContext* context, static UINT cliprdr_server_lock_clipboard_data(CliprdrServerContext* context, const CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) { + UINT error = CHANNEL_RC_OK; wStream* s; CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; if (lockClipboardData->msgType != CB_LOCK_CLIPDATA) @@ -396,11 +398,16 @@ static UINT cliprdr_server_lock_clipboard_data(CliprdrServerContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, - lockClipboardData->clipDataId); /* clipDataId (4 bytes) */ + if ((error = cliprdr_write_lock_clipdata(s, lockClipboardData))) + goto fail; + WLog_DBG(TAG, "ServerLockClipboardData: clipDataId: 0x%08"PRIX32"", lockClipboardData->clipDataId); return cliprdr_server_packet_send(cliprdr, s); + +fail: + Stream_Free(s, TRUE); + return error; } /** @@ -411,6 +418,7 @@ static UINT cliprdr_server_lock_clipboard_data(CliprdrServerContext* context, static UINT cliprdr_server_unlock_clipboard_data(CliprdrServerContext* context, const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) { + UINT error = CHANNEL_RC_OK; wStream* s; CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; if (unlockClipboardData->msgType != CB_UNLOCK_CLIPDATA) @@ -424,11 +432,16 @@ static UINT cliprdr_server_unlock_clipboard_data(CliprdrServerContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, - unlockClipboardData->clipDataId); /* clipDataId (4 bytes) */ + if ((error = cliprdr_write_unlock_clipdata(s, unlockClipboardData))) + goto fail; + WLog_DBG(TAG, "ServerUnlockClipboardData: clipDataId: 0x%08"PRIX32"", unlockClipboardData->clipDataId); return cliprdr_server_packet_send(cliprdr, s); + +fail: + Stream_Free(s, TRUE); + return error; } /** @@ -496,6 +509,7 @@ static UINT cliprdr_server_format_data_response(CliprdrServerContext* context, static UINT cliprdr_server_file_contents_request(CliprdrServerContext* context, const CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) { + UINT error = CHANNEL_RC_OK; wStream* s; CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; @@ -510,21 +524,16 @@ static UINT cliprdr_server_file_contents_request(CliprdrServerContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, fileContentsRequest->streamId); /* streamId (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->listIndex); /* listIndex (4 bytes) */ - Stream_Write_UINT32(s, fileContentsRequest->dwFlags); /* dwFlags (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->cbRequested); /* cbRequested (4 bytes) */ - Stream_Write_UINT32(s, - fileContentsRequest->clipDataId); /* clipDataId (4 bytes) */ + if ((error = cliprdr_write_file_contents_request(s, fileContentsRequest))) + goto fail; + WLog_DBG(TAG, "ServerFileContentsRequest: streamId: 0x%08"PRIX32"", fileContentsRequest->streamId); return cliprdr_server_packet_send(cliprdr, s); + +fail: + Stream_Free(s, TRUE); + return error; } /** @@ -535,19 +544,15 @@ static UINT cliprdr_server_file_contents_request(CliprdrServerContext* context, static UINT cliprdr_server_file_contents_response(CliprdrServerContext* context, const CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) { + UINT error = CHANNEL_RC_OK; wStream* s; CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - UINT32 cbRequested = fileContentsResponse->cbRequested; if (fileContentsResponse->msgType != CB_FILECONTENTS_RESPONSE) WLog_WARN(TAG, "[%s] called with invalid type %08"PRIx32, __FUNCTION__, fileContentsResponse->msgType); - if (fileContentsResponse->dwFlags & FILECONTENTS_SIZE) - cbRequested = sizeof(UINT64); - - s = cliprdr_server_packet_new(CB_FILECONTENTS_RESPONSE, - fileContentsResponse->msgFlags, - 4 + cbRequested); + s = cliprdr_server_packet_new(CB_FILECONTENTS_RESPONSE, fileContentsResponse->msgFlags, + 4 + fileContentsResponse->cbRequested); if (!s) { @@ -555,17 +560,16 @@ static UINT cliprdr_server_file_contents_response(CliprdrServerContext* context, return ERROR_INTERNAL_ERROR; } - Stream_Write_UINT32(s, fileContentsResponse->streamId); /* streamId (4 bytes) */ - /** - * requestedFileContentsData: - * FILECONTENTS_SIZE: file size as UINT64 - * FILECONTENTS_RANGE: file data from requested range - */ - Stream_Write(s, fileContentsResponse->requestedData, - cbRequested); - WLog_DBG(TAG, "ServerFileContentsResponse: streamId: 0x%08"PRIX32"", + if ((error = cliprdr_write_file_contents_response(s, fileContentsResponse))) + goto fail; + + WLog_DBG(TAG, "ServerFileContentsResponse: streamId: 0x%08" PRIX32 "", fileContentsResponse->streamId); return cliprdr_server_packet_send(cliprdr, s); + +fail: + Stream_Free(s, TRUE); + return error; } /** @@ -734,166 +738,15 @@ static UINT cliprdr_server_receive_temporary_directory(CliprdrServerContext* static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wStream* s, const CLIPRDR_HEADER* header) { - UINT32 index; - UINT32 dataLen; - size_t position; - BOOL asciiNames; - char* szFormatName; - WCHAR* wszFormatName; - CLIPRDR_FORMAT* formats = NULL; CLIPRDR_FORMAT_LIST formatList; UINT error = CHANNEL_RC_OK; - dataLen = header->dataLen; - asciiNames = (header->msgFlags & CB_ASCII_NAMES) ? TRUE : FALSE; + formatList.msgType = CB_FORMAT_LIST; formatList.msgFlags = header->msgFlags; formatList.dataLen = header->dataLen; - index = 0; - formatList.numFormats = 0; - position = Stream_GetPosition(s); - if (!header->dataLen) - { - /* empty format list */ - formatList.formats = NULL; - formatList.numFormats = 0; - } - else if (!context->useLongFormatNames) - { - formatList.numFormats = (dataLen / 36); - - if ((formatList.numFormats * 36) != dataLen) - { - WLog_ERR(TAG, "Invalid short format list length: %"PRIu32"", dataLen); - return ERROR_INVALID_PARAMETER; - } - - if (formatList.numFormats) - formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, - sizeof(CLIPRDR_FORMAT)); - - if (!formats) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - formatList.formats = formats; - - while (dataLen) - { - Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ - dataLen -= 4; - formats[index].formatName = NULL; - - /* According to MS-RDPECLIP 2.2.3.1.1.1 formatName is "a 32-byte block containing - * the *null-terminated* name assigned to the Clipboard Format: (32 ASCII 8 characters - * or 16 Unicode characters)" - * However, both Windows RDSH and mstsc violate this specs as seen in the following - * example of a transferred short format name string: [R.i.c.h. .T.e.x.t. .F.o.r.m.a.t.] - * These are 16 unicode charaters - *without* terminating null ! - */ - - if (asciiNames) - { - szFormatName = (char*) Stream_Pointer(s); - - if (szFormatName[0]) - { - /* ensure null termination */ - formats[index].formatName = (char*) malloc(32 + 1); - CopyMemory(formats[index].formatName, szFormatName, 32); - formats[index].formatName[32] = '\0'; - } - } - else - { - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (wszFormatName[0]) - { - /* ConvertFromUnicode always returns a null-terminated - * string on success, even if the source string isn't. - */ - if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, 16, - &(formats[index].formatName), 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert short clipboard format name"); - error = ERROR_INVALID_DATA; - goto out; - } - } - } - - Stream_Seek(s, 32); - dataLen -= 32; - index++; - } - } - else - { - while (dataLen) - { - size_t formatNameLength; - Stream_Seek(s, 4); /* formatId (4 bytes) */ - dataLen -= 4; - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (!wszFormatName[0]) - formatNameLength = 0; - else - formatNameLength = _wcslen(wszFormatName); - - Stream_Seek(s, (formatNameLength + 1) * 2); - dataLen -= ((formatNameLength + 1) * 2); - formatList.numFormats++; - } - - dataLen = formatList.dataLen; - Stream_SetPosition(s, position); - - if (formatList.numFormats) - formats = (CLIPRDR_FORMAT*) calloc(formatList.numFormats, - sizeof(CLIPRDR_FORMAT)); - - if (!formats) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - formatList.formats = formats; - - while (dataLen) - { - size_t formatNameLength; - - Stream_Read_UINT32(s, formats[index].formatId); /* formatId (4 bytes) */ - dataLen -= 4; - formats[index].formatName = NULL; - wszFormatName = (WCHAR*) Stream_Pointer(s); - - if (!wszFormatName[0]) - formatNameLength = 0; - else - formatNameLength = _wcslen(wszFormatName); - - if (formatNameLength) - { - if (ConvertFromUnicode(CP_UTF8, 0, wszFormatName, -1, - &(formats[index].formatName), 0, NULL, NULL) < 1) - { - WLog_ERR(TAG, "failed to convert long clipboard format name"); - error = ERROR_INVALID_DATA; - goto out; - } - } - - Stream_Seek(s, (formatNameLength + 1) * 2); - dataLen -= ((formatNameLength + 1) * 2); - index++; - } - } + if ((error = cliprdr_read_format_list(s, &formatList, context->useLongFormatNames))) + goto out; WLog_DBG(TAG, "ClientFormatList: numFormats: %"PRIu32"", formatList.numFormats); @@ -903,13 +756,7 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, WLog_ERR(TAG, "ClientFormatList failed with error %"PRIu32"!", error); out: - - for (index = 0; index < formatList.numFormats; index++) - { - free(formatList.formats[index].formatName); - } - - free(formatList.formats); + cliprdr_free_format_list(&formatList); return error; } @@ -979,18 +826,14 @@ static UINT cliprdr_server_receive_unlock_clipdata(CliprdrServerContext* CLIPRDR_UNLOCK_CLIPBOARD_DATA unlockClipboardData; UINT error = CHANNEL_RC_OK; WLog_DBG(TAG, "CliprdrClientUnlockClipData"); + unlockClipboardData.msgType = CB_UNLOCK_CLIPDATA; unlockClipboardData.msgFlags = header->msgFlags; unlockClipboardData.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_unlock_clipdata(s, &unlockClipboardData))) + return error; - Stream_Read_UINT32(s, - unlockClipboardData.clipDataId); /* clipDataId (4 bytes) */ IFCALLRET(context->ClientUnlockClipboardData, error, context, &unlockClipboardData); @@ -1015,14 +858,9 @@ static UINT cliprdr_server_receive_format_data_request(CliprdrServerContext* formatDataRequest.msgFlags = header->msgFlags; formatDataRequest.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_format_data_request(s, &formatDataRequest))) + return error; - Stream_Read_UINT32(s, - formatDataRequest.requestedFormatId); /* requestedFormatId (4 bytes) */ context->lastRequestedFormatId = formatDataRequest.requestedFormatId; IFCALLRET(context->ClientFormatDataRequest, error, context, &formatDataRequest); @@ -1047,16 +885,9 @@ static UINT cliprdr_server_receive_format_data_response( formatDataResponse.msgType = CB_FORMAT_DATA_RESPONSE; formatDataResponse.msgFlags = header->msgFlags; formatDataResponse.dataLen = header->dataLen; - formatDataResponse.requestedFormatData = NULL; - if (header->dataLen) - formatDataResponse.requestedFormatData = Stream_Pointer(s); - - if (!Stream_SafeSeek(s, header->dataLen)) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_format_data_response(s, &formatDataResponse))) + return error; IFCALLRET(context->ClientFormatDataResponse, error, context, &formatDataResponse); @@ -1082,23 +913,8 @@ static UINT cliprdr_server_receive_filecontents_request( request.msgFlags = header->msgFlags; request.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 24) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } - - Stream_Read_UINT32(s, request.streamId); /* streamId (4 bytes) */ - Stream_Read_UINT32(s, request.listIndex); /* listIndex (4 bytes) */ - Stream_Read_UINT32(s, request.dwFlags); /* dwFlags (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionLow); /* nPositionLow (4 bytes) */ - Stream_Read_UINT32(s, request.nPositionHigh); /* nPositionHigh (4 bytes) */ - Stream_Read_UINT32(s, request.cbRequested); /* cbRequested (4 bytes) */ - - if (Stream_GetRemainingLength(s) < 4) /* clipDataId (4 bytes) optional */ - request.clipDataId = 0; - else - Stream_Read_UINT32(s, request.clipDataId); + if ((error = cliprdr_read_file_contents_request(s, &request))) + return error; IFCALLRET(context->ClientFileContentsRequest, error, context, &request); @@ -1119,19 +935,14 @@ static UINT cliprdr_server_receive_filecontents_response( CLIPRDR_FILE_CONTENTS_RESPONSE response; UINT error = CHANNEL_RC_OK; WLog_DBG(TAG, "CliprdrClientFileContentsResponse"); + response.msgType = CB_FILECONTENTS_RESPONSE; response.msgFlags = header->msgFlags; response.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough data in stream!"); - return ERROR_INVALID_DATA; - } + if ((error = cliprdr_read_file_contents_response(s, &response))) + return error; - Stream_Read_UINT32(s, response.streamId); /* streamId (4 bytes) */ - response.cbRequested = header->dataLen - 4; - response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ IFCALLRET(context->ClientFileContentsResponse, error, context, &response); if (error) diff --git a/client/Wayland/wlf_cliprdr.c b/client/Wayland/wlf_cliprdr.c index cfd2c06e0..44f3b4439 100644 --- a/client/Wayland/wlf_cliprdr.c +++ b/client/Wayland/wlf_cliprdr.c @@ -752,7 +752,6 @@ static UINT wlf_cliprdr_send_file_contents_failure(CliprdrClientContext* context CLIPRDR_FILE_CONTENTS_RESPONSE response = { 0 }; response.msgFlags = CB_RESPONSE_FAIL; response.streamId = fileContentsRequest->streamId; - response.dwFlags = fileContentsRequest->dwFlags; return context->ClientFileContentsResponse(context, &response); }