[channels,cliprdr] implement client clipboard direction filter

* Filter remote -> local or local -> remote clipboard depending on
  setting.
* Filter remote -> local or local -> remote file clipboard
  depending on setting.
This commit is contained in:
akallabeth 2023-05-09 12:51:01 +02:00 committed by Martin Fleisz
parent 7288680bdd
commit 98fb56b767
4 changed files with 205 additions and 2 deletions

View File

@ -26,6 +26,8 @@
#include <winpr/print.h>
#include <freerdp/types.h>
#include <freerdp/freerdp.h>
#include <freerdp/settings.h>
#include <freerdp/constants.h>
#include <freerdp/client/cliprdr.h>
@ -33,6 +35,70 @@
#include "cliprdr_format.h"
#include "../cliprdr_common.h"
static BOOL cliprdr_filter_server_format_list(CLIPRDR_FORMAT_LIST* list, const UINT32 mask)
{
const UINT32 all = CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES;
WINPR_ASSERT(list);
if ((mask & all) == all)
return TRUE;
if ((mask & CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES) != 0)
{
const CLIPRDR_FORMAT* files = NULL;
for (size_t x = 0; x < list->numFormats; x++)
{
CLIPRDR_FORMAT* format = &list->formats[x];
if (!format->formatName)
continue;
if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0)
files = format;
else
{
free(format->formatName);
format->formatName = NULL;
}
}
if (!files)
list->numFormats = 0;
else
{
list->numFormats = 1;
list->formats[0] = *files;
}
return TRUE;
}
if ((mask & CLIPRDR_FLAG_REMOTE_TO_LOCAL) != 0)
{
BOOL move = FALSE;
for (size_t x = 0; x < list->numFormats; x++)
{
CLIPRDR_FORMAT* format = &list->formats[x];
if (move)
{
CLIPRDR_FORMAT* last = &list->formats[x - 1];
*last = *format;
}
else if (!format->formatName)
continue;
else if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0)
{
move = TRUE;
free(format->formatName);
format->formatName = NULL;
}
}
if (move)
list->numFormats -= 1;
return TRUE;
}
return FALSE;
}
/**
* Function description
*
@ -52,6 +118,11 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
if ((error = cliprdr_read_format_list(s, &formatList, cliprdr->useLongFormatNames)))
goto error_out;
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
if (!cliprdr_filter_server_format_list(&formatList, mask))
goto error_out;
WLog_Print(cliprdr->log, WLOG_DEBUG, "ServerFormatList: numFormats: %" PRIu32 "",
formatList.numFormats);
@ -112,6 +183,13 @@ UINT cliprdr_process_format_data_request(cliprdrPlugin* cliprdr, wStream* s, UIN
if ((error = cliprdr_read_format_data_request(s, &formatDataRequest)))
return error;
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
if ((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) == 0)
{
return cliprdr_send_error_response(cliprdr, CB_FORMAT_DATA_RESPONSE);
}
context->lastRequestedFormatId = formatDataRequest.requestedFormatId;
IFCALLRET(context->ServerFormatDataRequest, error, context, &formatDataRequest);
if (error)
@ -141,6 +219,15 @@ UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI
if ((error = cliprdr_read_format_data_response(s, &formatDataResponse)))
return error;
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
if ((mask & (CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES)) == 0)
{
WLog_WARN(TAG,
"Received ServerFormatDataResponse but remote -> local clipboard is disabled");
return CHANNEL_RC_OK;
}
IFCALLRET(context->ServerFormatDataResponse, error, context, &formatDataResponse);
if (error)
WLog_ERR(TAG, "ServerFormatDataResponse failed with error %" PRIu32 "!", error);

View File

@ -38,6 +38,8 @@
#include "cliprdr_format.h"
#include "../cliprdr_common.h"
const char* type_FileGroupDescriptorW = "FileGroupDescriptorW";
static const char* CB_MSG_TYPE_STRINGS(UINT32 type)
{
switch (type)
@ -124,6 +126,18 @@ static UINT cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s)
return status;
}
UINT cliprdr_send_error_response(cliprdrPlugin* cliprdr, UINT16 type)
{
wStream* s = cliprdr_packet_new(type, CB_RESPONSE_FAIL, 0);
if (!s)
{
WLog_ERR(TAG, "cliprdr_packet_new failed!");
return ERROR_OUTOFMEMORY;
}
return cliprdr_packet_send(cliprdr, s);
}
static void cliprdr_print_general_capability_flags(UINT32 flags)
{
WLog_DBG(TAG, "generalFlags (0x%08" PRIX32 ") {", flags);
@ -324,6 +338,13 @@ static UINT cliprdr_process_filecontents_request(cliprdrPlugin* cliprdr, wStream
if ((error = cliprdr_read_file_contents_request(s, &request)))
return error;
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
if ((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) == 0)
{
WLog_WARN(TAG, "local -> remote file copy disabled, ignoring request");
return cliprdr_send_error_response(cliprdr, CB_FILECONTENTS_RESPONSE);
}
IFCALLRET(context->ServerFileContentsRequest, error, context, &request);
if (error)
@ -639,6 +660,66 @@ static UINT cliprdr_temp_directory(CliprdrClientContext* context,
return cliprdr_packet_send(cliprdr, s);
}
static CLIPRDR_FORMAT_LIST cliprdr_filter_local_format_list(const CLIPRDR_FORMAT_LIST* list,
const UINT32 mask)
{
const UINT32 all = CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES;
WINPR_ASSERT(list);
CLIPRDR_FORMAT_LIST filtered = { 0 };
filtered.numFormats = list->numFormats;
filtered.formats = calloc(filtered.numFormats, sizeof(CLIPRDR_FORMAT_LIST));
size_t wpos = 0;
if ((mask & all) == all)
{
for (size_t x = 0; x < list->numFormats; x++)
{
const CLIPRDR_FORMAT* format = &list->formats[x];
CLIPRDR_FORMAT* cur = &filtered.formats[x];
cur->formatId = format->formatId;
if (format->formatName)
cur->formatName = _strdup(format->formatName);
wpos++;
}
}
else if ((mask & CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES) != 0)
{
for (size_t x = 0; x < list->numFormats; x++)
{
const CLIPRDR_FORMAT* format = &list->formats[x];
CLIPRDR_FORMAT* cur = &filtered.formats[wpos];
if (!format->formatName)
continue;
if (strcmp(format->formatName, type_FileGroupDescriptorW) == 0)
{
cur->formatId = format->formatId;
cur->formatName = _strdup(format->formatName);
wpos++;
}
}
}
else if ((mask & CLIPRDR_FLAG_LOCAL_TO_REMOTE) != 0)
{
for (size_t x = 0; x < list->numFormats; x++)
{
const CLIPRDR_FORMAT* format = &list->formats[x];
CLIPRDR_FORMAT* cur = &filtered.formats[wpos];
if (!format->formatName || (strcmp(format->formatName, type_FileGroupDescriptorW) != 0))
{
cur->formatId = format->formatId;
if (format->formatName)
cur->formatName = _strdup(format->formatName);
wpos++;
}
}
}
filtered.numFormats = wpos;
return filtered;
}
/**
* Function description
*
@ -655,7 +736,15 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context,
cliprdr = (cliprdrPlugin*)context->handle;
WINPR_ASSERT(cliprdr);
s = cliprdr_packet_format_list_new(formatList, cliprdr->useLongFormatNames);
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
CLIPRDR_FORMAT_LIST filterList = cliprdr_filter_local_format_list(formatList, mask);
if (filterList.numFormats == 0)
return CHANNEL_RC_OK;
s = cliprdr_packet_format_list_new(&filterList, cliprdr->useLongFormatNames);
cliprdr_free_format_list(&filterList);
if (!s)
{
WLog_ERR(TAG, "cliprdr_packet_format_list_new failed!");
@ -775,6 +864,13 @@ static UINT cliprdr_client_format_data_request(CliprdrClientContext* context,
cliprdr = (cliprdrPlugin*)context->handle;
WINPR_ASSERT(cliprdr);
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
if ((mask & (CLIPRDR_FLAG_REMOTE_TO_LOCAL | CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES)) == 0)
{
WLog_WARN(TAG, "remote -> local copy disabled, ignoring request");
return CHANNEL_RC_OK;
}
s = cliprdr_packet_new(CB_FORMAT_DATA_REQUEST, 0, 4);
if (!s)
@ -806,6 +902,10 @@ cliprdr_client_format_data_response(CliprdrClientContext* context,
cliprdr = (cliprdrPlugin*)context->handle;
WINPR_ASSERT(cliprdr);
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
WINPR_ASSERT((mask & (CLIPRDR_FLAG_LOCAL_TO_REMOTE | CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES)) != 0);
s = cliprdr_packet_new(CB_FORMAT_DATA_RESPONSE, formatDataResponse->common.msgFlags,
formatDataResponse->common.dataLen);
@ -835,6 +935,14 @@ cliprdr_client_file_contents_request(CliprdrClientContext* context,
WINPR_ASSERT(context);
WINPR_ASSERT(fileContentsRequest);
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
if ((mask & CLIPRDR_FLAG_REMOTE_TO_LOCAL_FILES) == 0)
{
WLog_WARN(TAG, "remote -> local file copy disabled, ignoring request");
return CHANNEL_RC_OK;
}
cliprdr = (cliprdrPlugin*)context->handle;
if (!cliprdr)
return ERROR_INTERNAL_ERROR;
@ -879,6 +987,11 @@ cliprdr_client_file_contents_response(CliprdrClientContext* context,
cliprdr = (cliprdrPlugin*)context->handle;
WINPR_ASSERT(cliprdr);
const UINT32 mask =
freerdp_settings_get_uint32(context->rdpcontext->settings, FreeRDP_ClipboardFeatureMask);
if ((mask & CLIPRDR_FLAG_LOCAL_TO_REMOTE_FILES) == 0)
return cliprdr_send_error_response(cliprdr, CB_FILECONTENTS_RESPONSE);
s = cliprdr_packet_file_contents_response_new(fileContentsResponse);
if (!s)

View File

@ -52,5 +52,8 @@ typedef struct
} cliprdrPlugin;
CliprdrClientContext* cliprdr_get_client_interface(cliprdrPlugin* cliprdr);
UINT cliprdr_send_error_response(cliprdrPlugin* cliprdr, UINT16 type);
extern const char* type_FileGroupDescriptorW;
#endif /* FREERDP_CHANNEL_CLIPRDR_CLIENT_MAIN_H */

View File

@ -72,7 +72,7 @@ wStream* cliprdr_packet_new(UINT16 msgType, UINT16 msgFlags, UINT32 dataLen)
Stream_Write_UINT16(s, msgType);
Stream_Write_UINT16(s, msgFlags);
/* Write actual length after the entire packet has been constructed. */
Stream_Seek(s, 4);
Stream_Write_UINT32(s, 0);
return s;
}