Extend In/Outbound text,file,image restriction respectively

It supports the extended configurations for sesman.ini:

Before:

  [Security]
  RestrictOutboundClipboard=true or false

After:

  [Security]
  RestrictInboundClipboard=[true or false | text or file or image | comma separated list]
  RestrictOutboundClipboard=[true or false | text or file or image | comma separated list]

Above configuration is disabled by default (false)
And it can be specified comma separated list like this:.

  RestrictInboundClipboard=file, image
  RestrictOutboundClipboard=text, file, image

Note that if RestrictOutboundClipboard=true,file is set,
file is ignored and it is treated as RestrictOutboundClipboard=true

It is same for RestrictInboundClipboard.
This commit is contained in:
Kentaro Hayashi 2021-12-14 14:35:50 +09:00
parent 69ea406440
commit bd82084505
5 changed files with 168 additions and 11 deletions

View File

@ -22,6 +22,13 @@
#include "parse.h"
#include "os_calls.h"
/* Define bitmask values for restricting the clipboard */
#define CLIP_RESTRICT_NONE 0
#define CLIP_RESTRICT_TEXT (1<<0)
#define CLIP_RESTRICT_FILE (1<<1)
#define CLIP_RESTRICT_IMAGE (1<<2)
#define CLIP_RESTRICT_ALL 0x7fffffff
int read_entire_packet(struct stream *src, struct stream **dest, int chan_flags, int length, int total_length);
#endif

View File

@ -30,12 +30,14 @@
#include "file.h"
#include "os_calls.h"
#include "chansrv_common.h"
#include "chansrv_config.h"
#include "string_calls.h"
/* Default settings */
#define DEFAULT_USE_UNIX_SOCKET 0
#define DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD 0
#define DEFAULT_RESTRICT_INBOUND_CLIPBOARD 0
#define DEFAULT_ENABLE_FUSE_MOUNT 1
#define DEFAULT_FUSE_MOUNT_NAME "xrdp-client"
#define DEFAULT_FILE_UMASK 077
@ -48,6 +50,21 @@ printflike(2, 3)
enum logReturns (*log_func_t)(const enum logLevels lvl,
const char *msg, ...);
/* Map clipboard strings into bitmask values */
static const struct bitmask_string clip_restrict_map[] =
{
{ CLIP_RESTRICT_TEXT, "text"},
{ CLIP_RESTRICT_FILE, "file"},
{ CLIP_RESTRICT_IMAGE, "image"},
{ CLIP_RESTRICT_ALL, "all"},
{ CLIP_RESTRICT_NONE, "none"},
/* Compatibility values */
{ CLIP_RESTRICT_ALL, "true"},
{ CLIP_RESTRICT_ALL, "yes"},
{ CLIP_RESTRICT_NONE, "false"},
BITMASK_STRING_END_OF_LIST
};
/***************************************************************************//**
* @brief Error logging function to use to log to stdout
*
@ -125,9 +142,30 @@ read_config_security(log_func_t logmsg,
const char *name = (const char *)list_get_item(names, index);
const char *value = (const char *)list_get_item(values, index);
char unrecognised[256];
if (g_strcasecmp(name, "RestrictOutboundClipboard") == 0)
{
cfg->restrict_outbound_clipboard = g_text2bool(value);
cfg->restrict_outbound_clipboard =
g_str_to_bitmask(value, clip_restrict_map, ",",
unrecognised, sizeof(unrecognised));
if (unrecognised[0] != '\0')
{
LOG(LOG_LEVEL_WARNING,
"Unrecognised tokens parsing 'RestrictOutboundClipboard' %s",
unrecognised);
}
}
if (g_strcasecmp(name, "RestrictInboundClipboard") == 0)
{
cfg->restrict_inbound_clipboard =
g_str_to_bitmask(value, clip_restrict_map, ",",
unrecognised, sizeof(unrecognised));
if (unrecognised[0] != '\0')
{
LOG(LOG_LEVEL_WARNING,
"Unrecognised tokens parsing 'RestrictInboundClipboard' %s",
unrecognised);
}
}
}
@ -208,6 +246,7 @@ new_config(void)
cfg->use_unix_socket = DEFAULT_USE_UNIX_SOCKET;
cfg->enable_fuse_mount = DEFAULT_ENABLE_FUSE_MOUNT;
cfg->restrict_outbound_clipboard = DEFAULT_RESTRICT_OUTBOUND_CLIPBOARD;
cfg->restrict_inbound_clipboard = DEFAULT_RESTRICT_INBOUND_CLIPBOARD;
cfg->fuse_mount_name = fuse_mount_name;
cfg->file_umask = DEFAULT_FILE_UMASK;
cfg->use_nautilus3_flist_format = DEFAULT_USE_NAUTILUS3_FLIST_FORMAT;
@ -286,10 +325,37 @@ config_dump(struct config_chansrv *config)
g_writeln(" UseUnixSocket (derived): %s",
g_bool2text(config->use_unix_socket));
char buf[256];
g_writeln("\nSecurity configuration:");
g_writeln(" RestrictOutboundClipboard: %s",
g_bool2text(config->restrict_outbound_clipboard));
if (config->restrict_outbound_clipboard == CLIP_RESTRICT_NONE)
{
g_writeln(" RestrictOutboundClipboard: %s", "none");
}
else if (config->restrict_outbound_clipboard == CLIP_RESTRICT_ALL)
{
g_writeln(" RestrictOutboundClipboard: %s", "all");
}
else
{
g_bitmask_to_str(config->restrict_outbound_clipboard,
clip_restrict_map, ',', buf, sizeof(buf));
g_writeln(" RestrictOutboundClipboard: %s", buf);
}
g_writeln(" RestrictInboundClipboard: %s", buf);
if (config->restrict_inbound_clipboard == CLIP_RESTRICT_NONE)
{
g_writeln(" RestrictInboundClipboard: %s", "none");
}
else if (config->restrict_inbound_clipboard == CLIP_RESTRICT_ALL)
{
g_writeln(" RestrictInboundClipboard: %s", "all");
}
else
{
g_bitmask_to_str(config->restrict_inbound_clipboard,
clip_restrict_map, ',', buf, sizeof(buf));
g_writeln(" RestrictInboundClipboard: %s", buf);
}
g_writeln("\nChansrv configuration:");
g_writeln(" EnableFuseMount %s",
g_bool2text(config->enable_fuse_mount));

View File

@ -31,6 +31,8 @@ struct config_chansrv
/** RestrictOutboundClipboard setting from sesman.ini */
int restrict_outbound_clipboard;
/** RestrictInboundClipboard setting from sesman.ini */
int restrict_inbound_clipboard;
/** * FuseMountName from sesman.ini */
char *fuse_mount_name;

