From bd820845057f41f135ac4406ab87732db9c868e0 Mon Sep 17 00:00:00 2001 From: Kentaro Hayashi Date: Tue, 14 Dec 2021 14:35:50 +0900 Subject: [PATCH] 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. --- sesman/chansrv/chansrv_common.h | 7 +++ sesman/chansrv/chansrv_config.c | 74 +++++++++++++++++++++++++-- sesman/chansrv/chansrv_config.h | 2 + sesman/config.c | 89 ++++++++++++++++++++++++++++++--- sesman/config.h | 7 +++ 5 files changed, 168 insertions(+), 11 deletions(-) diff --git a/sesman/chansrv/chansrv_common.h b/sesman/chansrv/chansrv_common.h index d15c8da7..656e608f 100644 --- a/sesman/chansrv/chansrv_common.h +++ b/sesman/chansrv/chansrv_common.h @@ -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 diff --git a/sesman/chansrv/chansrv_config.c b/sesman/chansrv/chansrv_config.c index adbecb5e..64297bcd 100644 --- a/sesman/chansrv/chansrv_config.c +++ b/sesman/chansrv/chansrv_config.c @@ -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)); diff --git a/sesman/chansrv/chansrv_config.h b/sesman/chansrv/chansrv_config.h index f4acd592..b0327fea 100644 --- a/sesman/chansrv/chansrv_config.h +++ b/sesman/chansrv/chansrv_config.h @@ -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; diff --git a/sesman/config.c b/sesman/config.c index 481ae760..61e9e403 100644 --- a/sesman/config.c +++ b/sesman/config.c @@ -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); diff --git a/sesman/config.h b/sesman/config.h index d9dbcefe..c6b72f8a 100644 --- a/sesman/config.h +++ b/sesman/config.h @@ -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; }; /**