Skip to content

Commit e679a35

Browse files
committed
Clear global clipboard after specified seconds
fixes: QubesOS/qubes-issues#6641
1 parent ed101ff commit e679a35

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

gui-daemon/xside.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,7 @@ static void save_clipboard_metadata(struct clipboard_metadata *metadata) {
880880
fprintf(file, "\"buffer_size\":%d,\n", metadata->buffer_size);
881881
fprintf(file, "\"protocol_version_xside\":%d,\n", metadata->protocol_version_xside);
882882
fprintf(file, "\"protocol_version_vmside\":%d\n", metadata->protocol_version_vmside);
883+
fprintf(file, "\"timeout\":%d\n", metadata->timeout);
883884
// other key,value pairs could be added if needed in future
884885
fprintf(file, "}\n");
885886
fclose(file);
@@ -959,6 +960,8 @@ static bool load_clipboard_metadata(struct clipboard_metadata *metadata, bool lo
959960
metadata->protocol_version_vmside = dummy;
960961
} else if (strcmp(key, "protocol_version_xside") == 0) {
961962
metadata->protocol_version_xside = dummy;
963+
} else if (strcmp(key, "timeout") == 0) {
964+
metadata->timeout = dummy;
962965
}
963966
}
964967
fclose(file);
@@ -1219,6 +1222,13 @@ static void handle_clipboard_data(Ghandles * g, unsigned int untrusted_len)
12191222
metadata.protocol_version_vmside = g->protocol_version;
12201223
metadata.protocol_version_xside = PROTOCOL_VERSION(
12211224
PROTOCOL_VERSION_MAJOR, PROTOCOL_VERSION_MINOR);
1225+
metadata.timeout = g->clipboard_timeout;
1226+
1227+
// if a clipboard timeout child is pending, terminate it and clear its PID.
1228+
if (g->clipboard_timeout_pid) {
1229+
kill(g->clipboard_timeout_pid, SIGTERM);
1230+
g->clipboard_timeout_pid = 0;
1231+
}
12221232

12231233
if (g->log_level > 0)
12241234
fprintf(stderr, "handle_clipboard_data, len=0x%x\n",
@@ -1301,6 +1311,42 @@ static void handle_clipboard_data(Ghandles * g, unsigned int untrusted_len)
13011311
save_clipboard_file_xevent_timestamp(g->clipboard_xevent_time);
13021312
metadata.successful = true;
13031313
save_clipboard_metadata(&metadata);
1314+
1315+
if (g->clipboard_timeout > 0) {
1316+
struct stat st0, st1;
1317+
if (lstat(QUBES_CLIPBOARD_FILENAME, &st0) == -1) {
1318+
perror("Can not get clipboard data file status");
1319+
exit(1);
1320+
}
1321+
switch (g->clipboard_timeout_pid = fork()) {
1322+
case -1:
1323+
perror("fork");
1324+
exit(1);
1325+
case 0:
1326+
if (sleep(g->clipboard_timeout) != 0) {
1327+
perror("Clipboard clearing timeout was interrupted");
1328+
_exit(1);
1329+
}
1330+
inter_appviewer_lock(g, 1);
1331+
if (lstat(QUBES_CLIPBOARD_FILENAME, &st1) == -1) {
1332+
perror("Can not get clipboard data file status");
1333+
_exit(1);
1334+
}
1335+
if (st0.st_mtime == st1.st_mtime) {
1336+
old_umask = umask(0007);
1337+
metadata.copy_action = false;
1338+
metadata.timeout = g->clipboard_timeout;
1339+
clear_clipboard(&metadata);
1340+
umask(old_umask);
1341+
if (g->log_level > 1)
1342+
fprintf(stderr, "Clipboard cleared after %d seconds\n",
1343+
g->clipboard_timeout);
1344+
}
1345+
inter_appviewer_lock(g, 0);
1346+
_exit(1);
1347+
}
1348+
}
1349+
13041350
error:
13051351
umask(old_umask);
13061352
inter_appviewer_lock(g, 0);
@@ -4494,6 +4540,8 @@ static void load_default_config_values(Ghandles * g)
44944540
g->paste_seq_mask = ControlMask | ShiftMask;
44954541
g->paste_seq_key = XK_v;
44964542
g->clipboard_buffer_size = DEFAULT_CLIPBOARD_BUFFER_SIZE;
4543+
g->clipboard_timeout = 0;
4544+
g->clipboard_timeout_pid = 0;
44974545
g->allow_fullscreen = 0;
44984546
g->override_redirect_protection = 1;
44994547
g->startup_timeout = 45;
@@ -4588,6 +4636,11 @@ static void parse_vm_config(Ghandles * g, config_setting_t * group)
45884636
}
45894637
}
45904638

4639+
if ((setting =
4640+
config_setting_get_member(group, "clipboard_timeout"))) {
4641+
g->clipboard_timeout = config_setting_get_int(setting);
4642+
}
4643+
45914644
if ((setting =
45924645
config_setting_get_member(group, "allow_utf8_titles"))) {
45934646
g->allow_utf8_titles = config_setting_get_bool(setting);
@@ -4976,6 +5029,8 @@ int main(int argc, char **argv)
49765029
ebuf_release_xevents(&ghandles);
49775030
}
49785031
} while (busy);
5032+
if (ghandles.clipboard_timeout_pid > 0)
5033+
kill(ghandles.clipboard_timeout_pid, SIGTERM);
49795034
if (ghandles.ebuf_max_delay > 0) {
49805035
wait_for_vchan_or_argfd_once(ghandles.vchan, xfd, ghandles.ebuf_next_timeout);
49815036
} else {

gui-daemon/xside.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ struct _global_handles {
241241
KeySym paste_seq_key; /* key for secure-paste key sequence */
242242
unsigned int clipboard_buffer_size; /* maximum clipboard size limit */
243243
int qrexec_clipboard; /* 0: use GUI protocol to fetch/put clipboard, 1: use qrexec */
244+
unsigned int clipboard_timeout; /* x: clear global clipboard after x seconds, 0: do not clear */
245+
pid_t clipboard_timeout_pid; /* pid of the existing clipboard timeout child (if any) */
244246
int use_kdialog; /* use kdialog for prompts (default on KDE) or zenity (default on non-KDE) */
245247
int prefix_titles; /* prefix windows titles with VM name (for WM without support for _QUBES_VMNAME property) */
246248
enum trayicon_mode trayicon_mode; /* trayicon coloring mode */
@@ -348,6 +350,7 @@ struct clipboard_metadata {
348350
unsigned int buffer_size; /* maximum allowed clipboard size for this vm */
349351
uint32_t protocol_version_vmside; /* inter-vm clipboard GUI protocol version - vmside */
350352
uint32_t protocol_version_xside; /* inter-vm clipboard GUI protocol version - xside */
353+
unsigned int timeout; /* 0: Clipboard is/will be NOT automatically cleared. x: is/will be cleared after x seconds */
351354
};
352355

353356
#define QUBES_NO_SHM_SEGMENT ((xcb_shm_seg_t)-1)

0 commit comments

Comments
 (0)