[gnome-settings-daemon] automount: disable automounting while screen is locked



commit 71deedf732a0fa52a58407c271c764f851cb6f57
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Mon Feb 21 11:47:26 2011 -0500

    automount: disable automounting while screen is locked
    
    Based on an initial patch by Martin Pitt <martin pitt ubuntu com>
    
    On the recent Shmoocon there was a presentation by Jon Larimer demonstrating
    how to abuse vulnerabilities and bugs, or even just creating socially or
    security compromising thumbnails in mounting and thumbnailing, which happens on
    automounting USB drives. This is a particular issue when this happens on a
    locked box where the attacker doesn't otherwise have access to the user
    account:
    
      http://www.net-security.org/secworld.php?id=10544
    
    Disable automounting if the GNOME screen saver is currently locked.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=642020

 plugins/automount/gsd-automount-manager.c |  217 ++++++++++++++++++++++++++++-
 1 files changed, 216 insertions(+), 1 deletions(-)
---
diff --git a/plugins/automount/gsd-automount-manager.c b/plugins/automount/gsd-automount-manager.c
index d2a5c9e..788a5fe 100644
--- a/plugins/automount/gsd-automount-manager.c
+++ b/plugins/automount/gsd-automount-manager.c
@@ -43,6 +43,12 @@ struct GsdAutomountManagerPrivate
 
         gboolean session_is_active;
         GDBusProxy *ck_proxy;
+
+        gboolean screensaver_active;
+        guint ss_watch_id;
+        GDBusProxy *ss_proxy;
+
+        GList *volume_queue;
 };
 
 static void     gsd_automount_manager_class_init  (GsdAutomountManagerClass *klass);
@@ -171,6 +177,60 @@ do_mount_volume (GVolume *volume)
 }
 
 static void
+check_volume_queue (GsdAutomountManager *manager)
+{
+        GList *l, *next;
+        GVolume *volume;
+
+        l = manager->priv->volume_queue;
+
+        if (!manager->priv->screensaver_active) {
+                g_assert (l == NULL);
+        }
+
+        while (l != NULL) {
+                volume = l->data;
+                next = l->next;
+
+                do_mount_volume (volume);
+                manager->priv->volume_queue =
+                        g_list_remove (manager->priv->volume_queue, volume);
+
+                g_object_unref (volume);
+                l = next;
+        }
+
+        manager->priv->volume_queue = NULL;
+}
+
+static void
+check_screen_lock_and_mount (GsdAutomountManager *manager,
+                             GVolume *volume)
+{
+        if (manager->priv->screensaver_active) {
+                /* queue the volume, to mount it after the screensaver state changed */
+                g_debug ("Queuing volume %p", volume);
+                manager->priv->volume_queue = g_list_prepend (manager->priv->volume_queue,
+                                                              g_object_ref (volume));
+        } else {
+                /* mount it immediately */
+                do_mount_volume (volume);
+        }       
+}
+
+static void
+volume_removed_callback (GVolumeMonitor *monitor,
+                         GVolume *volume,
+                         GsdAutomountManager *manager)
+{
+        g_debug ("Volume %p removed, removing from the queue", volume);
+
+        /* clear it from the queue, if present */
+        manager->priv->volume_queue =
+                g_list_remove (manager->priv->volume_queue, volume);
+}
+
+static void
 volume_added_callback (GVolumeMonitor *monitor,
 		       GVolume *volume,
 		       GsdAutomountManager *manager)
