diff --git a/data/80-udisks.rules b/data/80-udisks.rules index d1351f3..057d5df 100644 --- a/data/80-udisks.rules +++ b/data/80-udisks.rules @@ -223,5 +223,21 @@ ENV{ID_VENDOR}=="Sony", ENV{ID_MODEL}=="PRS*Launcher", ENV{UDISKS_PRESENTATION_H ############################################################################################################## +# Additional mount options passed to udisks-daemon to allow sysamins to restrict mount to read-only or "noexec" +# for example: +# +# ENV{UDISKS_MOUNT_OPTIONS}="ro,noexec" +# ENV{UDISKS_MOUNT_OPTIONS_ALLOW}="exec,noexec,nodev,nosuid,atime,noatime,nodiratime,ro,rw,sync,dirsync" +# +# use specific charset for FAT filesystems +# +# ENV{ID_FS_TYPE}=="vfat", +# ENV{UDISKS_MOUNT_OPTIONS}="utf8=0,iocharset=iso8859-15" +# +# mount all USB devices RO +# +# SUBSYSTEMS="usb", ENV{ID_FS_USAGE}=="filesystem", +# ENV{UDISKS_MOUNT_OPTIONS}="ro" + LABEL="udisks_end" diff --git a/doc/man/udisks7.xml b/doc/man/udisks7.xml index c5d0a55..e758d9f 100644 --- a/doc/man/udisks7.xml +++ b/doc/man/udisks7.xml @@ -74,6 +74,22 @@ icon theme specification. + + + + Additional mount options to be appended to the existing + mount options. Format is a comma separated list of options to pass to + mount. + + + + + + If set, this restricts the options allowed in mount. + Format is a comma separated list of possible options allowed to be + passed to mount (e.g. "exec,noexec,nodev,nosuid,atime,noatime,nodiratime,ro,rw,sync,dirsync") + + The properties are used to describe what diff --git a/src/device-private.c b/src/device-private.c index 22a0d35..9197fd8 100644 --- a/src/device-private.c +++ b/src/device-private.c @@ -552,6 +552,30 @@ device_set_device_presentation_icon_name (Device *device, } void +device_set_device_mount_options (Device *device, + const gchar *value) +{ + if (G_UNLIKELY (g_strcmp0 (device->priv->device_mount_options, value) != 0)) + { + g_free (device->priv->device_mount_options); + device->priv->device_mount_options = g_strdup (value); + emit_changed (device, "device_mount_options"); + } +} + +void +device_set_device_mount_options_allow (Device *device, + const gchar *value) +{ + if (G_UNLIKELY (g_strcmp0 (device->priv->device_mount_options_allow, value) != 0)) + { + g_free (device->priv->device_mount_options_allow); + device->priv->device_mount_options_allow = g_strdup (value); + emit_changed (device, "device_mount_options_allow"); + } +} + +void device_set_device_mounted_by_uid (Device *device, guint value) { diff --git a/src/device-private.h b/src/device-private.h index a6db7f2..f4b1fb3 100644 --- a/src/device-private.h +++ b/src/device-private.h @@ -130,6 +130,8 @@ struct DevicePrivate gboolean device_presentation_nopolicy; char *device_presentation_name; char *device_presentation_icon_name; + char *device_mount_options; + char *device_mount_options_allow; char *id_usage; char *id_type; @@ -286,6 +288,8 @@ void device_set_device_presentation_hide (Device *device, gboolean value); void device_set_device_presentation_nopolicy (Device *device, gboolean value); void device_set_device_presentation_name (Device *device, const gchar *value); void device_set_device_presentation_icon_name (Device *device, const gchar *value); +void device_set_device_mount_options (Device *device, const gchar *value); +void device_set_device_mount_options_allow (Device *device, const gchar *value); void device_set_id_usage (Device *device, const gchar *value); void device_set_id_type (Device *device, const gchar *value); diff --git a/src/device.c b/src/device.c index c4a83ff..b57f4d2 100644 --- a/src/device.c +++ b/src/device.c @@ -214,7 +214,9 @@ enum PROP_DEVICE_PRESENTATION_NOPOLICY, PROP_DEVICE_PRESENTATION_NAME, PROP_DEVICE_PRESENTATION_ICON_NAME, - + PROP_DEVICE_MOUNT_OPTIONS, + PROP_DEVICE_MOUNT_OPTIONS_ALLOW, + PROP_JOB_IN_PROGRESS, PROP_JOB_ID, PROP_JOB_INITIATED_BY_UID, @@ -485,6 +487,12 @@ get_property (GObject *object, case PROP_DEVICE_PRESENTATION_ICON_NAME: g_value_set_string (value, device->priv->device_presentation_icon_name); break; + case PROP_DEVICE_MOUNT_OPTIONS: + g_value_set_string (value, device->priv->device_mount_options); + break; + case PROP_DEVICE_MOUNT_OPTIONS_ALLOW: + g_value_set_string (value, device->priv->device_mount_options_allow); + break; case PROP_JOB_IN_PROGRESS: g_value_set_boolean (value, device->priv->job_in_progress); @@ -1117,6 +1125,20 @@ device_class_init (DeviceClass *klass) NULL, NULL, G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_DEVICE_MOUNT_OPTIONS, + g_param_spec_string ("device-mount-options", + NULL, + NULL, + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_DEVICE_MOUNT_OPTIONS_ALLOW, + g_param_spec_string ("device-mount-options-allow", + NULL, + NULL, + NULL, + G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_JOB_IN_PROGRESS, g_param_spec_boolean ("job-in-progress", NULL, @@ -1796,7 +1818,9 @@ device_finalize (GObject *object) g_ptr_array_free (device->priv->device_mount_paths, TRUE); g_free (device->priv->device_presentation_name); g_free (device->priv->device_presentation_icon_name); - + g_free (device->priv->device_mount_options); + g_free (device->priv->device_mount_options_allow); + g_free (device->priv->id_usage); g_free (device->priv->id_type); g_free (device->priv->id_version); @@ -2277,6 +2301,16 @@ diff_sorted_lists (GList *list1, /* ---------------------------------------------------------------------------------------------------- */ +/* update udisks_mount_options* properties */ +static gboolean +update_mount_options (Device *device) +{ + device_set_device_mount_options (device, g_udev_device_get_property (device->priv->d, "UDISKS_MOUNT_OPTIONS")); + device_set_device_mount_options_allow (device, g_udev_device_get_property (device->priv->d, "UDISKS_MOUNT_OPTIONS_ALLOW")); + + return TRUE; +} + /* update id_* properties */ static gboolean update_info_presentation (Device *device) @@ -4642,6 +4676,10 @@ update_info (Device *device) if (!update_info_presentation (device)) goto out; + /* device_mount_options property */ + if (!update_mount_options (device)) + goto out; + /* id_* properties */ if (!update_info_id (device)) goto out; @@ -5981,6 +6019,7 @@ is_uid_in_gid (uid_t uid, static gboolean is_mount_option_allowed (const FSMountOptions *fsmo, const char *option, + const char *options_allowed, uid_t caller_uid) { int n; @@ -5993,53 +6032,91 @@ is_mount_option_allowed (const FSMountOptions *fsmo, allowed = FALSE; - /* first run through the allowed mount options */ - if (fsmo != NULL) - { - for (n = 0; fsmo->allow != NULL && fsmo->allow[n] != NULL; n++) + /* If set, check the allowed mount options as set in udev */ + if (options_allowed != NULL && strlen (options_allowed) > 0) + { + gchar ** mount_options_allowed; + + mount_options_allowed = g_strsplit (options_allowed, ",", 0); + for (n = 0; mount_options_allowed != NULL && mount_options_allowed[n] != NULL; n++) { - ep = strstr (fsmo->allow[n], "="); + ep = strstr (mount_options_allowed[n], "="); if (ep != NULL && ep[1] == '\0') { - ep_len = ep - fsmo->allow[n] + 1; - if (strncmp (fsmo->allow[n], option, ep_len) == 0) + ep_len = ep - mount_options_allowed[n] + 1; + if (strncmp (mount_options_allowed[n], option, ep_len) == 0) { allowed = TRUE; + g_strfreev (mount_options_allowed); goto out; } } else { - if (strcmp (fsmo->allow[n], option) == 0) + if (strcmp (mount_options_allowed[n], option) == 0) { allowed = TRUE; + g_strfreev (mount_options_allowed); goto out; } } } + /* + * If set via udev, it takes precedence over all other possible allowed + * options (complete lockdown), so no need to check for others, if not + * found there, then it's not allowed, period. + */ + g_strfreev (mount_options_allowed); + goto out; } - for (n = 0; any_allow[n] != NULL; n++) + + /* then run through the allowed mount options */ + if (fsmo != NULL) { - ep = strstr (any_allow[n], "="); - if (ep != NULL && ep[1] == '\0') + for (n = 0; fsmo->allow != NULL && fsmo->allow[n] != NULL; n++) { - ep_len = ep - any_allow[n] + 1; - if (strncmp (any_allow[n], option, ep_len) == 0) + ep = strstr (fsmo->allow[n], "="); + if (ep != NULL && ep[1] == '\0') { - allowed = TRUE; - goto out; + ep_len = ep - fsmo->allow[n] + 1; + if (strncmp (fsmo->allow[n], option, ep_len) == 0) + { + allowed = TRUE; + goto out; + } } - } - else - { - if (strcmp (any_allow[n], option) == 0) + else { - allowed = TRUE; - goto out; + if (strcmp (fsmo->allow[n], option) == 0) + { + allowed = TRUE; + goto out; + } } } } + for (n = 0; any_allow[n] != NULL; n++) + { + ep = strstr (any_allow[n], "="); + if (ep != NULL && ep[1] == '\0') + { + ep_len = ep - any_allow[n] + 1; + if (strncmp (any_allow[n], option, ep_len) == 0) + { + allowed = TRUE; + goto out; + } + } + else + { + if (strcmp (any_allow[n], option) == 0) + { + allowed = TRUE; + goto out; + } + } + } /* .. then check for mount options where the caller is allowed to pass * in his own uid */ @@ -6308,6 +6385,11 @@ device_filesystem_mount_authorized_cb (Daemon *daemon, /* validate mount options and check for authorizations */ s = g_string_new ("uhelper=udisks,nodev,nosuid"); + if (device->priv->device_mount_options != NULL && strlen (device->priv->device_mount_options) > 0) + { + g_string_append_printf (s, ",%s", device->priv->device_mount_options); + } + for (n = 0; options[n] != NULL; n++) { const char *option = options[n]; @@ -6321,7 +6403,7 @@ device_filesystem_mount_authorized_cb (Daemon *daemon, } /* first check if the mount option is allowed */ - if (!is_mount_option_allowed (fsmo, option, caller_uid)) + if (!is_mount_option_allowed (fsmo, option, device->priv->device_mount_options_allow, caller_uid)) { throw_error (context, ERROR_INVALID_OPTION, "Mount option %s is not allowed", option); g_string_free (s, TRUE);