diff --git a/SOURCES/0015-audio-add-functions-to-set-volume-mute-with-alsa.patch b/SOURCES/0015-audio-add-functions-to-set-volume-mute-with-alsa.patch new file mode 100644 index 0000000..d901932 --- /dev/null +++ b/SOURCES/0015-audio-add-functions-to-set-volume-mute-with-alsa.patch @@ -0,0 +1,269 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Fri, 6 Mar 2015 18:14:21 +0100 +Subject: [PATCH] audio: add functions to set volume/mute with alsa + +This patch includes the vdagent-audio.[ch] files in order to +communicate with backend audio server. + +The two functions provide a way to set volume and mute in the guest +by connecting to default mixer control in alsa which is 'Master' for +playback and 'Capture' for record. +--- + Makefile.am | 12 +++- + configure.ac | 1 + + src/vdagent-audio.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/vdagent-audio.h | 27 +++++++++ + 4 files changed, 205 insertions(+), 3 deletions(-) + create mode 100644 src/vdagent-audio.c + create mode 100644 src/vdagent-audio.h + +diff --git a/Makefile.am b/Makefile.am +index a06a259..2effe4e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -4,9 +4,14 @@ NULL = + bin_PROGRAMS = src/spice-vdagent + sbin_PROGRAMS = src/spice-vdagentd + +-src_spice_vdagent_CFLAGS = $(X_CFLAGS) $(SPICE_CFLAGS) $(GLIB2_CFLAGS) +-src_spice_vdagent_LDADD = $(X_LIBS) $(SPICE_LIBS) $(GLIB2_LIBS) +-src_spice_vdagent_SOURCES = src/vdagent.c src/vdagent-x11.c src/vdagent-x11-randr.c src/vdagent-file-xfers.c src/udscs.c ++src_spice_vdagent_CFLAGS = $(X_CFLAGS) $(SPICE_CFLAGS) $(GLIB2_CFLAGS) $(ALSA_CFLAGS) ++src_spice_vdagent_LDADD = $(X_LIBS) $(SPICE_LIBS) $(GLIB2_LIBS) $(ALSA_LIBS) ++src_spice_vdagent_SOURCES = src/vdagent.c \ ++ src/vdagent-x11.c \ ++ src/vdagent-x11-randr.c \ ++ src/vdagent-file-xfers.c \ ++ src/vdagent-audio.c \ ++ src/udscs.c + + src_spice_vdagentd_CFLAGS = $(DBUS_CFLAGS) $(LIBSYSTEMD_LOGIN_CFLAGS) \ + $(PCIACCESS_CFLAGS) $(SPICE_CFLAGS) $(GLIB2_CFLAGS) $(PIE_CFLAGS) +@@ -30,6 +35,7 @@ endif + noinst_HEADERS = src/glib-compat.h \ + src/session-info.h \ + src/udscs.h \ ++ src/vdagent-audio.h \ + src/vdagent-file-xfers.h \ + src/vdagent-virtio-port.h \ + src/vdagent-x11.h \ +diff --git a/configure.ac b/configure.ac +index a1ce6c0..377fc74 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -79,6 +79,7 @@ AC_ARG_ENABLE([static-uinput], + PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= 2.12]) + PKG_CHECK_MODULES(X, [xfixes xrandr >= 1.3 xinerama x11]) + PKG_CHECK_MODULES(SPICE, [spice-protocol >= 0.12.5]) ++PKG_CHECK_MODULES(ALSA, [alsa >= 1.0.22]) + + if test "$with_session_info" = "auto" || test "$with_session_info" = "systemd"; then + PKG_CHECK_MODULES([LIBSYSTEMD_LOGIN], +diff --git a/src/vdagent-audio.c b/src/vdagent-audio.c +new file mode 100644 +index 0000000..6b11cd8 +--- /dev/null ++++ b/src/vdagent-audio.c +@@ -0,0 +1,168 @@ ++/* vdagent-audio.c vdagentd audio handling code ++ ++ Copyright 2015 Red Hat, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "vdagent-audio.h" ++ ++#define ALSA_MUTE 0 ++#define ALSA_UNMUTE 1 ++ ++static snd_mixer_elem_t * ++get_alsa_default_mixer_by_name(snd_mixer_t **handle, const char *name) ++{ ++ snd_mixer_selem_id_t *sid; ++ int err = 0; ++ ++ if ((err = snd_mixer_open(handle, 0)) < 0) ++ goto fail; ++ ++ if ((err = snd_mixer_attach(*handle, "default")) < 0) ++ goto fail; ++ ++ if ((err = snd_mixer_selem_register(*handle, NULL, NULL)) < 0) ++ goto fail; ++ ++ if ((err = snd_mixer_load(*handle)) < 0) ++ goto fail; ++ ++ snd_mixer_selem_id_alloca(&sid); ++ snd_mixer_selem_id_set_index(sid, 0); ++ snd_mixer_selem_id_set_name(sid, name); ++ return snd_mixer_find_selem(*handle, sid); ++ ++fail: ++ syslog(LOG_WARNING, "%s fail: %s", __func__, snd_strerror(err)); ++ return NULL; ++} ++ ++static bool set_alsa_capture(uint8_t mute, uint8_t nchannels, uint16_t *volume) ++{ ++ snd_mixer_t *handle = NULL; ++ snd_mixer_elem_t *e; ++ long min, max, vol; ++ bool ret = true; ++ int alsa_mute; ++ ++ e = get_alsa_default_mixer_by_name (&handle, "Capture"); ++ if (e == NULL) { ++ syslog(LOG_WARNING, "vdagent-audio: can't get default alsa mixer"); ++ ret = false; ++ goto end; ++ } ++ ++ alsa_mute = (mute) ? ALSA_MUTE : ALSA_UNMUTE; ++ snd_mixer_selem_set_capture_switch_all(e, alsa_mute); ++ ++ snd_mixer_selem_get_capture_volume_range(e, &min, &max); ++ switch (nchannels) { ++ case 1: /* MONO */ ++ vol = CLAMP(volume[0], min, max); ++ snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_MONO, vol); ++ syslog(LOG_DEBUG, "vdagent-audio: (capture-mono) %lu (%%%0.2f)", ++ vol, (float) (100*vol/max)); ++ break; ++ case 2: /* LEFT-RIGHT */ ++ vol = CLAMP(volume[0], min, max); ++ snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_FRONT_LEFT, vol); ++ syslog(LOG_DEBUG, "vdagent-audio: (capture-left) %lu (%%%0.2f)", ++ vol, (float) (100*vol/max)); ++ vol = CLAMP(volume[1], min, max); ++ snd_mixer_selem_set_capture_volume(e, SND_MIXER_SCHN_FRONT_RIGHT, vol); ++ syslog(LOG_DEBUG, "vdagent-audio: (capture-right) %lu (%%%0.2f)", ++ vol, (float) (100*vol/max)); ++ break; ++ default: ++ syslog(LOG_WARNING, "vdagent-audio: number of channels not supported"); ++ ret = false; ++ } ++end: ++ if (handle != NULL) ++ snd_mixer_close(handle); ++ return ret; ++} ++ ++static bool set_alsa_playback (uint8_t mute, uint8_t nchannels, uint16_t *volume) ++{ ++ snd_mixer_t *handle = NULL; ++ snd_mixer_elem_t* e; ++ long min, max, vol; ++ bool ret = true; ++ int alsa_mute; ++ ++ e = get_alsa_default_mixer_by_name (&handle, "Master"); ++ if (e == NULL) { ++ syslog(LOG_WARNING, "vdagent-audio: can't get default alsa mixer"); ++ ret = false; ++ goto end; ++ } ++ ++ alsa_mute = (mute) ? ALSA_MUTE : ALSA_UNMUTE; ++ snd_mixer_selem_set_playback_switch_all(e, alsa_mute); ++ ++ snd_mixer_selem_get_playback_volume_range(e, &min, &max); ++ switch (nchannels) { ++ case 1: /* MONO */ ++ vol = CLAMP(volume[0], min, max); ++ snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_MONO, vol); ++ syslog(LOG_DEBUG, "vdagent-audio: (playback-mono) %lu (%%%0.2f)", ++ vol, (float) (100*vol/max)); ++ break; ++ case 2: /* LEFT-RIGHT */ ++ vol = CLAMP(volume[0], min, max); ++ snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_FRONT_LEFT, vol); ++ syslog(LOG_DEBUG, "vdagent-audio: (playback-left) %lu (%%%0.2f)", ++ vol, (float) (100*vol/max)); ++ vol = CLAMP(volume[1], min, max); ++ snd_mixer_selem_set_playback_volume(e, SND_MIXER_SCHN_FRONT_RIGHT, vol); ++ syslog(LOG_DEBUG, "vdagent-audio: (playback-right) %lu (%%%0.2f)", ++ vol, (float) (100*vol/max)); ++ break; ++ default: ++ syslog(LOG_WARNING, "vdagent-audio: number of channels not supported"); ++ ret = false; ++ } ++end: ++ if (handle != NULL) ++ snd_mixer_close(handle); ++ return ret; ++} ++ ++void vdagent_audio_playback_sync(uint8_t mute, uint8_t nchannels, uint16_t *volume) ++{ ++ syslog(LOG_DEBUG, "%s mute=%s nchannels=%u", ++ __func__, (mute) ? "yes" : "no", nchannels); ++ if (set_alsa_playback (mute, nchannels, volume) == false) ++ syslog(LOG_WARNING, "Fail to sync playback volume"); ++} ++ ++void vdagent_audio_record_sync(uint8_t mute, uint8_t nchannels, uint16_t *volume) ++{ ++ syslog(LOG_DEBUG, "%s mute=%s nchannels=%u", ++ __func__, (mute) ? "yes" : "no", nchannels); ++ if (set_alsa_capture (mute, nchannels, volume) == false) ++ syslog(LOG_WARNING, "Fail to sync record volume"); ++} +diff --git a/src/vdagent-audio.h b/src/vdagent-audio.h +new file mode 100644 +index 0000000..6f29d4b +--- /dev/null ++++ b/src/vdagent-audio.h +@@ -0,0 +1,27 @@ ++/* vdagent-audio.h vdagentd audio handling header ++ ++ Copyright 2015 Red Hat, Inc. ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++*/ ++#ifndef __VDAGENT_AUDIO_H ++#define __VDAGENT_AUDIO_H ++ ++#include ++#include ++ ++void vdagent_audio_playback_sync(uint8_t mute, uint8_t nchannels, uint16_t *volume); ++void vdagent_audio_record_sync(uint8_t mute, uint8_t nchannels, uint16_t *volume); ++ ++#endif diff --git a/SOURCES/0016-vdagent-volume-synchronization-from-client.patch b/SOURCES/0016-vdagent-volume-synchronization-from-client.patch new file mode 100644 index 0000000..368719c --- /dev/null +++ b/SOURCES/0016-vdagent-volume-synchronization-from-client.patch @@ -0,0 +1,100 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Fri, 6 Mar 2015 18:15:35 +0100 +Subject: [PATCH] vdagent: volume synchronization from client. + +Include the capability of volume sync to set volume or mute to default +sink-input/source-output of guest. +--- + src/vdagent.c | 11 +++++++++++ + src/vdagentd-proto.h | 1 + + src/vdagentd.c | 21 +++++++++++++++++++++ + 3 files changed, 33 insertions(+) + +diff --git a/src/vdagent.c b/src/vdagent.c +index c5e09ff..a26af73 100644 +--- a/src/vdagent.c ++++ b/src/vdagent.c +@@ -39,6 +39,7 @@ + #include "udscs.h" + #include "vdagentd-proto.h" + #include "vdagentd-proto-strings.h" ++#include "vdagent-audio.h" + #include "vdagent-x11.h" + #include "vdagent-file-xfers.h" + +@@ -97,6 +98,16 @@ void daemon_read_complete(struct udscs_connection **connp, + (VDAgentFileXferStatusMessage *)data); + free(data); + break; ++ case VDAGENTD_AUDIO_VOLUME_SYNC: { ++ VDAgentAudioVolumeSync *avs = (VDAgentAudioVolumeSync *)data; ++ if (avs->is_playback) { ++ vdagent_audio_playback_sync(avs->mute, avs->nchannels, avs->volume); ++ } else { ++ vdagent_audio_record_sync(avs->mute, avs->nchannels, avs->volume); ++ } ++ free(data); ++ break; ++ } + case VDAGENTD_FILE_XFER_DATA: + vdagent_file_xfers_data(vdagent_file_xfers, + (VDAgentFileXferDataMessage *)data); +diff --git a/src/vdagentd-proto.h b/src/vdagentd-proto.h +index 25e6a36..0dbaaea 100644 +--- a/src/vdagentd-proto.h ++++ b/src/vdagentd-proto.h +@@ -36,6 +36,7 @@ enum { + VDAGENTD_CLIPBOARD_DATA, /* arg1: sel, arg 2: type, data: data */ + VDAGENTD_CLIPBOARD_RELEASE, /* arg1: selection */ + VDAGENTD_VERSION, /* daemon -> client, data: version string */ ++ VDAGENTD_AUDIO_VOLUME_SYNC, + VDAGENTD_FILE_XFER_START, + VDAGENTD_FILE_XFER_STATUS, + VDAGENTD_FILE_XFER_DATA, +diff --git a/src/vdagentd.c b/src/vdagentd.c +index 6280dfa..594f36b 100644 +--- a/src/vdagentd.c ++++ b/src/vdagentd.c +@@ -96,6 +96,7 @@ static void send_capabilities(struct vdagent_virtio_port *vport, + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_SELECTION); + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG); + VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_GUEST_LINEEND_LF); ++ VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_AUDIO_VOLUME_SYNC); + + vdagent_virtio_port_write(vport, VDP_CLIENT_PORT, + VD_AGENT_ANNOUNCE_CAPABILITIES, 0, +@@ -151,6 +152,19 @@ static void do_client_monitors(struct vdagent_virtio_port *vport, int port_nr, + (uint8_t *)&reply, sizeof(reply)); + } + ++static void do_client_volume_sync(struct vdagent_virtio_port *vport, int port_nr, ++ VDAgentMessage *message_header, ++ VDAgentAudioVolumeSync *avs) ++{ ++ if (active_session_conn == NULL) { ++ syslog(LOG_DEBUG, "No active session - Can't volume-sync"); ++ return; ++ } ++ ++ udscs_write(active_session_conn, VDAGENTD_AUDIO_VOLUME_SYNC, 0, 0, ++ (uint8_t *)avs, message_header->size); ++} ++ + static void do_client_capabilities(struct vdagent_virtio_port *vport, + VDAgentMessage *message_header, + VDAgentAnnounceCapabilities *caps) +@@ -366,6 +380,13 @@ int virtio_port_read_complete( + vdagent_virtio_port_reset(vport, VDP_CLIENT_PORT); + do_client_disconnect(); + break; ++ case VD_AGENT_AUDIO_VOLUME_SYNC: ++ if (message_header->size < sizeof(VDAgentAudioVolumeSync)) ++ goto size_error; ++ ++ do_client_volume_sync(vport, port_nr, message_header, ++ (VDAgentAudioVolumeSync *)data); ++ break; + default: + syslog(LOG_WARNING, "unknown message type %d, ignoring", + message_header->type); diff --git a/SOURCES/0017-vdagentd-proto-strings-Add-missing-string-for-VDAGEN.patch b/SOURCES/0017-vdagentd-proto-strings-Add-missing-string-for-VDAGEN.patch new file mode 100644 index 0000000..c00c6e3 --- /dev/null +++ b/SOURCES/0017-vdagentd-proto-strings-Add-missing-string-for-VDAGEN.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Pavel Grunt +Date: Tue, 28 Apr 2015 11:09:28 +0200 +Subject: [PATCH] vdagentd-proto-strings: Add missing string for + VDAGENTD_AUDIO_VOLUME_SYNC + +Avoids a crash when running spice-vdagent with debug + +Backtrace: + + #0 0x0000003dcf647e2c in _IO_vfprintf_internal (s=, format=, ap=) at vfprintf.c:1641 + #1 0x0000003dcf6e4e90 in __vsyslog_chk (pri=, flag=-1, fmt=0x40f360 "%p received %s, arg1: %u, arg2: %u, size %u", ap=0x7fffffffddc0) at ../misc/syslog.c:222 + #2 0x0000003dcf6e50c0 in __syslog (pri=, fmt=) at ../misc/syslog.c:119 + #3 0x000000000040c6da in udscs_read_complete (connp=0x610de8) at src/udscs.c:448 + #4 0x000000000040c8d1 in udscs_do_read (connp=0x610de8) at src/udscs.c:500 + #5 0x000000000040c303 in udscs_client_handle_fds (connp=0x610de8, readfds=0x7fffffffe0a0, writefds=0x7fffffffe020) at src/udscs.c:349 + #6 0x0000000000403d74 in main (argc=3, argv=0x7fffffffe248) at src/vdagent.c:365 +--- + src/vdagentd-proto-strings.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/vdagentd-proto-strings.h b/src/vdagentd-proto-strings.h +index e76cb3b..a3fbd32 100644 +--- a/src/vdagentd-proto-strings.h ++++ b/src/vdagentd-proto-strings.h +@@ -30,6 +30,7 @@ static const char * const vdagentd_messages[] = { + "clipboard data", + "clipboard release", + "version", ++ "audio volume sync", + "file xfer start", + "file xfer status", + "file xfer data", diff --git a/SOURCES/0018-vdagent-Return-1-when-virtio-device-cannot-be-opened.patch b/SOURCES/0018-vdagent-Return-1-when-virtio-device-cannot-be-opened.patch new file mode 100644 index 0000000..b8efe4b --- /dev/null +++ b/SOURCES/0018-vdagent-Return-1-when-virtio-device-cannot-be-opened.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Mon, 7 Sep 2015 16:38:10 +0200 +Subject: [PATCH] vdagent: Return '1' when virtio device cannot be opened + +The vdagent process currently exits with an error code set to 0 whenn +the virtio device cannot be opened (for example because it's missing). +This is not consistent with the other failures to startup which set the +exit code to 1. This commit ensures 1 is returned in this situation too. + +Resolves: rhbz#1256704 +--- + src/vdagent.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/vdagent.c b/src/vdagent.c +index a26af73..1336faa 100644 +--- a/src/vdagent.c ++++ b/src/vdagent.c +@@ -238,7 +238,8 @@ int main(int argc, char *argv[]) + LOG_USER); + + if (file_test(portdev) != 0) { +- return 0; ++ syslog(LOG_ERR, "Cannot access vdagent virtio channel %s", portdev); ++ return 1; + } + + if (do_daemonize) diff --git a/SOURCES/0019-build-sys-Enable-large-file-support.patch b/SOURCES/0019-build-sys-Enable-large-file-support.patch new file mode 100644 index 0000000..f43db79 --- /dev/null +++ b/SOURCES/0019-build-sys-Enable-large-file-support.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Thu, 9 Apr 2015 17:24:40 +0200 +Subject: [PATCH] build-sys: Enable large file support + +This is needed on 32 bit machines for drag and drop of large files (>2GB +to work). This fixes https://bugzilla.redhat.com/show_bug.cgi?id=1206663 +--- + configure.ac | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/configure.ac b/configure.ac +index 377fc74..9f9d34c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -10,6 +10,7 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) + AC_PROG_CC + AM_PROG_CC_C_O + AC_HEADER_STDC ++AC_SYS_LARGEFILE + AC_PROG_INSTALL + AC_PROG_LN_S + AC_DEFINE(_GNU_SOURCE, [1], [Enable GNU extensions]) diff --git a/SOURCES/0020-Add-g_return_if_fail-guards-to-file-xfer-public-func.patch b/SOURCES/0020-Add-g_return_if_fail-guards-to-file-xfer-public-func.patch new file mode 100644 index 0000000..eeb5de9 --- /dev/null +++ b/SOURCES/0020-Add-g_return_if_fail-guards-to-file-xfer-public-func.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Thu, 27 Feb 2014 18:45:15 +0100 +Subject: [PATCH] Add g_return_if_fail() guards to file xfer public functions + +With the next commit, we won't always have a file xfer object available. +This next commit will make sure NULL is never passed to the public file +xfer functions, but it's safer to guard against that anyway in case +this gets broken in the future. + +(cherry picked from commit ec9f11064efee2ad3f0be0d36f5fdbbbe2d51ad9) +--- + src/vdagent-file-xfers.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/vdagent-file-xfers.c b/src/vdagent-file-xfers.c +index 4dea6de..d59910b 100644 +--- a/src/vdagent-file-xfers.c ++++ b/src/vdagent-file-xfers.c +@@ -97,6 +97,8 @@ struct vdagent_file_xfers *vdagent_file_xfers_create( + + void vdagent_file_xfers_destroy(struct vdagent_file_xfers *xfers) + { ++ g_return_if_fail(xfers != NULL); ++ + g_hash_table_destroy(xfers->xfers); + g_free(xfers->save_dir); + g_free(xfers); +@@ -107,6 +109,8 @@ AgentFileXferTask *vdagent_file_xfers_get_task( + { + AgentFileXferTask *task; + ++ g_return_val_if_fail(xfers != NULL, NULL); ++ + task = g_hash_table_lookup(xfers->xfers, GUINT_TO_POINTER(id)); + if (task == NULL) + syslog(LOG_ERR, "file-xfer: error can not find task %u", id); +@@ -173,6 +177,8 @@ void vdagent_file_xfers_start(struct vdagent_file_xfers *xfers, + struct stat st; + int i; + ++ g_return_if_fail(xfers != NULL); ++ + if (g_hash_table_lookup(xfers->xfers, GUINT_TO_POINTER(msg->id))) { + syslog(LOG_ERR, "file-xfer: error id %u already exists, ignoring!", + msg->id); +@@ -246,6 +252,8 @@ void vdagent_file_xfers_status(struct vdagent_file_xfers *xfers, + { + AgentFileXferTask *task; + ++ g_return_if_fail(xfers != NULL); ++ + task = vdagent_file_xfers_get_task(xfers, msg->id); + if (!task) + return; +@@ -267,6 +275,8 @@ void vdagent_file_xfers_data(struct vdagent_file_xfers *xfers, + AgentFileXferTask *task; + int len, status = -1; + ++ g_return_if_fail(xfers != NULL); ++ + task = vdagent_file_xfers_get_task(xfers, msg->id); + if (!task) + return; diff --git a/SOURCES/0021-Make-creation-of-vdagent_file_xfers-optional.patch b/SOURCES/0021-Make-creation-of-vdagent_file_xfers-optional.patch new file mode 100644 index 0000000..fcb5cc8 --- /dev/null +++ b/SOURCES/0021-Make-creation-of-vdagent_file_xfers-optional.patch @@ -0,0 +1,76 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Thu, 27 Feb 2014 18:45:24 +0100 +Subject: [PATCH] Make creation of 'vdagent_file_xfers' optional + +This commit only adds if (vdagent_file_xfers != NULL) {} checks before +calling into the file transfer code. This allows to disable file transfer +handling by setting this variable to NULL. + +(cherry picked from commit 7fc4525dcedb280d22feabcd577ec84e5781960f) +--- + src/vdagent.c | 30 ++++++++++++++++++++---------- + 1 file changed, 20 insertions(+), 10 deletions(-) + +diff --git a/src/vdagent.c b/src/vdagent.c +index 1336faa..9586432 100644 +--- a/src/vdagent.c ++++ b/src/vdagent.c +@@ -89,13 +89,17 @@ void daemon_read_complete(struct udscs_connection **connp, + } + break; + case VDAGENTD_FILE_XFER_START: +- vdagent_file_xfers_start(vdagent_file_xfers, +- (VDAgentFileXferStartMessage *)data); ++ if (vdagent_file_xfers != NULL) { ++ vdagent_file_xfers_start(vdagent_file_xfers, ++ (VDAgentFileXferStartMessage *)data); ++ } + free(data); + break; + case VDAGENTD_FILE_XFER_STATUS: +- vdagent_file_xfers_status(vdagent_file_xfers, +- (VDAgentFileXferStatusMessage *)data); ++ if (vdagent_file_xfers != NULL) { ++ vdagent_file_xfers_status(vdagent_file_xfers, ++ (VDAgentFileXferStatusMessage *)data); ++ } + free(data); + break; + case VDAGENTD_AUDIO_VOLUME_SYNC: { +@@ -109,15 +113,19 @@ void daemon_read_complete(struct udscs_connection **connp, + break; + } + case VDAGENTD_FILE_XFER_DATA: +- vdagent_file_xfers_data(vdagent_file_xfers, +- (VDAgentFileXferDataMessage *)data); ++ if (vdagent_file_xfers != NULL) { ++ vdagent_file_xfers_data(vdagent_file_xfers, ++ (VDAgentFileXferDataMessage *)data); ++ } + free(data); + break; + case VDAGENTD_CLIENT_DISCONNECTED: + vdagent_x11_client_disconnected(x11); +- vdagent_file_xfers_destroy(vdagent_file_xfers); +- vdagent_file_xfers = vdagent_file_xfers_create(client, fx_dir, +- fx_open_dir, debug); ++ if (vdagent_file_xfers != NULL) { ++ vdagent_file_xfers_destroy(vdagent_file_xfers); ++ vdagent_file_xfers = vdagent_file_xfers_create(client, fx_dir, ++ fx_open_dir, debug); ++ } + break; + default: + syslog(LOG_ERR, "Unknown message from vdagentd type: %d, ignoring", +@@ -305,7 +313,9 @@ reconnect: + udscs_client_handle_fds(&client, &readfds, &writefds); + } + +- vdagent_file_xfers_destroy(vdagent_file_xfers); ++ if (vdagent_file_xfers != NULL) { ++ vdagent_file_xfers_destroy(vdagent_file_xfers); ++ } + vdagent_x11_destroy(x11, client == NULL); + udscs_destroy_connection(&client); + if (!quit && do_daemonize) diff --git a/SOURCES/0022-Disable-file-xfer-when-no-suitable-destination-dir.patch b/SOURCES/0022-Disable-file-xfer-when-no-suitable-destination-dir.patch new file mode 100644 index 0000000..be5164e --- /dev/null +++ b/SOURCES/0022-Disable-file-xfer-when-no-suitable-destination-dir.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Thu, 27 Mar 2014 18:04:59 +0100 +Subject: [PATCH] Disable file xfer when no suitable destination dir + +Currently, if no suitable destination directory can be found, the file +transfer code defaults to using '.' as the destination directory. As this +is unlikely to work, better to just disable file transfers when we end up +in such a situation. This currently happens when spawning spice-vdagent +from gdm where we don't want file transfers to be available anyway. + +(cherry picked from commit 689dcd35edb55abcdef4d30d92fdcca22d81ee23) +--- + src/vdagent.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/src/vdagent.c b/src/vdagent.c +index 9586432..32c84e5 100644 +--- a/src/vdagent.c ++++ b/src/vdagent.c +@@ -282,13 +282,14 @@ reconnect: + fx_dir = g_get_user_special_dir(G_USER_DIRECTORY_DESKTOP); + else if (!strcmp(fx_dir, "xdg-download")) + fx_dir = g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD); +- if (!fx_dir) { ++ if (fx_dir) { ++ vdagent_file_xfers = vdagent_file_xfers_create(client, fx_dir, ++ fx_open_dir, debug); ++ } else { + syslog(LOG_WARNING, +- "warning could not get file xfer save dir, using cwd"); +- fx_dir = "."; ++ "warning could not get file xfer save dir, file transfers will be disabled"); ++ vdagent_file_xfers = NULL; + } +- vdagent_file_xfers = vdagent_file_xfers_create(client, fx_dir, +- fx_open_dir, debug); + + while (client && !quit) { + FD_ZERO(&readfds); diff --git a/SOURCES/0023-Report-an-error-when-file-transfers-are-disabled.patch b/SOURCES/0023-Report-an-error-when-file-transfers-are-disabled.patch new file mode 100644 index 0000000..6ba40a9 --- /dev/null +++ b/SOURCES/0023-Report-an-error-when-file-transfers-are-disabled.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Tue, 8 Apr 2014 16:11:38 +0200 +Subject: [PATCH] Report an error when file transfers are disabled + +This commit sends back a VD_AGENT_FILE_XFER_STATUS_ERROR to clients which +try to transfer files when the agent disabled file transfers (for example +because there is no valid destination directory for the transferred files). + +(cherry picked from commit 9ea18740b8cf4466ebd2f6bca42d1d70dd0ba01c) +--- + src/vdagent-file-xfers.c | 8 ++++++++ + src/vdagent-file-xfers.h | 2 ++ + src/vdagent.c | 9 +++++++++ + 3 files changed, 19 insertions(+) + +diff --git a/src/vdagent-file-xfers.c b/src/vdagent-file-xfers.c +index d59910b..0dc549b 100644 +--- a/src/vdagent-file-xfers.c ++++ b/src/vdagent-file-xfers.c +@@ -316,3 +316,11 @@ void vdagent_file_xfers_data(struct vdagent_file_xfers *xfers, + g_hash_table_remove(xfers->xfers, GUINT_TO_POINTER(msg->id)); + } + } ++ ++void vdagent_file_xfers_error(struct udscs_connection *vdagentd, uint32_t msg_id) ++{ ++ g_return_if_fail(vdagentd != NULL); ++ ++ udscs_write(vdagentd, VDAGENTD_FILE_XFER_STATUS, ++ msg_id, VD_AGENT_FILE_XFER_STATUS_ERROR, NULL, 0); ++} +diff --git a/src/vdagent-file-xfers.h b/src/vdagent-file-xfers.h +index 20783eb..fe5da81 100644 +--- a/src/vdagent-file-xfers.h ++++ b/src/vdagent-file-xfers.h +@@ -37,5 +37,7 @@ void vdagent_file_xfers_status(struct vdagent_file_xfers *xfers, + VDAgentFileXferStatusMessage *msg); + void vdagent_file_xfers_data(struct vdagent_file_xfers *xfers, + VDAgentFileXferDataMessage *msg); ++void vdagent_file_xfers_error(struct udscs_connection *vdagentd, ++ uint32_t msg_id); + + #endif +diff --git a/src/vdagent.c b/src/vdagent.c +index 32c84e5..a0ba79e 100644 +--- a/src/vdagent.c ++++ b/src/vdagent.c +@@ -92,6 +92,9 @@ void daemon_read_complete(struct udscs_connection **connp, + if (vdagent_file_xfers != NULL) { + vdagent_file_xfers_start(vdagent_file_xfers, + (VDAgentFileXferStartMessage *)data); ++ } else { ++ vdagent_file_xfers_error(*connp, ++ ((VDAgentFileXferStartMessage *)data)->id); + } + free(data); + break; +@@ -99,6 +102,9 @@ void daemon_read_complete(struct udscs_connection **connp, + if (vdagent_file_xfers != NULL) { + vdagent_file_xfers_status(vdagent_file_xfers, + (VDAgentFileXferStatusMessage *)data); ++ } else { ++ vdagent_file_xfers_error(*connp, ++ ((VDAgentFileXferStatusMessage *)data)->id); + } + free(data); + break; +@@ -116,6 +122,9 @@ void daemon_read_complete(struct udscs_connection **connp, + if (vdagent_file_xfers != NULL) { + vdagent_file_xfers_data(vdagent_file_xfers, + (VDAgentFileXferDataMessage *)data); ++ } else { ++ vdagent_file_xfers_error(*connp, ++ ((VDAgentFileXferDataMessage *)data)->id); + } + free(data); + break; diff --git a/SOURCES/0024-vdagentd-send-file-xfer-status-generic-version.patch b/SOURCES/0024-vdagentd-send-file-xfer-status-generic-version.patch new file mode 100644 index 0000000..ed41763 --- /dev/null +++ b/SOURCES/0024-vdagentd-send-file-xfer-status-generic-version.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Tue, 3 May 2016 10:25:52 +0200 +Subject: [PATCH] vdagentd: send file-xfer status, generic version + +Change cancel_file_xfer() helper function to file_xfer_status() so we +can send other status to the client. + +Acked-by: Jonathon Jongsma +(cherry picked from commit b5f0352e9e5ea91eff0880674cbc5080e78c9e5b) +--- + src/vdagentd.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/src/vdagentd.c b/src/vdagentd.c +index 594f36b..2c8e973 100644 +--- a/src/vdagentd.c ++++ b/src/vdagentd.c +@@ -244,12 +244,14 @@ static void do_client_clipboard(struct vdagent_virtio_port *vport, + data, size); + } + +-static void cancel_file_xfer(struct vdagent_virtio_port *vport, +- const char *msg, uint32_t id) ++/* To be used by vdagentd for failures in file-xfer such as when file-xfer was ++ * cancelled or an error happened */ ++static void send_file_xfer_status(struct vdagent_virtio_port *vport, ++ const char *msg, uint32_t id, uint32_t xfer_status) + { + VDAgentFileXferStatusMessage status = { + .id = id, +- .result = VD_AGENT_FILE_XFER_STATUS_CANCELLED, ++ .result = xfer_status, + }; + syslog(LOG_WARNING, msg, id); + if (vport) +@@ -269,10 +271,10 @@ static void do_client_file_xfer(struct vdagent_virtio_port *vport, + case VD_AGENT_FILE_XFER_START: { + VDAgentFileXferStartMessage *s = (VDAgentFileXferStartMessage *)data; + if (!active_session_conn) { +- cancel_file_xfer(vport, ++ send_file_xfer_status(vport, + "Could not find an agent connnection belonging to the " + "active session, cancelling client file-xfer request %u", +- s->id); ++ s->id, VD_AGENT_FILE_XFER_STATUS_CANCELLED); + return; + } + udscs_write(active_session_conn, VDAGENTD_FILE_XFER_START, 0, 0, +@@ -617,8 +619,10 @@ void update_active_session_connection(struct udscs_connection *new_conn) + gboolean remove_active_xfers(gpointer key, gpointer value, gpointer conn) + { + if (value == conn) { +- cancel_file_xfer(virtio_port, "Agent disc; cancelling file-xfer %u", +- GPOINTER_TO_UINT(key)); ++ send_file_xfer_status(virtio_port, ++ "Agent disc; cancelling file-xfer %u", ++ GPOINTER_TO_UINT(key), ++ VD_AGENT_FILE_XFER_STATUS_CANCELLED); + return 1; + } else + return 0; diff --git a/SOURCES/0025-session-info-check-for-a-locked-session.patch b/SOURCES/0025-session-info-check-for-a-locked-session.patch new file mode 100644 index 0000000..c40d19a --- /dev/null +++ b/SOURCES/0025-session-info-check-for-a-locked-session.patch @@ -0,0 +1,308 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Sat, 9 Apr 2016 12:00:08 +0200 +Subject: [PATCH] session-info: check for a locked session + +Each session back-end can return this information to vdagentd when +requested. + +The agent should use this on situations that should not work when +session is locked such as file-transfer-start which is fixed by this +patch. + +systemd-login is the only back-end implementing this function at the +moment and I'll address console-kit back-end in a later patch. + +Also, this patch makes spice-vdagent depend on dbus for getting the +lock information. + +Resolve: https://bugzilla.redhat.com/show_bug.cgi?id=1323623 + +Acked-by: Jonathon Jongsma +(cherry picked from commit 364b6bba068bd694d7c4355b6275f88482d9f3f8) +--- + configure.ac | 17 ++----- + src/console-kit.c | 7 +++ + src/dummy-session-info.c | 5 ++ + src/session-info.h | 3 ++ + src/systemd-login.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++ + src/vdagentd.c | 7 +++ + 6 files changed, 153 insertions(+), 13 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 9f9d34c..9903ea9 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -81,6 +81,7 @@ PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= 2.12]) + PKG_CHECK_MODULES(X, [xfixes xrandr >= 1.3 xinerama x11]) + PKG_CHECK_MODULES(SPICE, [spice-protocol >= 0.12.5]) + PKG_CHECK_MODULES(ALSA, [alsa >= 1.0.22]) ++PKG_CHECK_MODULES([DBUS], [dbus-1]) + + if test "$with_session_info" = "auto" || test "$with_session_info" = "systemd"; then + PKG_CHECK_MODULES([LIBSYSTEMD_LOGIN], +@@ -100,19 +101,9 @@ fi + AM_CONDITIONAL(HAVE_LIBSYSTEMD_LOGIN, test x"$have_libsystemd_login" = "xyes") + + if test "$with_session_info" = "auto" || test "$with_session_info" = "console-kit"; then +- PKG_CHECK_MODULES([DBUS], +- [dbus-1], +- [have_console_kit="yes"], +- [have_console_kit="no"]) +- if test x"$have_console_kit" = "xno" && test "$with_session_info" = "console-kit"; then +- AC_MSG_ERROR([console-kit support explicitly requested, but some required packages are not available]) +- fi +- if test x"$have_console_kit" = "xyes"; then +- AC_DEFINE([HAVE_CONSOLE_KIT], [1], [If defined, vdagentd will be compiled with ConsoleKit support]) +- with_session_info="console-kit" +- else +- with_session_info="none" +- fi ++ AC_DEFINE([HAVE_CONSOLE_KIT], [1], [If defined, vdagentd will be compiled with ConsoleKit support]) ++ have_console_kit="yes" ++ with_session_info="console-kit" + else + have_console_kit="no" + fi +diff --git a/src/console-kit.c b/src/console-kit.c +index 759a81e..260fcc7 100644 +--- a/src/console-kit.c ++++ b/src/console-kit.c +@@ -352,3 +352,10 @@ static char *console_kit_check_active_session_change(struct session_info *ck) + + return ck->active_session; + } ++ ++gboolean session_info_session_is_locked(struct session_info *info) ++{ ++ /* TODO: It could be implemented based on Lock/Unlock signals from Session ++ * interface. */ ++ return FALSE; ++} +diff --git a/src/dummy-session-info.c b/src/dummy-session-info.c +index e188ddc..c09643b 100644 +--- a/src/dummy-session-info.c ++++ b/src/dummy-session-info.c +@@ -44,3 +44,8 @@ char *session_info_session_for_pid(struct session_info *si, uint32_t pid) + { + return NULL; + } ++ ++gboolean session_is_locked(struct session_info *ck) ++{ ++ return FALSE; ++} +diff --git a/src/session-info.h b/src/session-info.h +index 67099de..d660fcf 100644 +--- a/src/session-info.h ++++ b/src/session-info.h +@@ -24,6 +24,7 @@ + + #include + #include ++#include + + struct session_info; + +@@ -36,4 +37,6 @@ const char *session_info_get_active_session(struct session_info *ck); + /* Note result must be free()-ed by caller */ + char *session_info_session_for_pid(struct session_info *ck, uint32_t pid); + ++gboolean session_info_session_is_locked(struct session_info *si); ++ + #endif +diff --git a/src/systemd-login.c b/src/systemd-login.c +index 73db37f..4a365c0 100644 +--- a/src/systemd-login.c ++++ b/src/systemd-login.c +@@ -25,13 +25,121 @@ + #include + #include + #include ++#include + + struct session_info { + int verbose; + sd_login_monitor *mon; + char *session; ++ struct { ++ DBusConnection *system_connection; ++ char *match_session_signals; ++ } dbus; ++ gboolean session_is_locked; + }; + ++#define LOGIND_SESSION_INTERFACE "org.freedesktop.login1.Session" ++#define LOGIND_SESSION_OBJ_TEMPLATE "'/org/freedesktop/login1/session/_3%s'" ++ ++#define SESSION_SIGNAL_LOCK "Lock" ++#define SESSION_SIGNAL_UNLOCK "Unlock" ++ ++/* dbus related */ ++static DBusConnection *si_dbus_get_system_bus(void) ++{ ++ DBusConnection *connection; ++ DBusError error; ++ ++ dbus_error_init(&error); ++ connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); ++ if (connection == NULL || dbus_error_is_set(&error)) { ++ if (dbus_error_is_set(&error)) { ++ syslog(LOG_WARNING, "Unable to connect to system bus: %s", ++ error.message); ++ dbus_error_free(&error); ++ } else { ++ syslog(LOG_WARNING, "Unable to connect to system bus"); ++ } ++ return NULL; ++ } ++ return connection; ++} ++ ++static void si_dbus_match_remove(struct session_info *si) ++{ ++ DBusError error; ++ if (si->dbus.match_session_signals == NULL) ++ return; ++ ++ dbus_error_init(&error); ++ dbus_bus_remove_match(si->dbus.system_connection, ++ si->dbus.match_session_signals, ++ &error); ++ ++ g_free(si->dbus.match_session_signals); ++ si->dbus.match_session_signals = NULL; ++} ++ ++static void si_dbus_match_rule_update(struct session_info *si) ++{ ++ DBusError error; ++ ++ if (si->dbus.system_connection == NULL || ++ si->session == NULL) ++ return; ++ ++ si_dbus_match_remove(si); ++ ++ si->dbus.match_session_signals = ++ g_strdup_printf ("type='signal',interface='%s',path=" ++ LOGIND_SESSION_OBJ_TEMPLATE, ++ LOGIND_SESSION_INTERFACE, ++ si->session); ++ if (si->verbose) ++ syslog(LOG_DEBUG, "logind match: %s", si->dbus.match_session_signals); ++ ++ dbus_error_init(&error); ++ dbus_bus_add_match(si->dbus.system_connection, ++ si->dbus.match_session_signals, ++ &error); ++ if (dbus_error_is_set(&error)) { ++ syslog(LOG_WARNING, "Unable to add dbus rule match: %s", ++ error.message); ++ dbus_error_free(&error); ++ g_free(si->dbus.match_session_signals); ++ si->dbus.match_session_signals = NULL; ++ } ++} ++ ++static void ++si_dbus_read_signals(struct session_info *si) ++{ ++ DBusMessage *message = NULL; ++ ++ dbus_connection_read_write(si->dbus.system_connection, 0); ++ message = dbus_connection_pop_message(si->dbus.system_connection); ++ while (message != NULL) { ++ const char *member; ++ ++ member = dbus_message_get_member (message); ++ if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) { ++ si->session_is_locked = TRUE; ++ } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) { ++ si->session_is_locked = FALSE; ++ } else { ++ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) { ++ syslog(LOG_WARNING, "(systemd-login) received non signal message"); ++ } else if (si->verbose) { ++ syslog(LOG_DEBUG, "(systemd-login) Signal not handled: %s", member); ++ } ++ } ++ ++ dbus_message_unref(message); ++ dbus_connection_read_write(si->dbus.system_connection, 0); ++ message = dbus_connection_pop_message(si->dbus.system_connection); ++ } ++} ++ + struct session_info *session_info_create(int verbose) + { + struct session_info *si; +@@ -42,6 +150,7 @@ struct session_info *session_info_create(int verbose) + return NULL; + + si->verbose = verbose; ++ si->session_is_locked = FALSE; + + r = sd_login_monitor_new("session", &si->mon); + if (r < 0) { +@@ -50,6 +159,7 @@ struct session_info *session_info_create(int verbose) + return NULL; + } + ++ si->dbus.system_connection = si_dbus_get_system_bus(); + return si; + } + +@@ -58,6 +168,8 @@ void session_info_destroy(struct session_info *si) + if (!si) + return; + ++ si_dbus_match_remove(si); ++ dbus_connection_close(si->dbus.system_connection); + sd_login_monitor_unref(si->mon); + free(si->session); + free(si); +@@ -87,6 +199,7 @@ const char *session_info_get_active_session(struct session_info *si) + sd_login_monitor_flush(si->mon); + free(old_session); + ++ si_dbus_match_rule_update(si); + return si->session; + } + +@@ -104,3 +217,17 @@ char *session_info_session_for_pid(struct session_info *si, uint32_t pid) + + return session; + } ++ ++gboolean session_info_session_is_locked(struct session_info *si) ++{ ++ g_return_val_if_fail (si != NULL, FALSE); ++ ++ /* We could also rely on IdleHint property from Session which seems to work ++ * well in rhel7 but it wasn't working well in my own system (F23). I'm ++ * convinced for now that Lock/Unlock signals should be enough but that ++ * means Lock/Unlock being done by logind. That might take a while. ++ * Check: https://bugzilla.gnome.org/show_bug.cgi?id=764773 */ ++ ++ si_dbus_read_signals(si); ++ return si->session_is_locked; ++} +diff --git a/src/vdagentd.c b/src/vdagentd.c +index 2c8e973..2f77773 100644 +--- a/src/vdagentd.c ++++ b/src/vdagentd.c +@@ -276,6 +276,13 @@ static void do_client_file_xfer(struct vdagent_virtio_port *vport, + "active session, cancelling client file-xfer request %u", + s->id, VD_AGENT_FILE_XFER_STATUS_CANCELLED); + return; ++ } else if (session_info_session_is_locked(session_info)) { ++ syslog(LOG_DEBUG, "Session is locked, skipping file-xfer-start"); ++ send_file_xfer_status(vport, ++ "User's session is locked and cannot start file transfer. " ++ "Cancelling client file-xfer request %u", ++ s->id, VD_AGENT_FILE_XFER_STATUS_ERROR); ++ return; + } + udscs_write(active_session_conn, VDAGENTD_FILE_XFER_START, 0, 0, + data, message_header->size); diff --git a/SOURCES/0026-session-info-check-if-session-belongs-to-user.patch b/SOURCES/0026-session-info-check-if-session-belongs-to-user.patch new file mode 100644 index 0000000..b204aa1 --- /dev/null +++ b/SOURCES/0026-session-info-check-if-session-belongs-to-user.patch @@ -0,0 +1,169 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Thu, 21 Apr 2016 10:32:50 +0200 +Subject: [PATCH] session-info: check if session belongs to user + +session-info back-ends such as console-kit and systemd-login have the +concept of session's class which informs if session belongs to user or +not [0]. We can disable features based on the session class. + +[0] Display-Managers are 'Greeter' and Display lock screens are +'lock-screen' + +This patch introduces session_info_is_user() and disable file-xfer in +case agent's session does not belong to the 'user' class. As the +session-info data is hold by vdagentd, this patch also introduces +VDAGENTD_FILE_XFER_DISABLE message to disable file-xfer that is done +in vdagent. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1328761 + +Acked-by: Jonathon Jongsma +(cherry picked from commit 4c0e9c965e059ba2b884e66f0402e061a9d886a6) +--- + src/console-kit.c | 6 ++++++ + src/dummy-session-info.c | 5 +++++ + src/session-info.h | 1 + + src/systemd-login.c | 26 ++++++++++++++++++++++++++ + src/vdagent.c | 9 +++++++++ + src/vdagentd-proto-strings.h | 1 + + src/vdagentd-proto.h | 1 + + src/vdagentd.c | 9 +++++++++ + 8 files changed, 58 insertions(+) + +diff --git a/src/console-kit.c b/src/console-kit.c +index 260fcc7..573ee49 100644 +--- a/src/console-kit.c ++++ b/src/console-kit.c +@@ -359,3 +359,9 @@ gboolean session_info_session_is_locked(struct session_info *info) + * interface. */ + return FALSE; + } ++ ++gboolean session_info_is_user(struct session_info *info) ++{ ++ /* TODO */ ++ return TRUE; ++} +diff --git a/src/dummy-session-info.c b/src/dummy-session-info.c +index c09643b..0aa154e 100644 +--- a/src/dummy-session-info.c ++++ b/src/dummy-session-info.c +@@ -49,3 +49,8 @@ gboolean session_is_locked(struct session_info *ck) + { + return FALSE; + } ++ ++gboolean session_info_is_user(struct session_info *si) ++{ ++ return TRUE; ++} +diff --git a/src/session-info.h b/src/session-info.h +index d660fcf..823749b 100644 +--- a/src/session-info.h ++++ b/src/session-info.h +@@ -38,5 +38,6 @@ const char *session_info_get_active_session(struct session_info *ck); + char *session_info_session_for_pid(struct session_info *ck, uint32_t pid); + + gboolean session_info_session_is_locked(struct session_info *si); ++gboolean session_info_is_user(struct session_info *si); + + #endif +diff --git a/src/systemd-login.c b/src/systemd-login.c +index 4a365c0..ff9a3be 100644 +--- a/src/systemd-login.c ++++ b/src/systemd-login.c +@@ -231,3 +231,29 @@ gboolean session_info_session_is_locked(struct session_info *si) + si_dbus_read_signals(si); + return si->session_is_locked; + } ++ ++/* This function should only be called after session_info_get_active_session ++ * in order to verify if active session belongs to user (non greeter) */ ++gboolean session_info_is_user(struct session_info *si) ++{ ++ gchar *class = NULL; ++ gboolean ret; ++ ++ g_return_val_if_fail (si != NULL, TRUE); ++ g_return_val_if_fail (si->session != NULL, TRUE); ++ ++ if (sd_session_get_class(si->session, &class) != 0) { ++ syslog(LOG_WARNING, "Unable to get class from session: %s", ++ si->session); ++ return TRUE; ++ } ++ ++ if (si->verbose) ++ syslog(LOG_DEBUG, "(systemd-login) class for %s is %s", ++ si->session, class); ++ ++ ret = (g_strcmp0(class, "user") == 0); ++ g_free(class); ++ ++ return ret; ++} +diff --git a/src/vdagent.c b/src/vdagent.c +index a0ba79e..f952ba1 100644 +--- a/src/vdagent.c ++++ b/src/vdagent.c +@@ -108,6 +108,15 @@ void daemon_read_complete(struct udscs_connection **connp, + } + free(data); + break; ++ case VDAGENTD_FILE_XFER_DISABLE: ++ if (debug) ++ syslog(LOG_DEBUG, "Disabling file-xfers"); ++ ++ if (vdagent_file_xfers != NULL) { ++ vdagent_file_xfers_destroy(vdagent_file_xfers); ++ vdagent_file_xfers = NULL; ++ } ++ break; + case VDAGENTD_AUDIO_VOLUME_SYNC: { + VDAgentAudioVolumeSync *avs = (VDAgentAudioVolumeSync *)data; + if (avs->is_playback) { +diff --git a/src/vdagentd-proto-strings.h b/src/vdagentd-proto-strings.h +index a3fbd32..a56f380 100644 +--- a/src/vdagentd-proto-strings.h ++++ b/src/vdagentd-proto-strings.h +@@ -34,6 +34,7 @@ static const char * const vdagentd_messages[] = { + "file xfer start", + "file xfer status", + "file xfer data", ++ "file xfer disable", + "client disconnected", + }; + +diff --git a/src/vdagentd-proto.h b/src/vdagentd-proto.h +index 0dbaaea..c1c39ad 100644 +--- a/src/vdagentd-proto.h ++++ b/src/vdagentd-proto.h +@@ -40,6 +40,7 @@ enum { + VDAGENTD_FILE_XFER_START, + VDAGENTD_FILE_XFER_STATUS, + VDAGENTD_FILE_XFER_DATA, ++ VDAGENTD_FILE_XFER_DISABLE, + VDAGENTD_CLIENT_DISCONNECTED, /* daemon -> client */ + VDAGENTD_NO_MESSAGES /* Must always be last */ + }; +diff --git a/src/vdagentd.c b/src/vdagentd.c +index 2f77773..59ea8da 100644 +--- a/src/vdagentd.c ++++ b/src/vdagentd.c +@@ -613,6 +613,15 @@ void update_active_session_connection(struct udscs_connection *new_conn) + active_session_conn = new_conn; + if (debug) + syslog(LOG_DEBUG, "%p is now the active session", new_conn); ++ ++ if (active_session_conn && !session_info_is_user(session_info)) { ++ if (debug) ++ syslog(LOG_DEBUG, "New session agent does not belong to user: " ++ "disabling file-xfer"); ++ udscs_write(active_session_conn, VDAGENTD_FILE_XFER_DISABLE, 0, 0, ++ NULL, 0); ++ } ++ + if (active_session_conn && mon_config) + udscs_write(active_session_conn, VDAGENTD_MONITORS_CONFIG, 0, 0, + (uint8_t *)mon_config, sizeof(VDAgentMonitorsConfig) + diff --git a/SOURCES/0027-systemd-login-check-for-LockedHint-property.patch b/SOURCES/0027-systemd-login-check-for-LockedHint-property.patch new file mode 100644 index 0000000..364c209 --- /dev/null +++ b/SOURCES/0027-systemd-login-check-for-LockedHint-property.patch @@ -0,0 +1,169 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Toso +Date: Fri, 27 May 2016 11:42:29 +0200 +Subject: [PATCH] systemd-login: check for LockedHint property + +Property introduced in v230 of systemd. + +Systems that don't have up to date systemd-login will get the +following log message: + +"Properties.Get failed (locked-hint) due Unknown property or interface." + +Resolves: rhbz#1323623 +Acked-by: Pavel Grunt +(cherry picked from commit ec843a21b29d7fa21ba3393b84368bc2e39d3ce7) +--- + src/systemd-login.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 98 insertions(+), 10 deletions(-) + +diff --git a/src/systemd-login.c b/src/systemd-login.c +index ff9a3be..1b0b6f1 100644 +--- a/src/systemd-login.c ++++ b/src/systemd-login.c +@@ -36,14 +36,21 @@ struct session_info { + char *match_session_signals; + } dbus; + gboolean session_is_locked; ++ gboolean session_locked_hint; + }; + ++#define LOGIND_INTERFACE "org.freedesktop.login1" ++ + #define LOGIND_SESSION_INTERFACE "org.freedesktop.login1.Session" +-#define LOGIND_SESSION_OBJ_TEMPLATE "'/org/freedesktop/login1/session/_3%s'" ++#define LOGIND_SESSION_OBJ_TEMPLATE "/org/freedesktop/login1/session/_3%s" ++ ++#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" + + #define SESSION_SIGNAL_LOCK "Lock" + #define SESSION_SIGNAL_UNLOCK "Unlock" + ++#define SESSION_PROP_LOCKED_HINT "LockedHint" ++ + /* dbus related */ + static DBusConnection *si_dbus_get_system_bus(void) + { +@@ -91,8 +98,8 @@ static void si_dbus_match_rule_update(struct session_info *si) + si_dbus_match_remove(si); + + si->dbus.match_session_signals = +- g_strdup_printf ("type='signal',interface='%s',path=" +- LOGIND_SESSION_OBJ_TEMPLATE, ++ g_strdup_printf ("type='signal',interface='%s',path='" ++ LOGIND_SESSION_OBJ_TEMPLATE"'", + LOGIND_SESSION_INTERFACE, + si->session); + if (si->verbose) +@@ -112,6 +119,84 @@ static void si_dbus_match_rule_update(struct session_info *si) + } + + static void ++si_dbus_read_properties(struct session_info *si) ++{ ++ dbus_bool_t locked_hint, ret; ++ DBusMessageIter iter, iter_variant; ++ gint type; ++ DBusError error; ++ DBusMessage *message = NULL; ++ DBusMessage *reply = NULL; ++ gchar *session_object; ++ const gchar *interface, *property; ++ ++ if (si->session == NULL) ++ return; ++ ++ session_object = g_strdup_printf(LOGIND_SESSION_OBJ_TEMPLATE, si->session); ++ message = dbus_message_new_method_call(LOGIND_INTERFACE, ++ session_object, ++ DBUS_PROPERTIES_INTERFACE, ++ "Get"); ++ g_free (session_object); ++ if (message == NULL) { ++ syslog(LOG_ERR, "Unable to create dbus message"); ++ goto exit; ++ } ++ ++ interface = LOGIND_SESSION_INTERFACE; ++ property = SESSION_PROP_LOCKED_HINT; ++ ret = dbus_message_append_args(message, ++ DBUS_TYPE_STRING, &interface, ++ DBUS_TYPE_STRING, &property, ++ DBUS_TYPE_INVALID); ++ if (!ret) { ++ syslog(LOG_ERR, "Unable to request locked-hint"); ++ goto exit; ++ } ++ ++ dbus_error_init(&error); ++ reply = dbus_connection_send_with_reply_and_block(si->dbus.system_connection, ++ message, ++ -1, ++ &error); ++ if (reply == NULL) { ++ if (dbus_error_is_set(&error)) { ++ syslog(LOG_ERR, "Properties.Get failed (locked-hint) due %s", error.message); ++ dbus_error_free(&error); ++ } else { ++ syslog(LOG_ERR, "Properties.Get failed (locked-hint)"); ++ } ++ goto exit; ++ } ++ ++ dbus_message_iter_init(reply, &iter); ++ type = dbus_message_iter_get_arg_type(&iter); ++ if (type != DBUS_TYPE_VARIANT) { ++ syslog(LOG_ERR, "expected a variant, got a '%c' instead", type); ++ goto exit; ++ } ++ ++ dbus_message_iter_recurse(&iter, &iter_variant); ++ type = dbus_message_iter_get_arg_type(&iter_variant); ++ if (type != DBUS_TYPE_BOOLEAN) { ++ syslog(LOG_ERR, "expected a boolean, got a '%c' instead", type); ++ goto exit; ++ } ++ dbus_message_iter_get_basic(&iter_variant, &locked_hint); ++ ++ si->session_locked_hint = (locked_hint) ? TRUE : FALSE; ++exit: ++ if (reply != NULL) { ++ dbus_message_unref(reply); ++ } ++ ++ if (message != NULL) { ++ dbus_message_unref(message); ++ } ++} ++ ++static void + si_dbus_read_signals(struct session_info *si) + { + DBusMessage *message = NULL; +@@ -220,16 +305,19 @@ char *session_info_session_for_pid(struct session_info *si, uint32_t pid) + + gboolean session_info_session_is_locked(struct session_info *si) + { +- g_return_val_if_fail (si != NULL, FALSE); ++ gboolean locked; + +- /* We could also rely on IdleHint property from Session which seems to work +- * well in rhel7 but it wasn't working well in my own system (F23). I'm +- * convinced for now that Lock/Unlock signals should be enough but that +- * means Lock/Unlock being done by logind. That might take a while. +- * Check: https://bugzilla.gnome.org/show_bug.cgi?id=764773 */ ++ g_return_val_if_fail (si != NULL, FALSE); + + si_dbus_read_signals(si); +- return si->session_is_locked; ++ si_dbus_read_properties(si); ++ ++ locked = (si->session_is_locked || si->session_locked_hint); ++ if (si->verbose) { ++ syslog(LOG_DEBUG, "(systemd-login) session is locked: %s", ++ locked ? "yes" : "no"); ++ } ++ return locked; + } + + /* This function should only be called after session_info_get_active_session diff --git a/SPECS/spice-vdagent.spec b/SPECS/spice-vdagent.spec index 56e7d72..576ce71 100644 --- a/SPECS/spice-vdagent.spec +++ b/SPECS/spice-vdagent.spec @@ -1,6 +1,6 @@ Name: spice-vdagent Version: 0.14.0 -Release: 10%{?dist} +Release: 14%{?dist} Summary: Agent for Spice guests Group: Applications/System License: GPLv3+ @@ -24,12 +24,27 @@ Patch11: 0011-Don-t-abort-if-XRRSetCrtcConfig-fails.patch Patch12: 0012-Fix-gdm-autostart-path.patch Patch13: 0013-data-remove-rsyslog-config-files.patch Patch14: 0014-vdagent-file-xfers-only-open-the-file-transfer-dir-w.patch +Patch15: 0015-audio-add-functions-to-set-volume-mute-with-alsa.patch +Patch16: 0016-vdagent-volume-synchronization-from-client.patch +Patch17: 0017-vdagentd-proto-strings-Add-missing-string-for-VDAGEN.patch +Patch18: 0018-vdagent-Return-1-when-virtio-device-cannot-be-opened.patch +Patch19: 0019-build-sys-Enable-large-file-support.patch +Patch20: 0020-Add-g_return_if_fail-guards-to-file-xfer-public-func.patch +Patch21: 0021-Make-creation-of-vdagent_file_xfers-optional.patch +Patch22: 0022-Disable-file-xfer-when-no-suitable-destination-dir.patch +Patch23: 0023-Report-an-error-when-file-transfers-are-disabled.patch +Patch24: 0024-vdagentd-send-file-xfer-status-generic-version.patch +Patch25: 0025-session-info-check-for-a-locked-session.patch +Patch26: 0026-session-info-check-if-session-belongs-to-user.patch +Patch27: 0027-systemd-login-check-for-LockedHint-property.patch BuildRequires: systemd-devel glib2-devel spice-protocol >= 0.12.6 BuildRequires: libpciaccess-devel libXrandr-devel libXinerama-devel BuildRequires: libXfixes-devel systemd-units desktop-file-utils libtool +BuildRequires: alsa-lib-devel dbus-devel Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units +Requires: dbus systemd >= 219-21 %description Spice agent for Linux guests offering the following features: @@ -59,6 +74,19 @@ Features: %patch12 -p1 %patch13 -p1 %patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 autoreconf -fi @@ -100,6 +128,26 @@ rm $RPM_BUILD_ROOT%{_sysconfdir}/modules-load.d/spice-vdagentd.conf %changelog +* Fri Jul 8 2016 Victor Toso - 0.14.0-14 +- Do not allow drag-and-drop on (gdm) login screen + Resolves: rhbz#1328761 +- Do not allow drag-and-drop on locked screen + Resolves: rhbz#1323623 + +* Thu Apr 28 2016 Christophe Fergeau - 0.14.0-13 +- Enable large file support + Resolves: rhbz#1331490 + +* Thu Apr 28 2016 Christophe Fergeau - 0.14.0-12 +- Apply patches forgotten in previous build.. + Related: rhbz#1264102, rhbz#1256704 + +* Thu Apr 28 2016 Christophe Fergeau - 0.14.0-11 +- Add client to guest audio volume synchronization + Resolves: rhbz#1264102 +- Exit with error when virtio channel device is missing + Resolves: rhbz#1256704 + * Fri Jun 05 2015 Jonathon Jongsma - 0.14.0-10 - Don't open a separate file manager for each file transfered Resolves: rhbz#1168324