Blame SOURCES/0025-session-info-check-for-a-locked-session.patch

a547b4
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
a547b4
From: Victor Toso <victortoso@redhat.com>
a547b4
Date: Sat, 9 Apr 2016 12:00:08 +0200
a547b4
Subject: [PATCH] session-info: check for a locked session
a547b4
a547b4
Each session back-end can return this information to vdagentd when
a547b4
requested.
a547b4
a547b4
The agent should use this on situations that should not work when
a547b4
session is locked such as file-transfer-start which is fixed by this
a547b4
patch.
a547b4
a547b4
systemd-login is the only back-end implementing this function at the
a547b4
moment and I'll address console-kit back-end in a later patch.
a547b4
a547b4
Also, this patch makes spice-vdagent depend on dbus for getting the
a547b4
lock information.
a547b4
a547b4
Resolve: https://bugzilla.redhat.com/show_bug.cgi?id=1323623
a547b4
a547b4
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
a547b4
(cherry picked from commit 364b6bba068bd694d7c4355b6275f88482d9f3f8)
a547b4
---
a547b4
 configure.ac             |  17 ++-----
a547b4
 src/console-kit.c        |   7 +++
a547b4
 src/dummy-session-info.c |   5 ++
a547b4
 src/session-info.h       |   3 ++
a547b4
 src/systemd-login.c      | 127 +++++++++++++++++++++++++++++++++++++++++++++++
a547b4
 src/vdagentd.c           |   7 +++
a547b4
 6 files changed, 153 insertions(+), 13 deletions(-)
a547b4
a547b4
diff --git a/configure.ac b/configure.ac
a547b4
index 9f9d34c..9903ea9 100644
a547b4
--- a/configure.ac
a547b4
+++ b/configure.ac
a547b4
@@ -81,6 +81,7 @@ PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= 2.12])
a547b4
 PKG_CHECK_MODULES(X, [xfixes xrandr >= 1.3 xinerama x11])
a547b4
 PKG_CHECK_MODULES(SPICE, [spice-protocol >= 0.12.5])
a547b4
 PKG_CHECK_MODULES(ALSA, [alsa >= 1.0.22])
a547b4
+PKG_CHECK_MODULES([DBUS], [dbus-1])
a547b4
 
a547b4
 if test "$with_session_info" = "auto" || test "$with_session_info" = "systemd"; then
a547b4
     PKG_CHECK_MODULES([LIBSYSTEMD_LOGIN],
a547b4
@@ -100,19 +101,9 @@ fi
a547b4
 AM_CONDITIONAL(HAVE_LIBSYSTEMD_LOGIN, test x"$have_libsystemd_login" = "xyes")
a547b4
 
a547b4
 if test "$with_session_info" = "auto" || test "$with_session_info" = "console-kit"; then
a547b4
-    PKG_CHECK_MODULES([DBUS],
a547b4
-                      [dbus-1],
a547b4
-                      [have_console_kit="yes"],
a547b4
-                      [have_console_kit="no"])
a547b4
-    if test x"$have_console_kit" = "xno" && test "$with_session_info" = "console-kit"; then
a547b4
-        AC_MSG_ERROR([console-kit support explicitly requested, but some required packages are not available])
a547b4
-    fi
a547b4
-    if test x"$have_console_kit" = "xyes"; then
a547b4
-        AC_DEFINE([HAVE_CONSOLE_KIT], [1], [If defined, vdagentd will be compiled with ConsoleKit support])
a547b4
-        with_session_info="console-kit"
a547b4
-    else
a547b4
-        with_session_info="none"
a547b4
-    fi
a547b4
+    AC_DEFINE([HAVE_CONSOLE_KIT], [1], [If defined, vdagentd will be compiled with ConsoleKit support])
a547b4
+    have_console_kit="yes"
a547b4
+    with_session_info="console-kit"
a547b4
 else
a547b4
     have_console_kit="no"
a547b4
 fi
a547b4
diff --git a/src/console-kit.c b/src/console-kit.c
a547b4
index 759a81e..260fcc7 100644
a547b4
--- a/src/console-kit.c
a547b4
+++ b/src/console-kit.c
a547b4
@@ -352,3 +352,10 @@ static char *console_kit_check_active_session_change(struct session_info *ck)
a547b4
 
a547b4
     return ck->active_session;
a547b4
 }