View File

@ -34,6 +34,7 @@
#include "sesman.h"
#include "log.h"
#include "string_calls.h"
#include "chansrv/chansrv_common.h"
/***************************************************************************//**
*
@ -162,6 +163,26 @@ config_read_globals(int file, struct config_sesman *cf, struct list *param_n,
return 0;
}
/*
Map clipboard strings into bitmask values.
Duplicated definition exists in chansrv_config,
because it avoids build failure for xrdp-sesman and xrdp-sesrun.
It should be unified in the future.
*/
static const struct bitmask_string clip_restrict_map[] =
{
{ CLIP_RESTRICT_TEXT, "text"},
{ CLIP_RESTRICT_FILE, "file"},
{ CLIP_RESTRICT_IMAGE, "image"},
{ CLIP_RESTRICT_ALL, "all"},
{ CLIP_RESTRICT_NONE, "none"},
/* Compatibility values */
{ CLIP_RESTRICT_ALL, "true"},
{ CLIP_RESTRICT_ALL, "yes"},
{ CLIP_RESTRICT_NONE, "false"},
BITMASK_STRING_END_OF_LIST
};
/***************************************************************************//**
*
* @brief Reads sesman [Security] configuration section
@ -190,6 +211,7 @@ config_read_security(int file, struct config_security *sc,
sc->ts_users_enable = 0;
sc->ts_admins_enable = 0;
sc->restrict_outbound_clipboard = 0;
sc->restrict_inbound_clipboard = 0;
file_read_section(file, SESMAN_CFG_SECURITY, param_n, param_v);
@ -231,7 +253,31 @@ config_read_security(int file, struct config_security *sc,
if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD))
{
sc->restrict_outbound_clipboard = g_text2bool((char *)list_get_item(param_v, i));
char unrecognised[256];
sc->restrict_outbound_clipboard =
g_str_to_bitmask((const char *)list_get_item(param_v, i),
clip_restrict_map, ",",
unrecognised, sizeof(unrecognised));
if (unrecognised[0] != '\0')
{
LOG(LOG_LEVEL_WARNING,
"Unrecognised tokens parsing 'RestrictOutboundClipboard' %s",
unrecognised);
}
}
if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_INBOUND_CLIPBOARD))
{
char unrecognised[256];
sc->restrict_inbound_clipboard =
g_str_to_bitmask((const char *)list_get_item(param_v, i),
clip_restrict_map, ",",
unrecognised, sizeof(unrecognised));
if (unrecognised[0] != '\0')
{
LOG(LOG_LEVEL_WARNING,
"Unrecognised tokens parsing 'RestrictInboundClipboard' %s",
unrecognised);
}
}
}
@ -553,12 +599,41 @@ config_dump(struct config_sesman *config)
/* Security configuration */
g_writeln("Security configuration:");
g_writeln(" AllowRootLogin: %d", sc->allow_root);
g_writeln(" MaxLoginRetry: %d", sc->login_retry);
g_writeln(" AlwaysGroupCheck: %d", sc->ts_always_group_check);
g_writeln(" RestrictOutboundClipboard: %d", sc->restrict_outbound_clipboard);
g_writeln(" AllowRootLogin: %d", sc->allow_root);
g_writeln(" MaxLoginRetry: %d", sc->login_retry);
g_writeln(" AlwaysGroupCheck: %d", sc->ts_always_group_check);
if (sc->restrict_outbound_clipboard == CLIP_RESTRICT_NONE)
{
g_writeln(" RestrictOutboundClipboard: %s", "none");
}
else if (sc->restrict_outbound_clipboard == CLIP_RESTRICT_ALL)
{
g_writeln(" RestrictOutboundClipboard: %s", "all");
}
else
{
char buf[256];
g_bitmask_to_str(sc->restrict_outbound_clipboard,
clip_restrict_map, ',', buf, sizeof(buf));
g_writeln(" RestrictOutboundClipboard: %s", buf);
}
if (sc->restrict_inbound_clipboard == CLIP_RESTRICT_NONE)
{
g_writeln(" RestrictInboundClipboard: %s", "none");
}
else if (sc->restrict_inbound_clipboard == CLIP_RESTRICT_ALL)
{
g_writeln(" RestrictInboundClipboard: %s", "all");
}
else
{
char buf[256];
g_bitmask_to_str(sc->restrict_inbound_clipboard,
clip_restrict_map, ',', buf, sizeof(buf));
g_writeln(" RestrictInboundClipboard: %s", buf);
}
g_printf( " TSUsersGroup: ");
g_printf( " TSUsersGroup: ");
if (sc->ts_users_enable)
{
g_printf("%d", sc->ts_users);
@ -569,7 +644,7 @@ config_dump(struct config_sesman *config)
}
g_writeln("%s", "");
g_printf( " TSAdminsGroup: ");
g_printf( " TSAdminsGroup: ");
if (sc->ts_admins_enable)
{
g_printf("%d", sc->ts_admins);

View File

@ -61,6 +61,7 @@
#define SESMAN_CFG_SEC_ADM_GROUP "TerminalServerAdmins"
#define SESMAN_CFG_SEC_ALWAYSGROUPCHECK "AlwaysGroupCheck"
#define SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD "RestrictOutboundClipboard"
#define SESMAN_CFG_SEC_RESTRICT_INBOUND_CLIPBOARD "RestrictInboundClipboard"
#define SESMAN_CFG_SESSIONS "Sessions"
#define SESMAN_CFG_SESS_MAX "MaxSessions"
@ -134,6 +135,12 @@ struct config_security
* @brief if the clipboard should be enforced restricted. If true only allow client -> server, not vice versa.
*/
int restrict_outbound_clipboard;
/**
* @var restrict_inbound_clipboard
* @brief if the clipboard should be enforced restricted. If true only allow server -> client, not vice versa.
*/
int restrict_inbound_clipboard;
};
/**