From 98ebb6be0882ba2dbb0c621a2906e5190108bca1 Mon Sep 17 00:00:00 2001
From: Martin Pitt <martin.pitt@ubuntu.com>
Date: Tue, 22 Feb 2011 14:06:14 +0100
Subject: [PATCH] disable automounting while screen is locked

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 o
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.

Backported from gnome-settings-daemon trunk commits 71deedf7 and 90c0f8676.

https://bugzilla.gnome.org/show_bug.cgi?id=642020
---
 src/nautilus-application.c |  219 +++++++++++++++++++++++++++++++++++++++++++-
 src/nautilus-application.h |    5 +
 2 files changed, 223 insertions(+), 1 deletions(-)

Index: nautilus-2.32.2.1/src/nautilus-application.c
===================================================================
--- nautilus-2.32.2.1.orig/src/nautilus-application.c	2010-12-28 16:54:38.000000000 +0100
+++ nautilus-2.32.2.1/src/nautilus-application.c	2011-03-15 15:04:00.659603038 +0100
@@ -116,6 +116,9 @@
 static void     volume_added_callback              (GVolumeMonitor           *monitor,
 						    GVolume                  *volume,
 						    NautilusApplication      *application);
+static void     volume_removed_callback            (GVolumeMonitor           *monitor,
+						    GVolume                  *volume,
+						    NautilusApplication      *application);
 static void     drive_connected_callback           (GVolumeMonitor           *monitor,
 						    GDrive                   *drive,
 						    NautilusApplication      *application);
@@ -347,6 +350,15 @@
 
 	g_object_unref (application->unique_app);
 
+	if (application->ss_watch_id > 0) {
+		g_bus_unwatch_name (application->ss_watch_id);
+	}
+	
+	if (application->volume_queue != NULL) {
+		g_list_free_full (application->volume_queue, g_object_unref);
+		application->volume_queue = NULL;
+	}
+
 	if (application->automount_idle_id != 0) {
 		g_source_remove (application->automount_idle_id);
 		application->automount_idle_id = 0;
@@ -357,6 +369,11 @@
 		application->proxy = NULL;
 	}
 
+	if (application->ss_proxy != NULL) {
+		g_object_unref (application->ss_proxy);
+		application->ss_proxy = NULL;
+	}
+
         G_OBJECT_CLASS (nautilus_application_parent_class)->finalize (object);
 }
 
@@ -663,6 +680,175 @@
 }
 
 static void
+check_volume_queue (NautilusApplication *application)
+{
+        GList *l, *next;
+        GVolume *volume;
+
+        l = application->volume_queue;
+
+        if (application->screensaver_active) {
+                return;
+        }
+
+        while (l != NULL) {
+		volume = l->data;
+		next = l->next;
+
+		nautilus_file_operations_mount_volume (NULL, volume, TRUE);
+		application->volume_queue =
+			g_list_remove (application->volume_queue, volume);
+
+		g_object_unref (volume);
+		l = next;
+        }
+
+        application->volume_queue = NULL;
+}
+
+#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)
+{
+	NautilusApplication *application = user_data;
+
+	if (g_strcmp0 (signal_name, "ActiveChanged") == 0) {
+		g_variant_get (parameters, "(b)", &application->screensaver_active);
+		g_debug ("Screensaver active changed to %d", application->screensaver_active);
+
+		check_volume_queue (application);
+	}
+}
+
+static void
+screensaver_get_active_ready_cb (GObject *source,
+				 GAsyncResult *res,
+				 gpointer user_data)
+{
+	NautilusApplication *application = user_data;
+	GDBusProxy *proxy = application->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)", &application->screensaver_active);
+	g_variant_unref (result);
+
+	g_debug ("Screensaver GetActive() returned %d", application->screensaver_active);
+}
+
+static void
+screensaver_proxy_ready_cb (GObject *source,
+			    GAsyncResult *res,
+			    gpointer user_data)
+{
+	NautilusApplication *application = 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");
+
+	application->ss_proxy = ss_proxy;
+
+	g_signal_connect (ss_proxy, "g-signal",
+			  G_CALLBACK (screensaver_signal_callback), application);
+
+	g_dbus_proxy_call (ss_proxy,
+			   "GetActive",
+			   NULL,
+			   G_DBUS_CALL_FLAGS_NO_AUTO_START,
+			   -1,
+			   NULL,
+			   screensaver_get_active_ready_cb,
+			   application);
+}
+
+static void
+screensaver_appeared_callback (GDBusConnection *connection,
+			       const gchar *name,
+			       const gchar *name_owner,
+			       gpointer user_data)
+{
+	NautilusApplication *application = user_data;
+
+	g_debug ("ScreenSaver name appeared");
+
+	application->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,
+			  application);
+}
+
+static void
+screensaver_vanished_callback (GDBusConnection *connection,
+			       const gchar *name,
+			       gpointer user_data)
+{
+	NautilusApplication *application = user_data;
+
+	g_debug ("ScreenSaver name vanished");
+
+	application->screensaver_active = FALSE;
+	g_object_unref (&application->ss_proxy);
+
+	/* in this case force a clear of the volume queue, without
+	 * mounting them.
+	 */
+	if (application->volume_queue != NULL) {
+		g_list_free_full (application->volume_queue, g_object_unref);
+		application->volume_queue = NULL;
+	}
+}
+
+static void
+do_initialize_screensaver (NautilusApplication *application)
+{
+	application->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,
+				  application,
+				  NULL);
+}
+
+static void
 do_upgrades_once (NautilusApplication *application,
 		  gboolean no_desktop)
 {
@@ -709,6 +895,10 @@
 	/* Initialize the ConsoleKit listener for active session */
 	do_initialize_consolekit (application);
 
+	/* Initialize GNOME screen saver listener to control automount
+	 * permission */
+	do_initialize_screensaver (application);
+
 	/* Watch for mounts so we can restore open windows This used
 	 * to be for showing new window on mount, but is not used
 	 * anymore */
@@ -724,6 +914,8 @@
 				 G_CALLBACK (mount_added_callback), application, 0);
 	g_signal_connect_object (application->volume_monitor, "volume_added",
 				 G_CALLBACK (volume_added_callback), application, 0);