a547b4
+
a547b4
+gboolean session_info_session_is_locked(struct session_info *info)
a547b4
+{
a547b4
+    /* TODO: It could be implemented based on Lock/Unlock signals from Session
a547b4
+     * interface. */
a547b4
+    return FALSE;
a547b4
+}
a547b4
diff --git a/src/dummy-session-info.c b/src/dummy-session-info.c
a547b4
index e188ddc..c09643b 100644
a547b4
--- a/src/dummy-session-info.c
a547b4
+++ b/src/dummy-session-info.c
a547b4
@@ -44,3 +44,8 @@ char *session_info_session_for_pid(struct session_info *si, uint32_t pid)
a547b4
 {
a547b4
     return NULL;
a547b4
 }
a547b4
+
a547b4
+gboolean session_is_locked(struct session_info *ck)
a547b4
+{
a547b4
+    return FALSE;
a547b4
+}
a547b4
diff --git a/src/session-info.h b/src/session-info.h
a547b4
index 67099de..d660fcf 100644
a547b4
--- a/src/session-info.h
a547b4
+++ b/src/session-info.h
a547b4
@@ -24,6 +24,7 @@
a547b4
 
a547b4
 #include <stdio.h>
a547b4
 #include <stdint.h>
a547b4
+#include <glib.h>
a547b4
 
a547b4
 struct session_info;
a547b4
 
a547b4
@@ -36,4 +37,6 @@ const char *session_info_get_active_session(struct session_info *ck);
a547b4
 /* Note result must be free()-ed by caller */
a547b4
 char *session_info_session_for_pid(struct session_info *ck, uint32_t pid);
a547b4
 
a547b4
+gboolean session_info_session_is_locked(struct session_info *si);
a547b4
+
a547b4
 #endif
a547b4
diff --git a/src/systemd-login.c b/src/systemd-login.c
a547b4
index 73db37f..4a365c0 100644
a547b4
--- a/src/systemd-login.c
a547b4
+++ b/src/systemd-login.c
a547b4
@@ -25,13 +25,121 @@
a547b4
 #include <string.h>
a547b4
 #include <syslog.h>
a547b4
 #include <systemd/sd-login.h>
a547b4
+#include <dbus/dbus.h>
a547b4
 
a547b4
 struct session_info {
a547b4
     int verbose;
a547b4
     sd_login_monitor *mon;
a547b4
     char *session;
a547b4
+    struct {
a547b4
+        DBusConnection *system_connection;
a547b4
+        char *match_session_signals;
a547b4
+    } dbus;
a547b4
+    gboolean session_is_locked;
a547b4
 };
a547b4
 
