diff --git a/docs/man/sesman.ini.5.in b/docs/man/sesman.ini.5.in index 2074985c..29bed60c 100644 --- a/docs/man/sesman.ini.5.in +++ b/docs/man/sesman.ini.5.in @@ -196,6 +196,12 @@ login for all users is enabled. \fIThis option is currently ignored!\fR Only members of this group can 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 +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. + .TP \fBAlwaysGroupCheck\fR=\fI[true|false]\fR If set to \fB1\fR, \fBtrue\fR or \fByes\fR, require group membership even diff --git a/sesman/chansrv/chansrv.c b/sesman/chansrv/chansrv.c index 7a0de556..04a73000 100644 --- a/sesman/chansrv/chansrv.c +++ b/sesman/chansrv/chansrv.c @@ -59,6 +59,7 @@ int g_cliprdr_chan_id = -1; /* cliprdr */ int g_rdpsnd_chan_id = -1; /* rdpsnd */ int g_rdpdr_chan_id = -1; /* rdpdr */ int g_rail_chan_id = -1; /* rail */ +int g_restrict_outbound_clipboard = 0; char *g_exec_name; tbus g_exec_event; @@ -1780,7 +1781,7 @@ main(int argc, char **argv) enum logReturns error; struct log_config logconfig; enum logLevels log_level; - + char *restrict_outbound_clipboard_env; g_init("xrdp-chansrv"); /* os_calls */ log_path[255] = 0; @@ -1791,6 +1792,15 @@ main(int argc, char **argv) return 1; } + restrict_outbound_clipboard_env = g_getenv("CHANSRV_RESTRICT_OUTBOUND_CLIPBOARD"); + if (restrict_outbound_clipboard_env != 0) + { + if (g_strcmp(restrict_outbound_clipboard_env, "1") == 0) + { + g_restrict_outbound_clipboard = 1; + } + } + read_ini(); pid = g_getpid(); display_text = g_getenv("DISPLAY"); diff --git a/sesman/chansrv/clipboard.c b/sesman/chansrv/clipboard.c index a690e5e2..834fe051 100644 --- a/sesman/chansrv/clipboard.c +++ b/sesman/chansrv/clipboard.c @@ -185,38 +185,38 @@ x-special/gnome-copied-files #define LOG_LEVEL LOG_ERROR #define log_error(_params...) \ -{ \ - g_write("[%10.10u]: CLIPBOARD %s: %d : ERROR: ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ -} + { \ + g_write("[%10.10u]: CLIPBOARD %s: %d : ERROR: ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } #define log_always(_params...) \ -{ \ - g_write("[%10.10u]: CLIPBOARD %s: %d : ALWAYS: ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ -} + { \ + g_write("[%10.10u]: CLIPBOARD %s: %d : ALWAYS: ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } #define log_info(_params...) \ -{ \ - if (LOG_INFO <= LOG_LEVEL) \ - { \ - g_write("[%10.10u]: CLIPBOARD %s: %d : ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ - } \ -} + { \ + if (LOG_INFO <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: CLIPBOARD %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ + } #define log_debug(_params...) \ -{ \ - if (LOG_DEBUG <= LOG_LEVEL) \ - { \ - g_write("[%10.10u]: CLIPBOARD %s: %d : ", \ - g_time3(), __func__, __LINE__); \ - g_writeln (_params); \ - } \ -} + { \ + if (LOG_DEBUG <= LOG_LEVEL) \ + { \ + g_write("[%10.10u]: CLIPBOARD %s: %d : ", \ + g_time3(), __func__, __LINE__); \ + g_writeln (_params); \ + } \ + } static char g_bmp_image_header[] = { @@ -235,6 +235,8 @@ extern tbus g_x_wait_obj; /* in xcommon.c */ extern Screen *g_screen; /* in xcommon.c */ extern int g_screen_num; /* in xcommon.c */ +extern int g_restrict_outbound_clipboard; /* in chansrv.c */ + int g_clip_up = 0; static Atom g_clipboard_atom = 0; /* CLIPBOARD */ @@ -286,10 +288,10 @@ static int g_file_format_id = -1; static char g_last_atom_name[256] = ""; /*****************************************************************************/ -static char* +static char * get_atom_text(Atom atom) { - char* name; + char *name; int failed; failed = 0; @@ -405,10 +407,10 @@ clipboard_init(void) if (rv == 0) { log_debug("clipboard_init: g_xfixes_event_base %d", - g_xfixes_event_base); + g_xfixes_event_base); st = XFixesQueryVersion(g_display, &ver_maj, &ver_min); log_debug("clipboard_init st %d, maj %d min %d", st, - ver_maj, ver_min); + ver_maj, ver_min); g_clip_property_atom = XInternAtom(g_display, "XRDP_CLIP_PROPERTY_ATOM", False); g_get_time_atom = XInternAtom(g_display, "XRDP_GET_TIME_ATOM", @@ -428,7 +430,7 @@ clipboard_init(void) if (g_image_bmp_atom == None) { log_error("clipboard_init: g_image_bmp_atom was " - "not allocated"); + "not allocated"); } g_wnd = XCreateSimpleWindow(g_display, RootWindowOfScreen(g_screen), @@ -463,12 +465,12 @@ clipboard_init(void) s_mark_end(s); size = (int)(s->end - s->data); log_debug("clipboard_init: data out, sending " - "CB_CLIP_CAPS (clip_msg_id = 1)"); + "CB_CLIP_CAPS (clip_msg_id = 1)"); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); if (rv != 0) { log_error("clipboard_init: send_channel_data failed " - "rv = %d", rv); + "rv = %d", rv); rv = 4; } } @@ -484,12 +486,12 @@ clipboard_init(void) s_mark_end(s); size = (int)(s->end - s->data); log_debug("clipboard_init: data out, sending " - "CB_MONITOR_READY (clip_msg_id = 1)"); + "CB_MONITOR_READY (clip_msg_id = 1)"); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); if (rv != 0) { log_error("clipboard_init: send_channel_data failed " - "rv = %d", rv); + "rv = %d", rv); rv = 4; } } @@ -554,7 +556,7 @@ clipboard_send_data_request(int format_id) s_mark_end(s); size = (int)(s->end - s->data); log_debug("clipboard_send_data_request: data out, sending " - "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)"); + "CLIPRDR_DATA_REQUEST (clip_msg_id = 4)"); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; @@ -577,7 +579,7 @@ clipboard_send_format_ack(void) s_mark_end(s); size = (int)(s->end - s->data); log_debug("clipboard_send_format_ack: data out, sending " - "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)"); + "CLIPRDR_FORMAT_ACK (clip_msg_id = 3)"); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; @@ -715,7 +717,7 @@ clipboard_send_format_announce(int xrdp_clip_type) break; default: log_debug("clipboard_send_format_announce: unknown " - "xrdp_clip_type %d", xrdp_clip_type); + "xrdp_clip_type %d", xrdp_clip_type); break; } } @@ -759,7 +761,7 @@ clipboard_send_format_announce(int xrdp_clip_type) break; default: log_debug("clipboard_send_format_announce: unknown " - "xrdp_clip_type %d", xrdp_clip_type); + "xrdp_clip_type %d", xrdp_clip_type); break; } } @@ -774,7 +776,7 @@ clipboard_send_format_announce(int xrdp_clip_type) size = (int)(s->end - s->data); //g_hexdump(s->data, size); log_debug("clipboard_send_format_announce: data out, sending " - "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)"); + "CLIPRDR_FORMAT_ANNOUNCE (clip_msg_id = 2)"); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; @@ -789,7 +791,7 @@ clipboard_send_data_response_for_image(const char *data, int data_size) int rv; log_debug("clipboard_send_data_response_for_image: data_size %d", - data_size); + data_size); make_stream(s); init_stream(s, 64 + data_size); out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ @@ -814,17 +816,17 @@ clipboard_send_data_response_for_text(const char *data, int data_size) int num_chars; log_debug("clipboard_send_data_response_for_text: data_size %d", - data_size); + data_size); //g_hexdump(data, data_size); num_chars = g_mbstowcs(0, data, 0); if (num_chars < 0) { log_error("clipboard_send_data_response_for_text: " - "bad string"); + "bad string"); num_chars = 0; } log_debug("clipboard_send_data_response_for_text: data_size %d " - "num_chars %d", data_size, num_chars); + "num_chars %d", data_size, num_chars); make_stream(s); init_stream(s, 64 + num_chars * 2); out_uint16_le(s, CB_FORMAT_DATA_RESPONSE); /* 5 CLIPRDR_DATA_RESPONSE */ @@ -833,15 +835,15 @@ clipboard_send_data_response_for_text(const char *data, int data_size) if (clipboard_out_unicode(s, data, num_chars) != num_chars * 2) { log_error("clipboard_send_data_response_for_text: error " - "clipboard_out_unicode didn't write right number of bytes"); + "clipboard_out_unicode didn't write right number of bytes"); } out_uint16_le(s, 0); /* nil for string */ out_uint32_le(s, 0); s_mark_end(s); size = (int)(s->end - s->data); log_debug("clipboard_send_data_response_for_text: data out, " - "sending CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d " - "num_chars %d", size, num_chars); + "sending CLIPRDR_DATA_RESPONSE (clip_msg_id = 5) size %d " + "num_chars %d", size, num_chars); rv = send_channel_data(g_cliprdr_chan_id, s->data, size); free_stream(s); return rv; @@ -869,7 +871,7 @@ clipboard_send_data_response(int xrdp_clip_type, const char *data, int data_size else { log_debug("clipboard_send_data_response: unknown " - "xrdp_clip_type %d", xrdp_clip_type); + "xrdp_clip_type %d", xrdp_clip_type); } } else @@ -908,7 +910,7 @@ clipboard_provide_selection_c2s(XSelectionRequestEvent *req, Atom type) long val1[2]; log_debug("clipboard_provide_selection_c2s: bytes %d", - g_clip_c2s.total_bytes); + g_clip_c2s.total_bytes); if (g_clip_c2s.total_bytes < g_incr_max_req_size) { XChangeProperty(g_display, req->requestor, req->property, @@ -934,8 +936,8 @@ clipboard_provide_selection_c2s(XSelectionRequestEvent *req, Atom type) g_clip_c2s.property = req->property; g_clip_c2s.window = req->requestor; log_debug("clipboard_provide_selection_c2s: start INCR property %s " - "type %s", get_atom_text(req->property), - get_atom_text(type)); + "type %s", get_atom_text(req->property), + get_atom_text(type)); val1[0] = g_clip_c2s.total_bytes; val1[1] = 0; XChangeProperty(g_display, req->requestor, req->property, @@ -1020,7 +1022,7 @@ clipboard_process_format_announce(struct stream *s, int clip_msg_status, char *holdp; log_debug("clipboard_process_format_announce: " - "CLIPRDR_FORMAT_ANNOUNCE"); + "CLIPRDR_FORMAT_ANNOUNCE"); log_debug("clipboard_process_format_announce %d", clip_msg_len); clipboard_send_format_ack(); @@ -1052,8 +1054,8 @@ clipboard_process_format_announce(struct stream *s, int clip_msg_status, clip_msg_len -= 32; } log_debug("clipboard_process_format_announce: formatId 0x%8.8x " - "wszFormatName [%s] clip_msg_len %d", formatId, desc, - clip_msg_len); + "wszFormatName [%s] clip_msg_len %d", formatId, desc, + clip_msg_len); if (g_num_formatIds <= 15) { g_formatIds[g_num_formatIds] = formatId; @@ -1073,13 +1075,13 @@ clipboard_process_format_announce(struct stream *s, int clip_msg_status, } if ((g_num_formatIds > 0) && - (g_clip_c2s.incr_in_progress == 0) && /* don't interrupt incr */ - (g_clip_s2c.incr_in_progress == 0)) + (g_clip_c2s.incr_in_progress == 0) && /* don't interrupt incr */ + (g_clip_s2c.incr_in_progress == 0)) { if (clipboard_set_selection_owner() != 0) { log_error("clipboard_process_format_announce: " - "XSetSelectionOwner failed"); + "XSetSelectionOwner failed"); } } @@ -1130,7 +1132,7 @@ clipboard_process_data_request(struct stream *s, int clip_msg_status, int requestedFormatId; log_debug("clipboard_process_data_request: " - "CLIPRDR_DATA_REQUEST"); + "CLIPRDR_DATA_REQUEST"); log_debug("clipboard_process_data_request:"); log_debug(" %d", g_clip_s2c.xrdp_clip_type); in_uint32_le(s, requestedFormatId); @@ -1146,7 +1148,7 @@ clipboard_process_data_request(struct stream *s, int clip_msg_status, else { log_debug("clipboard_process_data_request: CB_FORMAT_FILE, " - "calling XConvertSelection to g_utf8_atom"); + "calling XConvertSelection to g_utf8_atom"); g_clip_s2c.xrdp_clip_type = XRDP_CB_FILE; XConvertSelection(g_display, g_clipboard_atom, g_clip_s2c.type, g_clip_property_atom, g_wnd, CurrentTime); @@ -1162,7 +1164,7 @@ clipboard_process_data_request(struct stream *s, int clip_msg_status, else { log_debug("clipboard_process_data_request: CB_FORMAT_DIB, " - "calling XConvertSelection to g_image_bmp_atom"); + "calling XConvertSelection to g_image_bmp_atom"); g_clip_s2c.xrdp_clip_type = XRDP_CB_BITMAP; XConvertSelection(g_display, g_clipboard_atom, g_image_bmp_atom, g_clip_property_atom, g_wnd, CurrentTime); @@ -1178,7 +1180,7 @@ clipboard_process_data_request(struct stream *s, int clip_msg_status, else { log_debug("clipboard_process_data_request: CB_FORMAT_UNICODETEXT, " - "calling XConvertSelection to g_utf8_atom"); + "calling XConvertSelection to g_utf8_atom"); g_clip_s2c.xrdp_clip_type = XRDP_CB_TEXT; XConvertSelection(g_display, g_clipboard_atom, g_utf8_atom, g_clip_property_atom, g_wnd, CurrentTime); @@ -1186,7 +1188,7 @@ clipboard_process_data_request(struct stream *s, int clip_msg_status, break; default: log_debug("clipboard_process_data_request: unknown type %d", - requestedFormatId); + requestedFormatId); clipboard_send_data_response_failed(); break; } @@ -1201,14 +1203,14 @@ clipboard_process_data_request(struct stream *s, int clip_msg_status, clipboard data. */ static int clipboard_process_data_response_for_image(struct stream *s, - int clip_msg_status, - int clip_msg_len) + int clip_msg_status, + int clip_msg_len) { XSelectionRequestEvent *lxev; int len; log_debug("clipboard_process_data_response_for_image: " - "CLIPRDR_DATA_RESPONSE_FOR_IMAGE"); + "CLIPRDR_DATA_RESPONSE_FOR_IMAGE"); lxev = &g_saved_selection_req_event; len = (int)(s->end - s->p); if (len < 1) @@ -1231,7 +1233,7 @@ clipboard_process_data_response_for_image(struct stream *s, g_memcpy(g_clip_c2s.data, g_bmp_image_header, 14); in_uint8a(s, g_clip_c2s.data + 14, len); log_debug("clipboard_process_data_response_for_image: calling " - "clipboard_provide_selection_c2s"); + "clipboard_provide_selection_c2s"); clipboard_provide_selection_c2s(lxev, lxev->target); return 0; } @@ -1259,7 +1261,7 @@ clipboard_process_data_response(struct stream *s, int clip_msg_status, if (g_clip_c2s.xrdp_clip_type == XRDP_CB_BITMAP) { clipboard_process_data_response_for_image(s, clip_msg_status, - clip_msg_len); + clip_msg_len); return 0; } if (g_clip_c2s.xrdp_clip_type == XRDP_CB_FILE) @@ -1287,7 +1289,7 @@ clipboard_process_data_response(struct stream *s, int clip_msg_status, return 0; } log_debug("clipboard_process_data_response: " - "CLIPRDR_DATA_RESPONSE"); + "CLIPRDR_DATA_RESPONSE"); len = (int)(s->end - s->p); if (len < 1) { @@ -1362,10 +1364,10 @@ clipboard_process_clip_caps(struct stream *s, int clip_msg_status, in_uint32_le(s, version); /* version */ in_uint32_le(s, flags); /* generalFlags */ log_debug("clipboard_process_clip_caps: " - "g_cliprdr_version %d version %d " - "g_cliprdr_flags 0x%x flags 0x%x", - g_cliprdr_version, version, - g_cliprdr_flags, flags); + "g_cliprdr_version %d version %d " + "g_cliprdr_flags 0x%x flags 0x%x", + g_cliprdr_version, version, + g_cliprdr_flags, flags); if (version < g_cliprdr_version) { g_cliprdr_version = version; @@ -1374,7 +1376,7 @@ clipboard_process_clip_caps(struct stream *s, int clip_msg_status, break; default: log_debug("clipboard_process_clip_caps: unknown " - "capabilitySetType %d", capabilitySetType); + "capabilitySetType %d", capabilitySetType); break; } s->p = holdp + lengthCapability; @@ -1552,16 +1554,16 @@ clipboard_data_in(struct stream *s, int chan_id, int chan_flags, int length, if (!g_clip_up) { log_error("aborting clipboard_data_in - clipboard has not " - "been initialized"); + "been initialized"); /* we return 0 here to indicate no protocol problem occurred */ return 0; } log_debug("clipboard_data_in: chan_id %d " - "chan_flags 0x%x length %d total_length %d " - "in_request %d g_ins->size %d", - chan_id, chan_flags, length, total_length, - g_clip_c2s.in_request, g_ins->size); + "chan_flags 0x%x length %d total_length %d " + "in_request %d g_ins->size %d", + chan_id, chan_flags, length, total_length, + g_clip_c2s.in_request, g_ins->size); if (g_clip_c2s.doing_response_ss) { @@ -1621,37 +1623,37 @@ clipboard_data_in(struct stream *s, int chan_id, int chan_flags, int length, in_uint32_le(ls, clip_msg_len); log_debug("clipboard_data_in: clip_msg_id %d " - "clip_msg_status %d clip_msg_len %d", - clip_msg_id, clip_msg_status, clip_msg_len); + "clip_msg_status %d clip_msg_len %d", + clip_msg_id, clip_msg_status, clip_msg_len); rv = 0; log_debug("clipboard_data_in: %d", clip_msg_id); switch (clip_msg_id) { - /* sent by client or server when its local system clipboard is */ - /* updated with new clipboard data; contains Clipboard Format ID */ - /* and name pairs of new Clipboard Formats on the clipboard. */ + /* sent by client or server when its local system clipboard is */ + /* updated with new clipboard data; contains Clipboard Format ID */ + /* and name pairs of new Clipboard Formats on the clipboard. */ case CB_FORMAT_LIST: /* 2 CLIPRDR_FORMAT_ANNOUNCE */ rv = clipboard_process_format_announce(ls, clip_msg_status, clip_msg_len); break; - /* response to CB_FORMAT_LIST; used to indicate whether */ - /* processing of the Format List PDU was successful */ + /* response to CB_FORMAT_LIST; used to indicate whether */ + /* processing of the Format List PDU was successful */ case CB_FORMAT_LIST_RESPONSE: /* 3 CLIPRDR_FORMAT_ACK */ rv = clipboard_process_format_ack(ls, clip_msg_status, clip_msg_len); break; - /* sent by recipient of CB_FORMAT_LIST; used to request data for one */ - /* of the formats that was listed in CB_FORMAT_LIST */ + /* sent by recipient of CB_FORMAT_LIST; used to request data for one */ + /* of the formats that was listed in CB_FORMAT_LIST */ case CB_FORMAT_DATA_REQUEST: /* 4 CLIPRDR_DATA_REQUEST */ rv = clipboard_process_data_request(ls, clip_msg_status, clip_msg_len); break; - /* sent as a reply to CB_FORMAT_DATA_REQUEST; used to indicate */ - /* whether processing of the CB_FORMAT_DATA_REQUEST was */ - /* successful; if processing was successful, */ - /* CB_FORMAT_DATA_RESPONSE includes contents of requested */ - /* clipboard data. */ + /* sent as a reply to CB_FORMAT_DATA_REQUEST; used to indicate */ + /* whether processing of the CB_FORMAT_DATA_REQUEST was */ + /* successful; if processing was successful, */ + /* CB_FORMAT_DATA_RESPONSE includes contents of requested */ + /* clipboard data. */ case CB_FORMAT_DATA_RESPONSE: /* 5 CLIPRDR_DATA_RESPONSE */ rv = clipboard_process_data_response(ls, clip_msg_status, clip_msg_len); @@ -1671,7 +1673,7 @@ clipboard_data_in(struct stream *s, int chan_id, int chan_flags, int length, default: log_debug("clipboard_data_in: unknown clip_msg_id %d", clip_msg_id); log_error("clipboard_data_in: unknown clip_msg_id %d", - clip_msg_id); + clip_msg_id); break; } @@ -1703,21 +1705,22 @@ clipboard_event_selection_owner_notify(XEvent *xevent) lxevent = (XFixesSelectionNotifyEvent *)xevent; log_debug("clipboard_event_selection_owner_notify: 0x%lx", lxevent->owner); log_debug("clipboard_event_selection_owner_notify: " - "window %ld subtype %d owner %ld g_wnd %ld", - lxevent->window, lxevent->subtype, lxevent->owner, g_wnd); + "window %ld subtype %d owner %ld g_wnd %ld", + lxevent->window, lxevent->subtype, lxevent->owner, g_wnd); if (lxevent->owner == g_wnd) { log_debug("clipboard_event_selection_owner_notify: matches g_wnd"); log_debug("clipboard_event_selection_owner_notify: skipping, " - "owner == g_wnd"); + "owner == g_wnd"); g_got_selection = 1; return 0; } g_got_selection = 0; if (lxevent->owner != 0) /* nil owner comes when selection */ - { /* window is closed */ + { + /* window is closed */ XConvertSelection(g_display, g_clipboard_atom, g_targets_atom, g_clip_property_atom, g_wnd, lxevent->timestamp); } @@ -1871,22 +1874,22 @@ clipboard_event_selection_notify(XEvent *xevent) if (lxevent->property == None) { log_error("clipboard_event_selection_notify: clip could " - "not be converted"); + "not be converted"); rv = 1; } if (rv == 0) { log_debug("clipboard_event_selection_notify: wnd 0x%lx prop %s", - lxevent->requestor, - get_atom_text(lxevent->property)); + lxevent->requestor, + get_atom_text(lxevent->property)); rv = clipboard_get_window_property(lxevent->requestor, lxevent->property, &type, &fmt, &n_items, &data, &data_size); if (rv != 0) { log_error("clipboard_event_selection_notify: " - "clipboard_get_window_property failed error %d", rv); + "clipboard_get_window_property failed error %d", rv); return 0; } //g_hexdump(data, data_size); @@ -1896,9 +1899,9 @@ clipboard_event_selection_notify(XEvent *xevent) /* nothing more to do here, the data is coming in through PropertyNotify */ log_debug("clipboard_event_selection_notify: type is INCR " - "data_size %d property name %s type %s", data_size, - get_atom_text(lxevent->property), - get_atom_text(lxevent->type)); + "data_size %d property name %s type %s", data_size, + get_atom_text(lxevent->property), + get_atom_text(lxevent->type)); g_clip_s2c.incr_in_progress = 1; g_clip_s2c.property = lxevent->property; g_clip_s2c.type = lxevent->target; @@ -1928,7 +1931,7 @@ clipboard_event_selection_notify(XEvent *xevent) "clipboard_event_selection_notify: 0x%lx %s 0x%lx", atom, get_atom_text(atom), XA_STRING)); log_debug("clipboard_event_selection_notify: 0x%lx %s", - atom, get_atom_text(atom)); + atom, get_atom_text(atom)); if (atom == g_utf8_atom) { got_utf8 = 1; @@ -1955,16 +1958,16 @@ clipboard_event_selection_notify(XEvent *xevent) else { log_error("clipboard_event_selection_notify: error, " - "target is 'TARGETS' and type[%ld] or fmt[%d] not right, " - "should be type[%ld], fmt[%d]", type, fmt, XA_ATOM, 32); + "target is 'TARGETS' and type[%ld] or fmt[%d] not right, " + "should be type[%ld], fmt[%d]", type, fmt, XA_ATOM, 32); } } else if (lxevent->target == g_utf8_atom) { log_debug("clipboard_event_selection_notify: UTF8_STRING " - "data_size %d", data_size); + "data_size %d", data_size); log_debug("clipboard_event_selection_notify: UTF8_STRING " - "data_size %d", data_size); + "data_size %d", data_size); if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 0)) { g_free(g_clip_s2c.data); @@ -1987,9 +1990,9 @@ clipboard_event_selection_notify(XEvent *xevent) else if (lxevent->target == XA_STRING) { log_debug("clipboard_event_selection_notify: XA_STRING " - "data_size %d", data_size); + "data_size %d", data_size); log_debug("clipboard_event_selection_notify: XA_STRING " - "data_size %d", data_size); + "data_size %d", data_size); if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 0)) { g_free(g_clip_s2c.data); @@ -2004,9 +2007,9 @@ clipboard_event_selection_notify(XEvent *xevent) else if (lxevent->target == g_image_bmp_atom) { log_debug("clipboard_event_selection_notify: image/bmp " - "data_size %d", data_size); + "data_size %d", data_size); log_debug("clipboard_event_selection_notify: image/bmp " - "data_size %d", data_size); + "data_size %d", data_size); if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 14)) { g_free(g_clip_s2c.data); @@ -2020,9 +2023,9 @@ clipboard_event_selection_notify(XEvent *xevent) else if (lxevent->target == g_file_atom1) { log_debug("clipboard_event_selection_notify: text/uri-list " - "data_size %d", data_size); + "data_size %d", data_size); log_debug("clipboard_event_selection_notify: text/uri-list " - "data_size %d", data_size); + "data_size %d", data_size); if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 0)) { g_free(g_clip_s2c.data); @@ -2037,9 +2040,9 @@ clipboard_event_selection_notify(XEvent *xevent) else if (lxevent->target == g_file_atom2) { log_debug("clipboard_event_selection_notify: text/uri-list " - "data_size %d", data_size); + "data_size %d", data_size); log_debug("clipboard_event_selection_notify: text/uri-list " - "data_size %d", data_size); + "data_size %d", data_size); if ((g_clip_s2c.incr_in_progress == 0) && (data_size > 0)) { g_free(g_clip_s2c.data); @@ -2054,13 +2057,13 @@ clipboard_event_selection_notify(XEvent *xevent) else { log_error("clipboard_event_selection_notify: " - "unknown target"); + "unknown target"); } } else { log_error("clipboard_event_selection_notify: " - "unknown selection"); + "unknown selection"); } } @@ -2145,24 +2148,24 @@ clipboard_event_selection_request(XEvent *xevent) lxev = (XSelectionRequestEvent *)xevent; log_debug("clipboard_event_selection_request: 0x%lx", lxev->property); log_debug("clipboard_event_selection_request: g_wnd %ld, " - ".requestor %ld .owner %ld .selection %ld '%s' .target %ld .property %ld", - g_wnd, lxev->requestor, lxev->owner, lxev->selection, - get_atom_text(lxev->selection), - lxev->target, lxev->property); + ".requestor %ld .owner %ld .selection %ld '%s' .target %ld .property %ld", + g_wnd, lxev->requestor, lxev->owner, lxev->selection, + get_atom_text(lxev->selection), + lxev->target, lxev->property); if (lxev->property == None) { log_debug("clipboard_event_selection_request: lxev->property " - "is None"); + "is None"); log_debug("clipboard_event_selection_request: " - "lxev->property is None"); + "lxev->property is None"); } else if (lxev->target == g_targets_atom) { log_debug("clipboard_event_selection_request: g_targets_atom"); /* requestor is asking what the selection can be converted to */ log_debug("clipboard_event_selection_request: " - "g_targets_atom"); + "g_targets_atom"); atom_buf[0] = g_targets_atom; atom_buf[1] = g_timestamp_atom; atom_buf[2] = g_multiple_atom; @@ -2193,7 +2196,7 @@ clipboard_event_selection_request(XEvent *xevent) { /* requestor is asking the time I got the selection */ log_debug("clipboard_event_selection_request: " - "g_timestamp_atom"); + "g_timestamp_atom"); atom_buf[0] = g_selection_time; atom_buf[1] = 0; return clipboard_provide_selection(lxev, XA_INTEGER, 32, @@ -2203,7 +2206,7 @@ clipboard_event_selection_request(XEvent *xevent) { /* target, property pairs */ log_debug("clipboard_event_selection_request: " - "g_multiple_atom"); + "g_multiple_atom"); xdata = 0; if (clipboard_get_window_property(lxev->requestor, lxev->property, @@ -2211,7 +2214,7 @@ clipboard_event_selection_request(XEvent *xevent) &xdata_size) == 0) { log_debug("clipboard_event_selection_request: g_multiple_atom " - "n_items %d", n_items); + "n_items %d", n_items); /* todo */ g_free(xdata); } @@ -2276,7 +2279,7 @@ clipboard_event_selection_request(XEvent *xevent) else { log_debug("clipboard_event_selection_request: unknown " - "target %s", get_atom_text(lxev->target)); + "target %s", get_atom_text(lxev->target)); LOGM((LOG_LEVEL_ERROR, "clipboard_event_selection_request: unknown " "target %s", get_atom_text(lxev->target))); } @@ -2332,9 +2335,9 @@ clipboard_event_property_notify(XEvent *xevent) log_debug("clipboard_event_property_notify:"); log_debug("clipboard_event_property_notify: PropertyNotify .window %ld " - ".state %d .atom %ld %s", xevent->xproperty.window, - xevent->xproperty.state, xevent->xproperty.atom, - get_atom_text(xevent->xproperty.atom)); + ".state %d .atom %ld %s", xevent->xproperty.window, + xevent->xproperty.state, xevent->xproperty.atom, + get_atom_text(xevent->xproperty.atom)); if (g_clip_c2s.incr_in_progress && (xevent->xproperty.window == g_clip_c2s.window) && @@ -2353,7 +2356,7 @@ clipboard_event_property_notify(XEvent *xevent) data = (tui8 *)(g_clip_c2s.data + g_clip_c2s.incr_bytes_done); data_bytes = g_clip_c2s.read_bytes_done - g_clip_c2s.incr_bytes_done; if ((data_bytes < 1) && - (g_clip_c2s.read_bytes_done < g_clip_c2s.total_bytes)) + (g_clip_c2s.read_bytes_done < g_clip_c2s.total_bytes)) { g_clip_c2s.incr_in_progress = 0; return 0; @@ -2423,7 +2426,7 @@ clipboard_event_property_notify(XEvent *xevent) else { log_error("clipboard_event_property_notify: error unknown type %ld", - g_clip_s2c.type); + g_clip_s2c.type); clipboard_send_data_response_failed(); } @@ -2484,6 +2487,8 @@ clipboard_xevent(void *xevent) { XEvent *lxevent; + log_debug("clipboard_xevent: event detected"); + if (!g_clip_up) { return 1; @@ -2494,7 +2499,15 @@ clipboard_xevent(void *xevent) switch (lxevent->type) { case SelectionNotify: - clipboard_event_selection_notify(lxevent); + if (g_restrict_outbound_clipboard == 0) + { + clipboard_event_selection_notify(lxevent); + } + else + { + log_debug("outbound clipboard is restricted because of config"); + return 1; + } break; case SelectionRequest: clipboard_event_selection_request(lxevent); diff --git a/sesman/config.c b/sesman/config.c index 78949995..1639517d 100644 --- a/sesman/config.c +++ b/sesman/config.c @@ -235,6 +235,7 @@ config_read_security(int file, struct config_security *sc, sc->login_retry = 3; sc->ts_users_enable = 0; sc->ts_admins_enable = 0; + sc->restrict_outbound_clipboard = 0; file_read_section(file, SESMAN_CFG_SECURITY, param_n, param_v); @@ -273,6 +274,12 @@ config_read_security(int file, struct config_security *sc, { sc->ts_always_group_check = g_text2bool((char *)list_get_item(param_v, i)); } + + if (0 == g_strcasecmp(buf, SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD)) + { + sc->restrict_outbound_clipboard = g_text2bool((char *)list_get_item(param_v, i)); + } + } return 0; @@ -481,7 +488,7 @@ config_dump(struct config_sesman *config) g_writeln(" DefaultWindowManager: %s", config->default_wm); g_writeln(" ReconnectScript: %s", config->reconnect_sh); g_writeln(" AuthFilePath: %s", - ((config->auth_file_path) ? (config->auth_file_path) : ("disabled"))); + ((config->auth_file_path) ? (config->auth_file_path) : ("disabled"))); /* Session configuration */ g_writeln("Session configuration:"); @@ -497,6 +504,7 @@ config_dump(struct config_sesman *config) 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_printf( " TSUsersGroup: "); if (sc->ts_users_enable) @@ -530,7 +538,7 @@ config_dump(struct config_sesman *config) for (i = 0; i < config->xorg_params->count; i++) { g_writeln(" Parameter %02d %s", - i, (char *) list_get_item(config->xorg_params, i)); + i, (char *) list_get_item(config->xorg_params, i)); } /* Xvnc */ @@ -542,7 +550,7 @@ config_dump(struct config_sesman *config) for (i = 0; i < config->vnc_params->count; i++) { g_writeln(" Parameter %02d %s", - i, (char *)list_get_item(config->vnc_params, i)); + i, (char *)list_get_item(config->vnc_params, i)); } /* X11rdp */ @@ -554,7 +562,7 @@ config_dump(struct config_sesman *config) for (i = 0; i < config->rdp_params->count; i++) { g_writeln(" Parameter %02d %s", - i, (char *)list_get_item(config->rdp_params, i)); + i, (char *)list_get_item(config->rdp_params, i)); } /* SessionVariables */ @@ -567,7 +575,7 @@ config_dump(struct config_sesman *config) { g_writeln(" Parameter %02d %s=%s", i, (char *) list_get_item(config->env_names, i), - (char *) list_get_item(config->env_values, i)); + (char *) list_get_item(config->env_values, i)); } } diff --git a/sesman/config.h b/sesman/config.h index 6e63fcef..d465687f 100644 --- a/sesman/config.h +++ b/sesman/config.h @@ -54,12 +54,13 @@ #define SESMAN_CFG_LOG_ENABLE_SYSLOG "EnableSyslog" #define SESMAN_CFG_LOG_SYSLOG_LEVEL "SyslogLevel" */ -#define SESMAN_CFG_SECURITY "Security" -#define SESMAN_CFG_SEC_LOGIN_RETRY "MaxLoginRetry" -#define SESMAN_CFG_SEC_ALLOW_ROOT "AllowRootLogin" -#define SESMAN_CFG_SEC_USR_GROUP "TerminalServerUsers" -#define SESMAN_CFG_SEC_ADM_GROUP "TerminalServerAdmins" -#define SESMAN_CFG_SEC_ALWAYSGROUPCHECK "AlwaysGroupCheck" +#define SESMAN_CFG_SECURITY "Security" +#define SESMAN_CFG_SEC_LOGIN_RETRY "MaxLoginRetry" +#define SESMAN_CFG_SEC_ALLOW_ROOT "AllowRootLogin" +#define SESMAN_CFG_SEC_USR_GROUP "TerminalServerUsers" +#define SESMAN_CFG_SEC_ADM_GROUP "TerminalServerAdmins" +#define SESMAN_CFG_SEC_ALWAYSGROUPCHECK "AlwaysGroupCheck" +#define SESMAN_CFG_SEC_RESTRICT_OUTBOUND_CLIPBOARD "RestrictOutboundClipboard" #define SESMAN_CFG_SESSIONS "Sessions" #define SESMAN_CFG_SESS_MAX "MaxSessions" @@ -126,6 +127,11 @@ struct config_security * @brief if the Groups are not found deny access */ int ts_always_group_check; + /** + * @var restrict_outbound_clipboard + * @brief if the clipboard should be enforced restricted. If true only allow client -> server, not vice versa. + */ + int restrict_outbound_clipboard; }; /** diff --git a/sesman/sesman.ini.in b/sesman/sesman.ini.in index 9af7a100..1c3147ad 100644 --- a/sesman/sesman.ini.in +++ b/sesman/sesman.ini.in @@ -19,6 +19,9 @@ TerminalServerAdmins=tsadmins ; When AlwaysGroupCheck=false access will be permitted ; if the group TerminalServerUsers is not defined. AlwaysGroupCheck=false +; When RestrictOutboundClipboard=true clipboard from the +; server is not pushed to the client. +RestrictOutboundClipboard=false [Sessions] ;; X11DisplayOffset - x11 display number offset diff --git a/sesman/session.c b/sesman/session.c index 0d9fdc70..9fab0392 100644 --- a/sesman/session.c +++ b/sesman/session.c @@ -374,6 +374,11 @@ session_start_chansrv(char *username, int display) g_cfg->env_names, g_cfg->env_values); + if (g_cfg->sec.restrict_outbound_clipboard == 1) + { + g_setenv("CHANSRV_RESTRICT_OUTBOUND_CLIPBOARD", "1", 1); + } + /* executing chansrv */ g_execvp(exe_path, (char **) (chansrv_params->items)); /* should not get here */