[Spice-devel] [vdagent-linux v2 1/5] session-info: check for a locked session

Victor Toso victortoso at redhat.com
Thu Apr 28 12:10:32 UTC 2016


On Wed, Apr 27, 2016 at 04:19:34PM -0500, Jonathon Jongsma wrote:
> On Sat, 2016-04-23 at 12:53 +0200, Victor Toso wrote:
> > 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
> > ---
> >  configure.ac             |   1 +
> >  src/console-kit.c        |   7 +++
> >  src/dummy-session-info.c |   5 ++
> >  src/session-info.h       |   3 ++
> >  src/systemd-login.c      | 128
> > +++++++++++++++++++++++++++++++++++++++++++++++
> >  src/vdagentd.c           |   7 +++
> >  6 files changed, 151 insertions(+)
> > 
> > diff --git a/configure.ac b/configure.ac
> > index 2fe685b..aa2ef9f 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -81,6 +81,7 @@ PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= 2.28])
> >  PKG_CHECK_MODULES(X, [xfixes xrandr >= 1.3 xinerama x11])
> >  PKG_CHECK_MODULES(SPICE, [spice-protocol >= 0.12.8])
> >  PKG_CHECK_MODULES(ALSA, [alsa >= 1.0.22])
> > +PKG_CHECK_MODULES([DBUS], [dbus-1])
>
> If you're adding a hard dbus requirement here, we could remove the conditional
> requirement from the console-kit section of configure.ac.

Squashed the next patch into this one.

> That said, it's kind of a shame to use libdbus for new code. Perhaps
> we could keep using libdbus for the consolekit / rhel6 code and bump
> the glib requirement for the systemd backend and use gdbus there?

I think we would need to have glib mainloop in the agent in order to
rely on gdbus. I'm in favour of it but I think we could do it later on,
after some more clean up in the agent code.

This work/cleanup could be done in order to have gtk integration in the
agent.  If that seems reasonable we can discuss the best way to do it.

Marc-André has started a 'vdagent-gtk' branch with a lot of interesting
changes [0] but it's been a while since I've read it.

[0] https://github.com/elmarco/vdagent-gtk

>
> >
> >  if test "$with_session_info" = "auto" || test "$with_session_info" =
> > "systemd"; then
> >      PKG_CHECK_MODULES([LIBSYSTEMD_LOGIN],
> > diff --git a/src/console-kit.c b/src/console-kit.c
> > index f3c4aa3..9662d3d 100644
> > --- a/src/console-kit.c
> > +++ b/src/console-kit.c
> > @@ -416,3 +416,10 @@ static char
> > *console_kit_check_active_session_change(struct session_info *si)
> >  
> >      return si->active_session;
> >  }
> > +
> > +gboolean session_info_session_is_locked(struct session_info *si)
> > +{
> > +    /* 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 2f0ae65..e7a716f 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 c4f8187..f395dbf 100644
> > --- a/src/session-info.h
> > +++ b/src/session-info.h
> > @@ -24,6 +24,7 @@
> >  
> >  #include <stdio.h>
> >  #include <stdint.h>
> > +#include <glib.h>
> >  
> >  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 9ba300a..470a9ff 100644
> > --- a/src/systemd-login.c
> > +++ b/src/systemd-login.c
> > @@ -25,13 +25,121 @@
> >  #include <string.h>
> >  #include <syslog.h>
> >  #include <systemd/sd-login.h>
> > +#include <dbus/dbus.h>
> >  
> >  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);
> > +}
> > +
> > +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);
> > +    }
> > +}
> > +
> > +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;
> > +
> > +        if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) {
> > +            syslog(LOG_WARNING, "(systemd-login) received non signal
> > message");
> > +            dbus_message_unref(message);
> > +            break;
> > +        }
> > +
> > +        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 (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,18 @@ 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)
> > +{
> > +    if (si == NULL)
> > +        return 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 69332ff..efcf951 100644
> > --- a/src/vdagentd.c
> > +++ b/src/vdagentd.c
> > @@ -279,6 +279,13 @@ static void do_client_file_xfer(struct
> > vdagent_virtio_port *vport,
> >                 "active session, cancelling client file-xfer request %u",
> >                 s->id);
> >              return;
> > +        } else if (session_info_session_is_locked(session_info)) {
> > +            syslog(LOG_DEBUG, "Session is locked, skipping file-xfer-start");
> > +            cancel_file_xfer(vport,
> > +               "User's session is locked and cannot start file transfer. "
> > +               "Cancelling client file-xfer request %u",
> > +               s->id);
> > +            return;
> >          }
> >          udscs_write(active_session_conn, VDAGENTD_FILE_XFER_START, 0, 0,
> >                      data, message_header->size);


More information about the Spice-devel mailing list