a547b4
+#define LOGIND_SESSION_INTERFACE    "org.freedesktop.login1.Session"
a547b4
+#define LOGIND_SESSION_OBJ_TEMPLATE "'/org/freedesktop/login1/session/_3%s'"
a547b4
+
a547b4
+#define SESSION_SIGNAL_LOCK         "Lock"
a547b4
+#define SESSION_SIGNAL_UNLOCK       "Unlock"
a547b4
+
a547b4
+/* dbus related */
a547b4
+static DBusConnection *si_dbus_get_system_bus(void)
a547b4
+{
a547b4
+    DBusConnection *connection;
a547b4
+    DBusError error;
a547b4
+
a547b4
+    dbus_error_init(&error);
a547b4
+    connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
a547b4
+    if (connection == NULL || dbus_error_is_set(&error)) {
a547b4
+        if (dbus_error_is_set(&error)) {
a547b4
+            syslog(LOG_WARNING, "Unable to connect to system bus: %s",
a547b4
+                   error.message);
a547b4
+            dbus_error_free(&error);
a547b4
+        } else {
a547b4
+            syslog(LOG_WARNING, "Unable to connect to system bus");
a547b4
+        }
a547b4
+        return NULL;
a547b4
+    }
a547b4
+    return connection;
a547b4
+}
a547b4
+
a547b4
+static void si_dbus_match_remove(struct session_info *si)
a547b4
+{
a547b4
+    DBusError error;
a547b4
+    if (si->dbus.match_session_signals == NULL)
a547b4
+        return;
a547b4
+
a547b4
+    dbus_error_init(&error);
a547b4
+    dbus_bus_remove_match(si->dbus.system_connection,
a547b4
+                          si->dbus.match_session_signals,
a547b4
+                          &error);
a547b4
+
a547b4
+    g_free(si->dbus.match_session_signals);
a547b4
+    si->dbus.match_session_signals = NULL;
a547b4
+}
a547b4
+
a547b4
+static void si_dbus_match_rule_update(struct session_info *si)
a547b4
+{
a547b4
+    DBusError error;
a547b4
+
a547b4
+    if (si->dbus.system_connection == NULL ||
a547b4
+            si->session == NULL)
a547b4
+        return;
a547b4
+
a547b4
+    si_dbus_match_remove(si);
a547b4
+
a547b4
+    si->dbus.match_session_signals =
a547b4
+        g_strdup_printf ("type='signal',interface='%s',path="
a547b4
+                         LOGIND_SESSION_OBJ_TEMPLATE,
a547b4
+                         LOGIND_SESSION_INTERFACE,
a547b4
+                         si->session);
a547b4
+    if (si->verbose)
a547b4
+        syslog(LOG_DEBUG, "logind match: %s", si->dbus.match_session_signals);
a547b4
+
a547b4
+    dbus_error_init(&error);
a547b4
+    dbus_bus_add_match(si->dbus.system_connection,
a547b4
+                       si->dbus.match_session_signals,
a547b4
+                       &error);
a547b4
+    if (dbus_error_is_set(&error)) {
a547b4
+        syslog(LOG_WARNING, "Unable to add dbus rule match: %s",
a547b4
+               error.message);
a547b4
+        dbus_error_free(&error);
a547b4
+        g_free(si->dbus.match_session_signals);
a547b4
+        si->dbus.match_session_signals = NULL;
a547b4
+    }
a547b4
+}
a547b4
+
a547b4
+static void
a547b4
+si_dbus_read_signals(struct session_info *si)
a547b4
+{
a547b4
+    DBusMessage *message = NULL;
a547b4
+
a547b4
+    dbus_connection_read_write(si->dbus.system_connection, 0);
a547b4
+    message = dbus_connection_pop_message(si->dbus.system_connection);
a547b4
+    while (message != NULL) {
a547b4
+        const char *member;
a547b4
+
a547b4
+        member = dbus_message_get_member (message);
a547b4
+        if (g_strcmp0(member, SESSION_SIGNAL_LOCK) == 0) {
a547b4
+            si->session_is_locked = TRUE;
a547b4
+        } else if (g_strcmp0(member, SESSION_SIGNAL_UNLOCK) == 0) {
a547b4
+            si->session_is_locked = FALSE;
a547b4
+        } else {
a547b4
+            if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
a547b4
+                syslog(LOG_WARNING, "(systemd-login) received non signal message");
a547b4
+            } else if (si->verbose) {
a547b4
+                syslog(LOG_DEBUG, "(systemd-login) Signal not handled: %s", member);
a547b4
+            }
a547b4
+        }
a547b4
+
a547b4
+        dbus_message_unref(message);
a547b4
+        dbus_connection_read_write(si->dbus.system_connection, 0);
a547b4
+        message = dbus_connection_pop_message(si->dbus.system_connection);
a547b4
+    }
a547b4
+}
a547b4
+
a547b4
 struct session_info *session_info_create(int verbose)
