Merge pull request #2082 from kenhys/extend-inbound-outbound-restriction
Extend inbound/outbound clipboard restriction
This commit is contained in:
commit
dfd64e2147
@ -986,3 +986,72 @@ g_bitmask_to_str(int bitmask, const struct bitmask_string bitdefs[],
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
int
|
||||
g_str_to_bitmask(const char *str, const struct bitmask_string bitdefs[],
|
||||
const char *delim, char *unrecognised, int unrecognised_len)
|
||||
{
|
||||
char *properties = NULL;
|
||||
char *p = NULL;
|
||||
int mask = 0;
|
||||
|
||||
if (unrecognised_len < 1)
|
||||
{
|
||||
/* No space left to tell unrecognised tokens */
|
||||
return 0;
|
||||
}
|
||||
if (!unrecognised)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* ensure not to return with uninitialized buffer */
|
||||
unrecognised[0] = '\0';
|
||||
if (!str || !bitdefs || !delim)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
properties = g_strdup(str);
|
||||
if (!properties)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
p = strtok(properties, delim);
|
||||
while (p != NULL)
|
||||
{
|
||||
g_strtrim(p, 3);
|
||||
const struct bitmask_string *b;
|
||||
int found = 0;
|
||||
for (b = &bitdefs[0] ; b->str != NULL; ++b)
|
||||
{
|
||||
if (0 == g_strcasecmp(p, b->str))
|
||||
{
|
||||
mask |= b->mask;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == 0)
|
||||
{
|
||||
int length = g_strlen(unrecognised);
|
||||
if (length > 0)
|
||||
{
|
||||
/* adding ",property" */
|
||||
if (length + g_strlen(p) + 1 < unrecognised_len)
|
||||
{
|
||||
unrecognised[length] = delim[0];
|
||||
length += 1;
|
||||
g_strcpy(unrecognised + length, p);
|
||||
}
|
||||
}
|
||||
else if (g_strlen(p) < unrecognised_len)
|
||||
{
|
||||
g_strcpy(unrecognised, p);
|
||||
}
|
||||
}
|
||||
p = strtok(NULL, delim);
|
||||
}
|
||||
|
||||
g_free(properties);
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
@ -174,6 +174,20 @@ int
|
||||
g_bitmask_to_str(int bitmask, const struct bitmask_string[],
|
||||
char delim, char *buff, int bufflen);
|
||||
|
||||
/***
|
||||
* Converts a string containing a series of tokens to a bitmask.
|
||||
* @param str Input string
|
||||
* @param bitmask_string Array mapping tokens to bitmask values
|
||||
* @param delim Delimiter for tokens in str
|
||||
* @param[out] unrecognised Buffer for any unrecognised tokens
|
||||
* @param unrecognised_len Length of unrecognised including '\0';
|
||||
* @return bitmask value for recognised tokens
|
||||
*/
|
||||
int
|
||||
g_str_to_bitmask(const char *str, const struct bitmask_string[],
|
||||
const char *delim, char *unrecognised,
|
||||
int unrecognised_len);
|
||||
|
||||
int g_strlen(const char *text);
|
||||
char *g_strchr(const char *text, int c);
|
||||
char *g_strrchr(const char *text, int c);
|
||||
|
@ -221,10 +221,62 @@ login for all users is enabled.
|
||||
have session management rights.
|
||||
|
||||
.TP
|
||||
\fBRestrictOutboundClipboard\fR=\fI[true|false]\fR
|
||||
If set to \fB1\fR, \fBtrue\fR or \fByes\fR, will restrict the clipboard
|
||||
\fBRestrictOutboundClipboard\fR=\fI[all|none|text|file|image]\fR
|
||||
If set to \fBall\fR, will restrict the clipboard
|
||||
outbound from the server, to prevent data copied inside the xrdp session
|
||||
to be be pasted in the client host. Default value is \fBfalse\fR.
|
||||
to be pasted in the client. Default value is \fBnone\fR.
|
||||
In addition, you can control text/file/image transfer restrictions
|
||||
respectively. It also accepts comma separated list such as text,file,image.
|
||||
.br
|
||||
|
||||
.br
|
||||
\fBnone\fR - No restriction about copying inbound clipboard data.
|
||||
.br
|
||||
\fBall\fR - Restrict to copy inbound clipboard data.
|
||||
.br
|
||||
\fBtext\fR - Restrict to copy only inbound text clipboard data.
|
||||
.br
|
||||
\fBfile\fR - Restrict to copy only inbound file clipboard data.
|
||||
.br
|
||||
\fBimage\fR - Restrict to copy only inbound image clipboard data.
|
||||
.br
|
||||
|
||||
To keep compatibility, the following aliases are also available.
|
||||
.br
|
||||
\fBtrue\fR - an alias of \fBall\fR.
|
||||
.br
|
||||
\fBfalse\fR - an alias of \fBnone\fR.
|
||||
.br
|
||||
\fByes\fR - an alias of \fBall\fR.
|
||||
|
||||
.TP
|
||||
\fBRestrictInboundClipboard\fR=\fI[none|all|text|file|image]\fR
|
||||
If set to \fBall\fR, will restrict the clipboard
|
||||
inbound from the client, to prevent data copied inside the client
|
||||
to be pasted in the xrdp session. Default value is \fBnone\fR.
|
||||
In addition, you can control text/file/image transfer restrictions
|
||||
respectively. It also accepts comma separated list such as text,file,image.
|
||||
.br
|
||||
|
||||
.br
|
||||
\fBnone\fR - No restriction about copying inbound clipboard data.
|
||||
.br
|
||||
\fBall\fR - Restrict to copy inbound clipboard data.
|
||||
.br
|
||||
\fBtext\fR - Restrict to copy only inbound text clipboard data.
|
||||
.br
|
||||
\fBfile\fR - Restrict to copy only inbound file clipboard data.
|
||||
.br
|
||||
\fBimage\fR - Restrict to copy only inbound image clipboard data.
|
||||
.br
|
||||
|
||||
To keep compatibility, the following aliases are also available.
|
||||
.br
|
||||
\fBtrue\fR - an alias of \fBall\fR.
|
||||
.br
|
||||
\fBfalse\fR - an alias of \fBnone\fR.
|
||||
.br
|
||||
\fByes\fR - an alias of \fBall\fR.
|
||||
|
||||
.TP
|
||||
\fBAlwaysGroupCheck\fR=\fI[true|false]\fR
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -171,6 +171,7 @@ x-special/gnome-copied-files
|
||||
#include "os_calls.h"
|
||||
#include "string_calls.h"
|
||||
#include "chansrv.h"
|
||||
#include "chansrv_common.h"
|
||||
#include "chansrv_config.h"
|
||||
#include "clipboard.h"
|
||||
#include "clipboard_file.h"
|
||||
@ -2005,14 +2006,33 @@ clipboard_event_selection_notify(XEvent *xevent)
|
||||
g_clip_s2c.data[g_clip_s2c.total_bytes] = 0;
|
||||
if (g_clip_s2c.xrdp_clip_type == XRDP_CB_FILE)
|
||||
{
|
||||
clipboard_send_data_response_for_file(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(file) UTF8_STRING(%s) is restricted because of config",
|
||||
g_clip_s2c.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_send_data_response_for_file(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_send_data_response_for_text(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_TEXT)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(text) UTF8_STRING(%s) is restricted because of config",
|
||||
g_clip_s2c.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_send_data_response_for_text(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (lxevent->target == XA_STRING)
|
||||
@ -2026,8 +2046,18 @@ clipboard_event_selection_notify(XEvent *xevent)
|
||||
g_clip_s2c.data = (char *) g_malloc(g_clip_s2c.total_bytes + 1, 0);
|
||||
g_memcpy(g_clip_s2c.data, data, g_clip_s2c.total_bytes);
|
||||
g_clip_s2c.data[g_clip_s2c.total_bytes] = 0;
|
||||
clipboard_send_data_response_for_text(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_TEXT)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(text) XA_STRING(%s) is restricted because of config",
|
||||
g_clip_s2c.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_send_data_response_for_text(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (lxevent->target == g_image_bmp_atom)
|
||||
@ -2037,11 +2067,21 @@ clipboard_event_selection_notify(XEvent *xevent)
|
||||
if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 14))
|
||||
{
|
||||
g_free(g_clip_s2c.data);
|
||||
g_clip_s2c.total_bytes = data_size;
|
||||
g_clip_s2c.data = (char *) g_malloc(data_size, 0);
|
||||
g_memcpy(g_clip_s2c.data, data, data_size);
|
||||
clipboard_send_data_response_for_image(g_clip_s2c.data + 14,
|
||||
data_size - 14);
|
||||
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_IMAGE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(image) image/bmp is restricted because of config");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clip_s2c.total_bytes = data_size;
|
||||
g_clip_s2c.data = (char *) g_malloc(data_size, 0);
|
||||
g_memcpy(g_clip_s2c.data, data, data_size);
|
||||
clipboard_send_data_response_for_image(g_clip_s2c.data + 14,
|
||||
data_size - 14);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (lxevent->target == g_file_atom1)
|
||||
@ -2055,8 +2095,19 @@ clipboard_event_selection_notify(XEvent *xevent)
|
||||
g_clip_s2c.data = (char *) g_malloc(g_clip_s2c.total_bytes + 1, 0);
|
||||
g_memcpy(g_clip_s2c.data, data, g_clip_s2c.total_bytes);
|
||||
g_clip_s2c.data[g_clip_s2c.total_bytes] = 0;
|
||||
clipboard_send_data_response_for_file(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(file) text/uri-list(%s) is restricted because of config",
|
||||
g_clip_s2c.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_send_data_response_for_file(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (lxevent->target == g_file_atom2)
|
||||
@ -2070,8 +2121,18 @@ clipboard_event_selection_notify(XEvent *xevent)
|
||||
g_clip_s2c.data = (char *) g_malloc(g_clip_s2c.total_bytes + 1, 0);
|
||||
g_memcpy(g_clip_s2c.data, data, g_clip_s2c.total_bytes);
|
||||
g_clip_s2c.data[g_clip_s2c.total_bytes] = 0;
|
||||
clipboard_send_data_response_for_file(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(file) x-special/gnome-copied-files(%s) is restricted because of config",
|
||||
g_clip_s2c.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_send_data_response_for_file(g_clip_s2c.data,
|
||||
g_clip_s2c.total_bytes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -2090,35 +2151,81 @@ clipboard_event_selection_notify(XEvent *xevent)
|
||||
if (got_file_atom != 0)
|
||||
{
|
||||
/* text/uri-list or x-special/gnome-copied-files */
|
||||
g_clip_s2c.type = got_file_atom;
|
||||
g_clip_s2c.xrdp_clip_type = XRDP_CB_FILE;
|
||||
g_clip_s2c.converted = 0;
|
||||
g_clip_s2c.clip_time = lxevent->time;
|
||||
send_format_announce = 1;
|
||||
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(file) is restricted because of config");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clip_s2c.type = got_file_atom;
|
||||
g_clip_s2c.xrdp_clip_type = XRDP_CB_FILE;
|
||||
g_clip_s2c.converted = 0;
|
||||
g_clip_s2c.clip_time = lxevent->time;
|
||||
send_format_announce = 1;
|
||||
}
|
||||
|
||||
}
|
||||
else if (got_utf8)
|
||||
{
|
||||
g_clip_s2c.type = g_utf8_atom;
|
||||
g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT;
|
||||
g_clip_s2c.converted = 0;
|
||||
g_clip_s2c.clip_time = lxevent->time;
|
||||
send_format_announce = 1;
|
||||
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_TEXT)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(text) is restricted because of config");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clip_s2c.type = g_utf8_atom;
|
||||
g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT;
|
||||
g_clip_s2c.converted = 0;
|
||||
g_clip_s2c.clip_time = lxevent->time;
|
||||
send_format_announce = 1;
|
||||
}
|
||||
|
||||
}
|
||||
else if (got_string)
|
||||
{
|
||||
g_clip_s2c.type = XA_STRING;
|
||||
g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT;
|
||||
g_clip_s2c.converted = 0;
|
||||
g_clip_s2c.clip_time = lxevent->time;
|
||||
send_format_announce = 1;
|
||||
|
||||
/*
|
||||
* In most cases, when copying text, TARGETS atom and UTF8_STRING atom exists,
|
||||
* it means that this code block which checks STRING atom might not be never executed
|
||||
* in recent platforms.
|
||||
* Use echo foo | xclip -selection clipboard -noutf8 to reproduce it.
|
||||
*/
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_TEXT)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(text) is restricted because of config");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clip_s2c.type = XA_STRING;
|
||||
g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT;
|
||||
g_clip_s2c.converted = 0;
|
||||
g_clip_s2c.clip_time = lxevent->time;
|
||||
send_format_announce = 1;
|
||||
}
|
||||
|
||||
}
|
||||
else if (got_bmp_image)
|
||||
{
|
||||
g_clip_s2c.type = g_image_bmp_atom;
|
||||
g_clip_s2c.xrdp_clip_type = XRDP_CB_BITMAP;
|
||||
g_clip_s2c.converted = 0;
|
||||
g_clip_s2c.clip_time = lxevent->time;
|
||||
send_format_announce = 1;
|
||||
|
||||
if (g_cfg->restrict_outbound_clipboard & CLIP_RESTRICT_IMAGE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"outbound clipboard(image) is restricted because of config");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clip_s2c.type = g_image_bmp_atom;
|
||||
g_clip_s2c.xrdp_clip_type = XRDP_CB_BITMAP;
|
||||
g_clip_s2c.converted = 0;
|
||||
g_clip_s2c.clip_time = lxevent->time;
|
||||
send_format_announce = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (send_format_announce)
|
||||
@ -2187,16 +2294,23 @@ clipboard_event_selection_request(XEvent *xevent)
|
||||
atom_buf[0] = g_targets_atom;
|
||||
atom_buf[1] = g_timestamp_atom;
|
||||
atom_buf[2] = g_multiple_atom;
|
||||
atom_buf[3] = XA_STRING;
|
||||
atom_buf[4] = g_utf8_atom;
|
||||
atom_count = 5;
|
||||
if (clipboard_find_format_id(CB_FORMAT_DIB) >= 0)
|
||||
atom_count = 3;
|
||||
if ((g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_TEXT) == 0)
|
||||
{
|
||||
atom_buf[atom_count] = XA_STRING;
|
||||
atom_count++;
|
||||
atom_buf[atom_count] = g_utf8_atom;
|
||||
atom_count++;
|
||||
}
|
||||
if (clipboard_find_format_id(CB_FORMAT_DIB) >= 0 &&
|
||||
(g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_IMAGE) == 0)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, " reporting image/bmp");
|
||||
atom_buf[atom_count] = g_image_bmp_atom;
|
||||
atom_count++;
|
||||
}
|
||||
if (clipboard_find_format_id(g_file_format_id) >= 0)
|
||||
if (clipboard_find_format_id(g_file_format_id) >= 0 &&
|
||||
(g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE) == 0)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, " reporting text/uri-list");
|
||||
atom_buf[atom_count] = g_file_atom1;
|
||||
@ -2243,19 +2357,43 @@ clipboard_event_selection_request(XEvent *xevent)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: "
|
||||
"text requested when files available");
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = lxev->target;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
|
||||
clipboard_send_data_request(g_file_format_id);
|
||||
|
||||
if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"inbound clipboard %s is restricted because of config",
|
||||
lxev->target == XA_STRING ? "XA_STRING" : "UTF8_STRING");
|
||||
clipboard_refuse_selection(lxev);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = lxev->target;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
|
||||
clipboard_send_data_request(g_file_format_id);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = lxev->target;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_TEXT;
|
||||
clipboard_send_data_request(CB_FORMAT_UNICODETEXT);
|
||||
|
||||
if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_TEXT)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"inbound clipboard %s is restricted because of config",
|
||||
lxev->target == XA_STRING ? "XA_STRING" : "UTF8_STRING");
|
||||
clipboard_refuse_selection(lxev);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = lxev->target;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_TEXT;
|
||||
clipboard_send_data_request(CB_FORMAT_UNICODETEXT);
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -2265,15 +2403,37 @@ clipboard_event_selection_request(XEvent *xevent)
|
||||
if ((g_clip_c2s.type == lxev->target) && g_clip_c2s.converted)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: -------------------------------------------");
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
|
||||
if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_IMAGE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"inbound clipboard image/bmp converted is restricted because of config");
|
||||
clipboard_refuse_selection(lxev);
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_IMAGE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"inbound clipboard image/bmp is restricted because of config");
|
||||
clipboard_refuse_selection(lxev);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = g_image_bmp_atom;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_BITMAP;
|
||||
clipboard_send_data_request(CB_FORMAT_DIB);
|
||||
}
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = g_image_bmp_atom;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_BITMAP;
|
||||
clipboard_send_data_request(CB_FORMAT_DIB);
|
||||
return 0;
|
||||
|
||||
}
|
||||
else if (lxev->target == g_file_atom1)
|
||||
{
|
||||
@ -2281,31 +2441,73 @@ clipboard_event_selection_request(XEvent *xevent)
|
||||
if ((g_clip_c2s.type == lxev->target) && g_clip_c2s.converted)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: -------------------------------------------");
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"inbound clipboard text/uri-list is restricted because of config");
|
||||
clipboard_refuse_selection(lxev);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"inbound clipboard text/uri-list is restricted because of config");
|
||||
clipboard_refuse_selection(lxev);
|
||||
return 0;
|
||||
}
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = g_file_atom1;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
|
||||
clipboard_send_data_request(g_file_format_id);
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = g_file_atom1;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
|
||||
clipboard_send_data_request(g_file_format_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
else if (lxev->target == g_file_atom2)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: g_file_atom2");
|
||||
|
||||
if ((g_clip_c2s.type == lxev->target) && g_clip_c2s.converted)
|
||||
{
|
||||
LOG_DEVEL(LOG_LEVEL_DEBUG, "clipboard_event_selection_request: -------------------------------------------");
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"inbound clipboard x-special/gnome-copied-files converted is restricted because of config");
|
||||
clipboard_refuse_selection(lxev);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
clipboard_provide_selection_c2s(lxev, lxev->target);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (g_cfg->restrict_inbound_clipboard & CLIP_RESTRICT_FILE)
|
||||
{
|
||||
LOG(LOG_LEVEL_DEBUG,
|
||||
"inbound clipboard x-special/gnome-copied-files is restricted because of config");
|
||||
clipboard_refuse_selection(lxev);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = g_file_atom2;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
|
||||
clipboard_send_data_request(g_file_format_id);
|
||||
return 0;
|
||||
}
|
||||
g_memcpy(&g_saved_selection_req_event, lxev,
|
||||
sizeof(g_saved_selection_req_event));
|
||||
g_clip_c2s.type = g_file_atom2;
|
||||
g_clip_c2s.xrdp_clip_type = XRDP_CB_FILE;
|
||||
clipboard_send_data_request(g_file_format_id);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2527,15 +2729,7 @@ clipboard_xevent(void *xevent)
|
||||
switch (lxevent->type)
|
||||
{
|
||||
case SelectionNotify:
|
||||
if (g_cfg->restrict_outbound_clipboard == 0)
|
||||
{
|
||||
clipboard_event_selection_notify(lxevent);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LOG_LEVEL_INFO, "outbound clipboard is restricted because of config");
|
||||
return 1;
|
||||
}
|
||||
clipboard_event_selection_notify(lxevent);
|
||||
break;
|
||||
case SelectionRequest:
|
||||
clipboard_event_selection_request(lxevent);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -19,9 +19,24 @@ TerminalServerAdmins=tsadmins
|
||||
; When AlwaysGroupCheck=false access will be permitted
|
||||
; if the group TerminalServerUsers is not defined.
|
||||
AlwaysGroupCheck=false
|
||||
; When RestrictOutboundClipboard=true clipboard from the
|
||||
; When RestrictOutboundClipboard=all clipboard from the
|
||||
; server is not pushed to the client.
|
||||
RestrictOutboundClipboard=false
|
||||
; In addition, you can control text/file/image transfer restrictions
|
||||
; respectively. It also accepts comma separated list such as text,file,image.
|
||||
; To keep compatibility, some aliases are also available:
|
||||
; true: an alias of all
|
||||
; false: an alias of none
|
||||
; yes: an alias of all
|
||||
RestrictOutboundClipboard=none
|
||||
; When RestrictInboundClipboard=all clipboard from the
|
||||
; client is not pushed to the server.
|
||||
; In addition, you can control text/file/image transfer restrictions
|
||||
; respectively. It also accepts comma separated list such as text,file,image.
|
||||
; To keep compatibility, some aliases are also available:
|
||||
; true: an alias of all
|
||||
; false: an alias of none
|
||||
; yes: an alias of all
|
||||
RestrictInboundClipboard=none
|
||||
|
||||
[Sessions]
|
||||
;; X11DisplayOffset - x11 display number offset
|
||||
|
@ -323,6 +323,331 @@ START_TEST(test_bm2str__overflow_some_bits_undefined)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__null_string)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
rv = g_str_to_bitmask(NULL, bits, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__empty_string)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
rv = g_str_to_bitmask("", bits, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__null_bitdefs)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
rv = g_str_to_bitmask("BIT_0", NULL, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__null_delim)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
rv = g_str_to_bitmask("BIT_0", bits, NULL, buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__null_buffer)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
rv = g_str_to_bitmask("BIT_0", bits, ",", NULL, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "dummy");
|
||||
ck_assert_int_eq(rv, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__zero_buffer)
|
||||
{
|
||||
int rv;
|
||||
char buff[1];
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
rv = g_str_to_bitmask("BIT_0", bits, ",", buff, 0);
|
||||
|
||||
ck_assert_int_eq(rv, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__zero_mask)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{0, "ZERO MASK"}, /* mask 0 should not be detected as end of list */
|
||||
{1 << 0, "BIT_0"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 0;
|
||||
rv = g_str_to_bitmask("BIT_0", bits, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__all_defined)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 0 | 1 << 1;
|
||||
rv = g_str_to_bitmask("BIT_0,BIT_1", bits, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__no_defined)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 0;
|
||||
rv = g_str_to_bitmask("BIT_2,BIT_3", bits, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "BIT_2,BIT_3");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__some_defined)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
{1 << 2, "BIT_2"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 1;
|
||||
rv = g_str_to_bitmask("a,BIT_1,b", bits, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "a,b");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__trim_space)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
{1 << 2, "BIT_2"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 0 | 1 << 1 | 1 << 2;
|
||||
rv = g_str_to_bitmask("BIT_0 , BIT_1 , BIT_2", bits, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__overflow_undefined)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
{1 << 2, "BIT_2"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 1;
|
||||
rv = g_str_to_bitmask("123456789,BIT_1,abcdef", bits, ",", buff, sizeof(buff));
|
||||
|
||||
/* abcdef is not filled */
|
||||
ck_assert_str_eq(buff, "123456789");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__delim_slash)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
{1 << 2, "BIT_2"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 0 | 1 << 1 | 1 << 2;
|
||||
rv = g_str_to_bitmask("BIT_0/BIT_1/BIT_2", bits, "/", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__no_delim)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
rv = g_str_to_bitmask("BIT_0,BIT_1", bits, "", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "BIT_0,BIT_1");
|
||||
ck_assert_int_eq(rv, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__multiple_delim)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
{1 << 2, "BIT_2"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 0 | 1 << 1 | 1 << 2;
|
||||
rv = g_str_to_bitmask("BIT_0/BIT_1,BIT_2", bits, ",/", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__first_delim_is_semicolon)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
{1 << 1, "BIT_1"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 1;
|
||||
rv = g_str_to_bitmask("a;b;BIT_1;c", bits, ";,", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "a;b;c");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_str2bm__empty_token)
|
||||
{
|
||||
int rv;
|
||||
char buff[16] = { 'd', 'u', 'm', 'm', 'y' };
|
||||
|
||||
static const struct bitmask_string bits[] =
|
||||
{
|
||||
{1 << 0, "BIT_0"},
|
||||
BITMASK_STRING_END_OF_LIST
|
||||
};
|
||||
|
||||
int bitmask = 1 << 0;
|
||||
rv = g_str_to_bitmask(",BIT_0, ,", bits, ",", buff, sizeof(buff));
|
||||
|
||||
ck_assert_str_eq(buff, "");
|
||||
ck_assert_int_eq(rv, bitmask);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
START_TEST(test_strtrim__trim_left)
|
||||
@ -385,6 +710,7 @@ make_suite_test_string(void)
|
||||
Suite *s;
|
||||
TCase *tc_strnjoin;
|
||||
TCase *tc_bm2str;
|
||||
TCase *tc_str2bm;
|
||||
TCase *tc_strtrim;
|
||||
|
||||
s = suite_create("String");
|
||||
@ -410,6 +736,25 @@ make_suite_test_string(void)
|
||||
tcase_add_test(tc_bm2str, test_bm2str__some_bits_undefined);
|
||||
tcase_add_test(tc_bm2str, test_bm2str__overflow_all_bits_defined);
|
||||
tcase_add_test(tc_bm2str, test_bm2str__overflow_some_bits_undefined);
|
||||
tc_str2bm = tcase_create("str2bm");
|
||||
suite_add_tcase(s, tc_str2bm);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__null_string);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__empty_string);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__null_bitdefs);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__null_delim);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__null_buffer);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__zero_buffer);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__zero_mask);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__all_defined);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__no_defined);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__some_defined);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__trim_space);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__overflow_undefined);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__no_delim);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__delim_slash);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__multiple_delim);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__first_delim_is_semicolon);
|
||||
tcase_add_test(tc_str2bm, test_str2bm__empty_token);
|
||||
|
||||
tc_strtrim = tcase_create("strtrim");
|
||||
suite_add_tcase(s, tc_strtrim);
|
||||
|
Loading…
Reference in New Issue
Block a user