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

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