a547b4
 {
a547b4
     struct session_info *si;
a547b4
@@ -42,6 +150,7 @@ struct session_info *session_info_create(int verbose)
a547b4
         return NULL;
a547b4
 
a547b4
     si->verbose = verbose;
a547b4
+    si->session_is_locked = FALSE;
a547b4
 
a547b4
     r = sd_login_monitor_new("session", &si->mon);
a547b4
     if (r < 0) {
a547b4
@@ -50,6 +159,7 @@ struct session_info *session_info_create(int verbose)
a547b4
         return NULL;
a547b4
     }
a547b4
 
a547b4
+    si->dbus.system_connection = si_dbus_get_system_bus();
a547b4
     return si;
a547b4
 }
a547b4
 
a547b4
@@ -58,6 +168,8 @@ void session_info_destroy(struct session_info *si)
a547b4
     if (!si)
a547b4
         return;
a547b4
 
a547b4
+    si_dbus_match_remove(si);
a547b4
+    dbus_connection_close(si->dbus.system_connection);
a547b4
     sd_login_monitor_unref(si->mon);
a547b4
     free(si->session);
a547b4
     free(si);
a547b4
@@ -87,6 +199,7 @@ const char *session_info_get_active_session(struct session_info *si)
a547b4
     sd_login_monitor_flush(si->mon);
a547b4
     free(old_session);
a547b4
 
a547b4
+    si_dbus_match_rule_update(si);
a547b4
     return si->session;
a547b4
 }
a547b4
 
a547b4
@@ -104,3 +217,17 @@ char *session_info_session_for_pid(struct session_info *si, uint32_t pid)
a547b4
 
a547b4
     return session;
a547b4
 }
a547b4
+
a547b4
+gboolean session_info_session_is_locked(struct session_info *si)
a547b4
+{
a547b4
+    g_return_val_if_fail (si != NULL, FALSE);
a547b4
+
a547b4
+    /* We could also rely on IdleHint property from Session which seems to work
a547b4
+     * well in rhel7 but it wasn't working well in my own system (F23). I'm
a547b4
+     * convinced for now that Lock/Unlock signals should be enough but that
a547b4
+     * means Lock/Unlock being done by logind. That might take a while.
a547b4
+     * Check: https://bugzilla.gnome.org/show_bug.cgi?id=764773 */
a547b4
+
a547b4
+    si_dbus_read_signals(si);
a547b4
+    return si->session_is_locked;
a547b4
+}
a547b4
diff --git a/src/vdagentd.c b/src/vdagentd.c
a547b4
index 2c8e973..2f77773 100644
a547b4
--- a/src/vdagentd.c
a547b4
+++ b/src/vdagentd.c
a547b4
@@ -276,6 +276,13 @@ static void do_client_file_xfer(struct vdagent_virtio_port *vport,
a547b4
                "active session, cancelling client file-xfer request %u",
a547b4
                s->id, VD_AGENT_FILE_XFER_STATUS_CANCELLED);
a547b4
             return;
a547b4
+        } else if (session_info_session_is_locked(session_info)) {
a547b4
+            syslog(LOG_DEBUG, "Session is locked, skipping file-xfer-start");
a547b4
+            send_file_xfer_status(vport,
a547b4
+               "User's session is locked and cannot start file transfer. "
a547b4
+               "Cancelling client file-xfer request %u",
a547b4
+               s->id, VD_AGENT_FILE_XFER_STATUS_ERROR);
a547b4
+            return;
a547b4
         }
a547b4
         udscs_write(active_session_conn, VDAGENTD_FILE_XFER_START, 0, 0,
a547b4
                     data, message_header->size);