+	g_signal_connect_object (application->volume_monitor, "volume_removed",
+				 G_CALLBACK (volume_removed_callback), application, 0);
 	g_signal_connect_object (application->volume_monitor, "drive_connected",
 				 G_CALLBACK (drive_connected_callback), application, 0);
 
@@ -1520,6 +1712,33 @@
 }
 
 static void
+check_screen_lock_and_mount (NautilusApplication *application,
+                             GVolume *volume)
+{
+        if (application->screensaver_active) {
+                /* queue the volume, to mount it after the screensaver state changed */
+                g_debug ("Queuing volume %p", volume);
+                application->volume_queue = g_list_prepend (application->volume_queue,
+                                                              g_object_ref (volume));
+        } else {
+                /* mount it immediately */
+		nautilus_file_operations_mount_volume (NULL, volume, TRUE);
+        }       
+}
+
+static void
+volume_removed_callback (GVolumeMonitor *monitor,
+                         GVolume *volume,
+                         NautilusApplication *application)
+{
+        g_debug ("Volume %p removed, removing from the queue", volume);
+
+        /* clear it from the queue, if present */
+        application->volume_queue =
+                g_list_remove (application->volume_queue, volume);
+}
+
+static void
 volume_added_callback (GVolumeMonitor *monitor,
 		       GVolume *volume,
 		       NautilusApplication *application)
@@ -1527,7 +1746,7 @@
 	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_MEDIA_AUTOMOUNT) &&
 	    g_volume_should_automount (volume) &&
 	    g_volume_can_mount (volume)) {
-		nautilus_file_operations_mount_volume (NULL, volume, TRUE);
+		check_screen_lock_and_mount (application, volume);
 	} else {
 		/* Allow nautilus_autorun() to run. When the mount is later
 		 * added programmatically (i.e. for a blank CD),
Index: nautilus-2.32.2.1/src/nautilus-application.h
===================================================================
--- nautilus-2.32.2.1.orig/src/nautilus-application.h	2010-12-28 16:54:38.000000000 +0100
+++ nautilus-2.32.2.1/src/nautilus-application.h	2011-03-15 15:03:21.099603020 +0100
@@ -68,6 +68,11 @@
 	unsigned int automount_idle_id;
 	GDBusProxy *proxy;
 	gboolean session_is_active;
+
+	gboolean screensaver_active;
+	guint ss_watch_id;
+	GDBusProxy *ss_proxy;
+	GList *volume_queue;
 } NautilusApplication;
 
 typedef struct {
