From b7262fa945ef1ea936c15f0d248ad7a024d97dca Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Tue, 22 Feb 2011 13:06:14 +0000 Subject: 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 --- diff --git a/src/nautilus-application.c b/src/nautilus-application.c index 08407a5..dfeaea6 100644 --- a/src/nautilus-application.c +++ b/src/nautilus-application.c @@ -116,6 +116,9 @@ static void mount_added_callback (GVolumeMonitor *mo 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,13 @@ nautilus_application_finalize (GObject *object) g_object_unref (application->unique_app); + 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 +367,11 @@ nautilus_application_finalize (GObject *object) 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 +678,182 @@ do_initialize_consolekit (NautilusApplication *application) } 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); + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "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); + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "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; + } + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "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; + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "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; + + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "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 +900,10 @@ finish_startup (NautilusApplication *application, /* 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 +919,8 @@ finish_startup (NautilusApplication *application, 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 +1717,35 @@ window_can_be_closed (NautilusWindow *window) } 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 */ + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "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) +{ + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "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 +1753,7 @@ volume_added_callback (GVolumeMonitor *monitor, 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), diff --git a/src/nautilus-application.h b/src/nautilus-application.h index 36e53b6..d558932 100644 --- a/src/nautilus-application.h +++ b/src/nautilus-application.h @@ -68,6 +68,11 @@ typedef struct { 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 { -- cgit v0.9