@@ -178,7 +238,7 @@ volume_added_callback (GVolumeMonitor *monitor,
 	if (g_settings_get_boolean (manager->priv->settings, "automount") &&
 	    g_volume_should_automount (volume) &&
 	    g_volume_can_mount (volume)) {
-	    do_mount_volume (volume);
+                check_screen_lock_and_mount (manager, volume);
 	} else {
 		/* Allow gsd_autorun() to run. When the mount is later
 		 * added programmatically (i.e. for a blank CD),
@@ -380,16 +440,163 @@ do_initialize_consolekit (GsdAutomountManager *manager)
         g_object_unref (connection);
 }
 
+#define SCREENSAVER_NAME "org.gnome.ScreenSaver"
+#define SCREENSAVER_PATH "/org/gnome/ScreenSaver"
+#define SCREENSAVER_INTERFACE "org.gnome.ScreenSaver"
+
+static void
+screensaver_signal_callback (GDBusProxy *proxy,
+                             const gchar *sender_name,
+                             const gchar *signal_name,
+                             GVariant *parameters,
+                             gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+
+        if (g_strcmp0 (signal_name, "ActiveChanged") == 0) {
+                g_variant_get (parameters, "(b)", &manager->priv->screensaver_active);
+                g_debug ("Screensaver active changed to %d", manager->priv->screensaver_active);
+
+                check_volume_queue (manager);
+        }
+}
+
+static void
+screensaver_get_active_ready_cb (GObject *source,
+                                 GAsyncResult *res,
+                                 gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+        GDBusProxy *proxy = manager->priv->ss_proxy;
+        GVariant *result;
+        GError *error = NULL;
+
+        result = g_dbus_proxy_call_finish (proxy,
+                                           res,
+                                           &error);
+
+        if (error != NULL) {
+                g_warning ("Can't call GetActive() on the ScreenSaver object: %s",
+                           error->message);
+                g_error_free (error);
+
+                return;
+        }
+
+        g_variant_get (result, "(b)", &manager->priv->screensaver_active);
+        g_variant_unref (result);
+
+        g_debug ("Screensaver GetActive() returned %d", manager->priv->screensaver_active);
+}
+
+static void
+screensaver_proxy_ready_cb (GObject *source,
+                            GAsyncResult *res,
+                            gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+        GError *error = NULL;
+        GDBusProxy *ss_proxy;
+        
+        ss_proxy = g_dbus_proxy_new_finish (res, &error);
+
+        if (error != NULL) {
+                g_warning ("Can't get proxy for the ScreenSaver object: %s",
+                           error->message);
+                g_error_free (error);
+
+                return;
+        }
+
+        g_debug ("ScreenSaver proxy ready");
+
+        manager->priv->ss_proxy = ss_proxy;
+
+        g_signal_connect (ss_proxy, "g-signal",
+                          G_CALLBACK (screensaver_signal_callback), manager);
+
+        g_dbus_proxy_call (ss_proxy,
+                           "GetActive",
+                           NULL,
+                           G_DBUS_CALL_FLAGS_NO_AUTO_START,
+                           -1,
+                           NULL,
+                           screensaver_get_active_ready_cb,
+                           manager);
+}
+
+static void
+screensaver_appeared_callback (GDBusConnection *connection,
+                               const gchar *name,
+                               const gchar *name_owner,
+                               gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+
+        g_debug ("ScreenSaver name appeared");
+
+        manager->priv->screensaver_active = FALSE;
+
+        g_dbus_proxy_new (connection,
+                          G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+                          NULL,
+                          name,
+                          SCREENSAVER_PATH,
+                          SCREENSAVER_INTERFACE,
+                          NULL,
+                          screensaver_proxy_ready_cb,
+                          manager);
+}
+
+static void
+screensaver_vanished_callback (GDBusConnection *connection,
+                               const gchar *name,
+                               gpointer user_data)
+{
+        GsdAutomountManager *manager = user_data;
+
+        g_debug ("ScreenSaver name vanished");
+
+        manager->priv->screensaver_active = FALSE;
+        g_clear_object (&manager->priv->ss_proxy);
+
+        /* in this case force a clear of the volume queue, without
+         * mounting them.
+         */
+        if (manager->priv->volume_queue != NULL) {
+                g_list_free_full (manager->priv->volume_queue, g_object_unref);
+                manager->priv->volume_queue = NULL;
+        }
+}
+
+static void
+do_initialize_screensaver (GsdAutomountManager *manager)
+{
+        GsdAutomountManagerPrivate *p = manager->priv;
+
+        p->ss_watch_id =
+                g_bus_watch_name (G_BUS_TYPE_SESSION,
+                                  SCREENSAVER_NAME,
+                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
+                                  screensaver_appeared_callback,
+                                  screensaver_vanished_callback,
+                                  manager,
+                                  NULL);
+}
+
 static void
 setup_automounter (GsdAutomountManager *manager)
 {
         do_initialize_consolekit (manager);
+        do_initialize_screensaver (manager);
         
 	manager->priv->volume_monitor = g_volume_monitor_get ();
 	g_signal_connect_object (manager->priv->volume_monitor, "mount-added",
 				 G_CALLBACK (mount_added_callback), manager, 0);
 	g_signal_connect_object (manager->priv->volume_monitor, "volume-added",
 				 G_CALLBACK (volume_added_callback), manager, 0);
+	g_signal_connect_object (manager->priv->volume_monitor, "volume-removed",
+				 G_CALLBACK (volume_removed_callback), manager, 0);
 
 	manager->priv->automount_idle_id =
 		g_idle_add_full (G_PRIORITY_LOW,
@@ -422,6 +629,14 @@ gsd_automount_manager_stop (GsdAutomountManager *manager)
         g_clear_object (&p->ck_proxy);
         g_clear_object (&p->volume_monitor);
         g_clear_object (&p->settings);
+        g_clear_object (&p->ss_proxy);
+
+        g_bus_unwatch_name (p->ss_watch_id);
+
+        if (p->volume_queue != NULL) {
+                g_list_free_full (p->volume_queue, g_object_unref);
+                p->volume_queue = NULL;
+        }
 
         if (p->automount_idle_id != 0) {
                 g_source_remove (p->automount_idle_id);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]