summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2012-04-22 11:50:42 -0400
committerDavid Zeuthen <davidz@redhat.com>2012-04-22 11:57:21 -0400
commit9541a638ffd3b1bcb1b6ef6a8a00cc599a626093 (patch)
tree6c971d472cc21a233aa9726e7c92b0ccfc3f2456
parent0d924997d7d21c9cbdf2e59ce11395481e6147e8 (diff)
Interpret ID_SEAT=all to mean that a device is available on all seats
This changes a couple of things - when mounting the device, we use different defaults so other users can access the filesystem too. We also mount the device in /media, not /run/media/$USER (unless an /etc/fstab entry exists for the device, of course) - if the drive is shared, we allow other users to unmount a filesystem mounted by another user (through a new polkit action) - we need to serialize multiple concurrent mount requests so we don't end up mounting the device twice... with this change, one one of the requests will succeed, the other one will get the AlreadyMounted error (basically, add locking, we needed that anyway .. it just only became apparent with this change because multiple sessions tried to mount the shared drive.) Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r--data/org.freedesktop.UDisks2.xml3
-rw-r--r--data/org.freedesktop.udisks2.policy.in10
-rw-r--r--src/udisksdaemonutil.c10
-rw-r--r--src/udiskslinuxdrive.c7
-rw-r--r--src/udiskslinuxfilesystem.c129
5 files changed, 139 insertions, 20 deletions
diff --git a/data/org.freedesktop.UDisks2.xml b/data/org.freedesktop.UDisks2.xml
index 7ca555e..ee76c32 100644
--- a/data/org.freedesktop.UDisks2.xml
+++ b/data/org.freedesktop.UDisks2.xml
@@ -225,6 +225,9 @@
<!-- Seat:
A string identifying what seat the drive is plugged into, if any.
+
+ The special value <quote>all</quote> means that the drive
+ should is available on all seats.
-->
<property name="Seat" type="s" access="read"/>
diff --git a/data/org.freedesktop.udisks2.policy.in b/data/org.freedesktop.udisks2.policy.in
index d150eb2..7963252 100644
--- a/data/org.freedesktop.udisks2.policy.in
+++ b/data/org.freedesktop.udisks2.policy.in
@@ -60,6 +60,16 @@
</defaults>
</action>
+ <action id="org.freedesktop.udisks2.filesystem-unmount-others-shared">
+ <_description>Unmount a shared device mounted by another user</_description>
+ <_message>Authentication is required to unmount a filesystem mounted by another user</_message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>yes</allow_active>
+ </defaults>
+ </action>
+
<!-- Unlocking encrypted devices -->
<action id="org.freedesktop.udisks2.encrypted-unlock">
<_description>Unlock an encrypted device</_description>
diff --git a/src/udisksdaemonutil.c b/src/udisksdaemonutil.c
index bac1057..0804e83 100644
--- a/src/udisksdaemonutil.c
+++ b/src/udisksdaemonutil.c
@@ -859,12 +859,18 @@ udisks_daemon_util_on_same_seat (UDisksDaemon *daemon,
/* Assume device belongs to "seat0" if not tagged */
drive_seat = udisks_drive_get_seat (drive);
- if (drive_seat == NULL || strlen (drive_seat) == 0)
- drive_seat = "seat0";
+
+ /* the special value "all" means available on all seat, hence available on caller's seat */
+ if (g_strcmp0 (drive_seat, "all") == 0)
+ {
+ ret = TRUE;
+ goto out;
+ }
if (g_strcmp0 (seat, drive_seat) == 0)
{
ret = TRUE;
+ goto out;
}
out:
diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c
index 4aa382b..a89fe32 100644
--- a/src/udiskslinuxdrive.c
+++ b/src/udiskslinuxdrive.c
@@ -453,6 +453,7 @@ udisks_linux_drive_update (UDisksLinuxDrive *drive,
UDisksDaemon *daemon;
UDisksLinuxProvider *provider;
gboolean coldplug = FALSE;
+ const gchar *seat;
device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
if (device == NULL)
@@ -622,7 +623,11 @@ udisks_linux_drive_update (UDisksLinuxDrive *drive,
removable_hint = TRUE;
udisks_drive_set_removable (iface, removable_hint);
- udisks_drive_set_seat (iface, g_udev_device_get_property (device, "ID_SEAT"));
+ seat = g_udev_device_get_property (device, "ID_SEAT");
+ /* assume seat0 if not set */
+ if (seat == NULL || strlen (seat) == 0)
+ seat = "seat0";
+ udisks_drive_set_seat (iface, seat);
set_media_time_detected (drive, device, is_pc_floppy_drive, coldplug);
diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c
index 159d6e6..454026c 100644
--- a/src/udiskslinuxfilesystem.c
+++ b/src/udiskslinuxfilesystem.c
@@ -64,6 +64,7 @@ typedef struct _UDisksLinuxFilesystemClass UDisksLinuxFilesystemClass;
struct _UDisksLinuxFilesystem
{
UDisksFilesystemSkeleton parent_instance;
+ GMutex lock;
};
struct _UDisksLinuxFilesystemClass
@@ -79,8 +80,20 @@ G_DEFINE_TYPE_WITH_CODE (UDisksLinuxFilesystem, udisks_linux_filesystem, UDISKS_
/* ---------------------------------------------------------------------------------------------------- */
static void
+udisks_linux_filesystem_finalize (GObject *object)
+{
+ UDisksLinuxFilesystem *filesystem = UDISKS_LINUX_FILESYSTEM (object);
+
+ g_mutex_clear (&(filesystem->lock));
+
+ if (G_OBJECT_CLASS (udisks_linux_filesystem_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (udisks_linux_filesystem_parent_class)->finalize (object);
+}
+
+static void
udisks_linux_filesystem_init (UDisksLinuxFilesystem *filesystem)
{
+ g_mutex_init (&filesystem->lock);
g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (filesystem),
G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
}
@@ -88,6 +101,10 @@ udisks_linux_filesystem_init (UDisksLinuxFilesystem *filesystem)
static void
udisks_linux_filesystem_class_init (UDisksLinuxFilesystemClass *klass)
{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = udisks_linux_filesystem_finalize;
}
/**
@@ -249,6 +266,7 @@ is_allowed_filesystem (const gchar *fstype)
typedef struct
{
const gchar *fstype;
+ const gchar * const *defaults_shared;
const gchar * const *defaults;
const gchar * const *allow;
const gchar * const *allow_uid_self;
@@ -257,6 +275,7 @@ typedef struct
/* ---------------------- vfat -------------------- */
+static const gchar *vfat_defaults_shared[] = { "shortname=mixed", "dmask=0000", "utf8=1", "showexec", NULL };
static const gchar *vfat_defaults[] = { "uid=", "gid=", "shortname=mixed", "dmask=0077", "utf8=1", "showexec", NULL };
static const gchar *vfat_allow[] = { "flush", "utf8=", "shortname=", "umask=", "dmask=", "fmask=", "codepage=", "iocharset=", "usefree", "showexec", NULL };
static const gchar *vfat_allow_uid_self[] = { "uid=", NULL };
@@ -265,6 +284,7 @@ static const gchar *vfat_allow_gid_self[] = { "gid=", NULL };
/* ---------------------- ntfs -------------------- */
/* this is assuming that ntfs-3g is used */
+static const gchar *ntfs_defaults_shared[] = { "dmask=0000", "fmask=0111", NULL };
static const gchar *ntfs_defaults[] = { "uid=", "gid=", "dmask=0077", "fmask=0177", NULL };
static const gchar *ntfs_allow[] = { "umask=", "dmask=", "fmask=", "locale=", "norecover", "ignore_case", "windows_names", "compression", "nocompression", NULL };
static const gchar *ntfs_allow_uid_self[] = { "uid=", NULL };
@@ -272,6 +292,7 @@ static const gchar *ntfs_allow_gid_self[] = { "gid=", NULL };
/* ---------------------- iso9660 -------------------- */
+static const gchar *iso9660_defaults_shared[] = { "iocharset=utf8", "mode=0444", "dmode=0555", NULL };
static const gchar *iso9660_defaults[] = { "uid=", "gid=", "iocharset=utf8", "mode=0400", "dmode=0500", NULL };
static const gchar *iso9660_allow[] = { "norock", "nojoliet", "iocharset=", "mode=", "dmode=", NULL };
static const gchar *iso9660_allow_uid_self[] = { "uid=", NULL };
@@ -279,6 +300,7 @@ static const gchar *iso9660_allow_gid_self[] = { "gid=", NULL };
/* ---------------------- udf -------------------- */
+static const gchar *udf_defaults_shared[] = { "iocharset=utf8", "umask=0000", NULL };
static const gchar *udf_defaults[] = { "uid=", "gid=", "iocharset=utf8", "umask=0077", NULL };
static const gchar *udf_allow[] = { "iocharset=", "umask=", NULL };
static const gchar *udf_allow_uid_self[] = { "uid=", NULL };
@@ -291,10 +313,10 @@ static const gchar *any_allow[] = { "exec", "noexec", "nodev", "nosuid", "atime"
static const FSMountOptions fs_mount_options[] =
{
- { "vfat", vfat_defaults, vfat_allow, vfat_allow_uid_self, vfat_allow_gid_self },
- { "ntfs", ntfs_defaults, ntfs_allow, ntfs_allow_uid_self, ntfs_allow_gid_self },
- { "iso9660", iso9660_defaults, iso9660_allow, iso9660_allow_uid_self, iso9660_allow_gid_self },
- { "udf", udf_defaults, udf_allow, udf_allow_uid_self, udf_allow_gid_self },
+ { "vfat", vfat_defaults_shared, vfat_defaults, vfat_allow, vfat_allow_uid_self, vfat_allow_gid_self },
+ { "ntfs", ntfs_defaults, ntfs_defaults_shared, ntfs_allow, ntfs_allow_uid_self, ntfs_allow_gid_self },
+ { "iso9660", iso9660_defaults_shared, iso9660_defaults, iso9660_allow, iso9660_allow_uid_self, iso9660_allow_gid_self },
+ { "udf", udf_defaults_shared, udf_defaults, udf_allow, udf_allow_uid_self, udf_allow_gid_self },
};
/* ------------------------------------------------ */
@@ -495,8 +517,9 @@ is_mount_option_allowed (const FSMountOptions *fsmo,
static gchar **
prepend_default_mount_options (const FSMountOptions *fsmo,
- uid_t caller_uid,
- GVariant *given_options)
+ uid_t caller_uid,
+ gboolean shared,
+ GVariant *given_options)
{
GPtrArray *options;
gint n;
@@ -507,9 +530,16 @@ prepend_default_mount_options (const FSMountOptions *fsmo,
options = g_ptr_array_new ();
if (fsmo != NULL)
{
- for (n = 0; fsmo->defaults != NULL && fsmo->defaults[n] != NULL; n++)
+ const gchar *const *defaults;
+
+ /* the defaults depend on whether the device is shared */
+ defaults = fsmo->defaults;
+ if (shared)
+ defaults = fsmo->defaults_shared;
+
+ for (n = 0; defaults != NULL && defaults[n] != NULL; n++)
{
- const gchar *option = fsmo->defaults[n];
+ const gchar *option = defaults[n];
if (strcmp (option, "uid=") == 0)
{
@@ -576,6 +606,36 @@ subst_str_and_escape (const gchar *str,
/* ---------------------------------------------------------------------------------------------------- */
+static gboolean
+shared_between_seats (UDisksDaemon *daemon,
+ UDisksBlock *block)
+{
+ gboolean ret = FALSE;
+ UDisksObject *drive_object = NULL;
+ UDisksDrive *drive = NULL;
+
+ drive_object = udisks_daemon_find_object (daemon, udisks_block_get_drive (block));
+ if (drive_object == NULL)
+ goto out;
+
+ drive = udisks_object_get_drive (UDISKS_OBJECT (drive_object));
+ if (drive == NULL)
+ goto out;
+
+ if (g_strcmp0 (udisks_drive_get_seat (drive), "all") == 0)
+ {
+ ret = TRUE;
+ goto out;
+ }
+
+ out:
+ g_clear_object (&drive_object);
+ g_clear_object (&drive);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
/*
* calculate_fs_type: <internal>
* @block: A #UDisksBlock.
@@ -655,6 +715,7 @@ calculate_fs_type (UDisksBlock *block,
/*
* calculate_mount_options: <internal>
+ * @daemon: A #UDisksDaemon.
* @block: A #UDisksBlock.
* @caller_uid: The uid of the caller making the request.
* @fs_type: The filesystem type to use or %NULL.
@@ -667,7 +728,8 @@ calculate_fs_type (UDisksBlock *block,
* Returns: A string with mount options or %NULL if @error is set. Free with g_free().
*/
static gchar *
-calculate_mount_options (UDisksBlock *block,
+calculate_mount_options (UDisksDaemon *daemon,
+ UDisksBlock *block,
uid_t caller_uid,
const gchar *fs_type,
GVariant *options,
@@ -676,6 +738,7 @@ calculate_mount_options (UDisksBlock *block,
const FSMountOptions *fsmo;
gchar **options_to_use;
gchar *options_to_use_str;
+ gboolean shared;
GString *str;
guint n;
@@ -684,10 +747,12 @@ calculate_mount_options (UDisksBlock *block,
fsmo = find_mount_options_for_fs (fs_type);
+ shared = shared_between_seats (daemon, block);
+
/* always prepend some reasonable default mount options; these are
* chosen here; the user can override them if he wants to
*/
- options_to_use = prepend_default_mount_options (fsmo, caller_uid, options);
+ options_to_use = prepend_default_mount_options (fsmo, caller_uid, shared, options);
/* validate mount options */
str = g_string_new ("uhelper=udisks2,nodev,nosuid");
@@ -798,6 +863,7 @@ add_acl (const gchar *path,
/*
* calculate_mount_point: <internal>
+ * @dameon: A #UDisksDaemon.
* @block: A #UDisksBlock.
* @uid: user id of the calling user
* @gid: group id of the calling user
@@ -810,7 +876,8 @@ add_acl (const gchar *path,
* Returns: A UTF-8 string with the mount point to use or %NULL if @error is set. Free with g_free().
*/
static gchar *
-calculate_mount_point (UDisksBlock *block,
+calculate_mount_point (UDisksDaemon *daemon,
+ UDisksBlock *block,
uid_t uid,
gid_t gid,
const gchar *user_name,
@@ -835,8 +902,10 @@ calculate_mount_point (UDisksBlock *block,
uuid = udisks_block_get_id_uuid (block);
}
- /* If we know the user-name and it doesn't have any '/' character in it, mount in /run/media/$USER */
- if (user_name != NULL && strstr (user_name, "/") == NULL)
+ /* If the device is not shared between seats, we know the user-name and it
+ * doesn't have any '/' character in it, mount in /run/media/$USER
+ */
+ if (!shared_between_seats (daemon, block) && user_name != NULL && strstr (user_name, "/") == NULL)
{
mount_dir = g_strdup_printf ("/run/media/%s", user_name);
if (!g_file_test (mount_dir, G_FILE_TEST_EXISTS))
@@ -1110,6 +1179,9 @@ handle_mount (UDisksFilesystem *filesystem,
caller_user_name = NULL;
system_managed = FALSE;
+ /* only allow a single call at a time */
+ g_mutex_lock (&UDISKS_LINUX_FILESYSTEM (filesystem)->lock);
+
error = NULL;
object = udisks_daemon_util_dup_object (filesystem, &error);
if (object == NULL)
@@ -1312,7 +1384,8 @@ handle_mount (UDisksFilesystem *filesystem,
/* calculate mount options (guaranteed to be valid UTF-8) */
error = NULL;
- mount_options_to_use = calculate_mount_options (block,
+ mount_options_to_use = calculate_mount_options (daemon,
+ block,
caller_uid,
fs_type_to_use,
options,
@@ -1352,7 +1425,8 @@ handle_mount (UDisksFilesystem *filesystem,
/* calculate mount point (guaranteed to be valid UTF-8) */
error = NULL;
- mount_point_to_use = calculate_mount_point (block,
+ mount_point_to_use = calculate_mount_point (daemon,
+ block,
caller_uid,
caller_gid,
caller_user_name,
@@ -1436,6 +1510,9 @@ handle_mount (UDisksFilesystem *filesystem,
g_free (caller_user_name);
g_clear_object (&object);
+ /* only allow a single call at a time */
+ g_mutex_unlock (&UDISKS_LINUX_FILESYSTEM (filesystem)->lock);
+
return TRUE; /* returning TRUE means that we handled the method invocation */
}
@@ -1482,6 +1559,9 @@ handle_unmount (UDisksFilesystem *filesystem,
error_message = NULL;
opt_force = FALSE;
+ /* only allow a single call at a time */
+ g_mutex_lock (&UDISKS_LINUX_FILESYSTEM (filesystem)->lock);
+
error = NULL;
object = udisks_daemon_util_dup_object (filesystem, &error);
if (object == NULL)
@@ -1599,11 +1679,23 @@ handle_unmount (UDisksFilesystem *filesystem,
if (caller_uid != 0 && (caller_uid != mounted_by_uid))
{
+ const gchar *action_id;
+ const gchar *message;
+
+ action_id = "org.freedesktop.udisks2.filesystem-unmount-others";
+ message = N_("Authentication is required to unmount $(udisks2.device) mounted by another user");
+ /* if the device is shared, use another action that defaults to 'yes' */
+ if (shared_between_seats (daemon, block))
+ {
+ action_id = "org.freedesktop.udisks2.filesystem-unmount-others-shared";
+ message = N_("Authentication is required to unmount $(udisks2.device) mounted by another user");
+ }
+
if (!udisks_daemon_util_check_authorization_sync (daemon,
object,
- "org.freedesktop.udisks2.filesystem-unmount-others",
+ action_id,
options,
- N_("Authentication is required to unmount $(udisks2.device) mounted by another user"),
+ message,
invocation))
goto out;
}
@@ -1668,6 +1760,9 @@ handle_unmount (UDisksFilesystem *filesystem,
g_free (mount_point);
g_free (fstab_mount_options);
g_clear_object (&object);
+
+ g_mutex_unlock (&UDISKS_LINUX_FILESYSTEM (filesystem)->lock);
+
return TRUE;
}