summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2011-08-12 12:40:17 -0400
committerDavid Zeuthen <davidz@redhat.com>2011-08-12 12:40:17 -0400
commit8d432a303d277b4a7b469a9fc4b822be6b6d2778 (patch)
tree42a6115f910c0ce2d9bfd1cf4e53436f879df991
parent2f7455e32bb90dc31bbeaaa01e64a9767c2a16ae (diff)
Allow mounting/unmounting fstab devices without the 'user' or 'users' option
... by introducing a new org.freedesktop.udisks2.filesystem-nonuser-fstab polkit action. http://people.freedesktop.org/~david/palimpsest-nonuser-fstab-devices.png Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r--data/org.freedesktop.UDisks2.xml16
-rw-r--r--policy/org.freedesktop.udisks2.policy.in10
-rw-r--r--src/tests/test.c30
-rw-r--r--src/udiskscleanup.c18
-rw-r--r--src/udisksdaemon.c53
-rw-r--r--src/udisksdaemon.h11
-rw-r--r--src/udiskslinuxdrive.c6
-rw-r--r--src/udiskslinuxencrypted.c12
-rw-r--r--src/udiskslinuxfilesystem.c74
-rw-r--r--src/udiskslinuxloop.c6
-rw-r--r--src/udiskslinuxswapspace.c6
-rw-r--r--src/udisksspawnedjob.c75
-rw-r--r--src/udisksspawnedjob.h3
13 files changed, 240 insertions, 80 deletions
diff --git a/data/org.freedesktop.UDisks2.xml b/data/org.freedesktop.UDisks2.xml
index 4a5b21c..012791a 100644
--- a/data/org.freedesktop.UDisks2.xml
+++ b/data/org.freedesktop.UDisks2.xml
@@ -674,8 +674,14 @@
file)
then the
<citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- command is called directly as the calling user and no clean-up
- is performed when the device is removed. Additionally, the
+ command is called directly as the calling user.
+ If the calling user does not have sufficient permissions to
+ mount the device (it could be the <literal>user</literal> or
+ <literal>users</literal> option isn't specificed), then
+ additional authorization is requested and, if obtained, the
+ <citerefentry><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ command is invoked as root.
+ Additionally, the
given <parameter>options</parameter> and
<parameter>fstype</parameter> options are not used as they are
instead read from the system-wide configuration file in
@@ -702,6 +708,12 @@
then the
<citerefentry><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
command is called directly as the calling user.
+ If the calling user does not have sufficient permissions to
+ unmount the device (it could be the <literal>user</literal> or
+ <literal>users</literal> option isn't specificed), then
+ additional authorization is requested and, if obtained, the
+ <citerefentry><refentrytitle>umount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ command is invoked as root.
-->
<method name="Unmount">
<arg name="options" direction="in" type="a{sv}"/>
diff --git a/policy/org.freedesktop.udisks2.policy.in b/policy/org.freedesktop.udisks2.policy.in
index 8e61608..a27b6b2 100644
--- a/policy/org.freedesktop.udisks2.policy.in
+++ b/policy/org.freedesktop.udisks2.policy.in
@@ -30,6 +30,16 @@
</defaults>
</action>
+ <action id="org.freedesktop.udisks2.filesystem-nonuser-fstab">
+ <_description>Mount/unmount non-user filesystems defined in the fstab file</_description>
+ <_message>Authentication is required to mount/unmount the filesystem</_message>
+ <defaults>
+ <allow_any>auth_admin</allow_any>
+ <allow_inactive>auth_admin</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
+ </defaults>
+ </action>
+
<action id="org.freedesktop.udisks2.filesystem-unmount-others">
<_description>Unmount a device mounted by another user</_description>
<_message>Authentication is required to unmount a filesystem mounted by another user</_message>
diff --git a/src/tests/test.c b/src/tests/test.c
index 0964e12..1855deb 100644
--- a/src/tests/test.c
+++ b/src/tests/test.c
@@ -69,7 +69,7 @@ test_spawned_job_successful (void)
{
UDisksSpawnedJob *job;
- job = udisks_spawned_job_new ("/bin/true", NULL, getuid (), NULL);
+ job = udisks_spawned_job_new ("/bin/true", NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "completed", G_CALLBACK (on_completed_expect_success), NULL);
g_object_unref (job);
}
@@ -81,7 +81,7 @@ test_spawned_job_failure (void)
{
UDisksSpawnedJob *job;
- job = udisks_spawned_job_new ("/bin/false", NULL, getuid (), NULL);
+ job = udisks_spawned_job_new ("/bin/false", NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "completed", G_CALLBACK (on_completed_expect_failure),
"Command-line `/bin/false' exited with non-zero exit status 1: ");
g_object_unref (job);
@@ -94,7 +94,7 @@ test_spawned_job_missing_program (void)
{
UDisksSpawnedJob *job;
- job = udisks_spawned_job_new ("/path/to/unknown/file", NULL, getuid (), NULL);
+ job = udisks_spawned_job_new ("/path/to/unknown/file", NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "completed", G_CALLBACK (on_completed_expect_failure),
"Error spawning command-line `/path/to/unknown/file': Failed to execute child process \"/path/to/unknown/file\" (No such file or directory) (g-exec-error-quark, 8)");
g_object_unref (job);
@@ -110,7 +110,7 @@ test_spawned_job_cancelled_at_start (void)
cancellable = g_cancellable_new ();
g_cancellable_cancel (cancellable);
- job = udisks_spawned_job_new ("/bin/true", NULL, getuid (), cancellable);
+ job = udisks_spawned_job_new ("/bin/true", NULL, getuid (), geteuid (), cancellable);
_g_assert_signal_received (job, "completed", G_CALLBACK (on_completed_expect_failure),
"Operation was cancelled (g-io-error-quark, 19)");
g_object_unref (job);
@@ -135,7 +135,7 @@ test_spawned_job_cancelled_midway (void)
GCancellable *cancellable;
cancellable = g_cancellable_new ();
- job = udisks_spawned_job_new ("/bin/sleep 0.5", NULL, getuid (), cancellable);
+ job = udisks_spawned_job_new ("/bin/sleep 0.5", NULL, getuid (), geteuid (), cancellable);
g_timeout_add (10, on_timeout, cancellable); /* 10 msec */
g_main_loop_run (loop);
_g_assert_signal_received (job, "completed", G_CALLBACK (on_completed_expect_failure),
@@ -167,7 +167,7 @@ test_spawned_job_override_signal_handler (void)
UDisksSpawnedJob *job;
gboolean handler_ran;
- job = udisks_spawned_job_new ("/path/to/unknown/file", NULL, getuid (), NULL /* GCancellable */);
+ job = udisks_spawned_job_new ("/path/to/unknown/file", NULL, getuid (), geteuid (), NULL /* GCancellable */);
handler_ran = FALSE;
g_signal_connect (job, "spawned-job-completed", G_CALLBACK (on_spawned_job_completed), &handler_ran);
_g_assert_signal_received (job, "completed", G_CALLBACK (on_completed_expect_failure),
@@ -183,7 +183,7 @@ test_spawned_job_premature_termination (void)
{
UDisksSpawnedJob *job;
- job = udisks_spawned_job_new ("/bin/sleep 1000", NULL, getuid (), NULL /* GCancellable */);
+ job = udisks_spawned_job_new ("/bin/sleep 1000", NULL, getuid (), geteuid (), NULL /* GCancellable */);
g_object_unref (job);
}
@@ -214,7 +214,7 @@ test_spawned_job_read_stdout (void)
gchar *s;
s = g_strdup_printf (UDISKS_TEST_DIR "/udisks-test-helper 0");
- job = udisks_spawned_job_new (s, NULL, getuid (), NULL);
+ job = udisks_spawned_job_new (s, NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "spawned-job-completed", G_CALLBACK (read_stdout_on_spawned_job_completed), NULL);
g_object_unref (job);
g_free (s);
@@ -247,7 +247,7 @@ test_spawned_job_read_stderr (void)
gchar *s;
s = g_strdup_printf (UDISKS_TEST_DIR "/udisks-test-helper 1");
- job = udisks_spawned_job_new (s, NULL, getuid (), NULL);
+ job = udisks_spawned_job_new (s, NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "spawned-job-completed", G_CALLBACK (read_stderr_on_spawned_job_completed), NULL);
g_object_unref (job);
g_free (s);
@@ -278,14 +278,14 @@ test_spawned_job_exit_status (void)
gchar *s;
s = g_strdup_printf (UDISKS_TEST_DIR "/udisks-test-helper 2");
- job = udisks_spawned_job_new (s, NULL, getuid (), NULL);
+ job = udisks_spawned_job_new (s, NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "spawned-job-completed", G_CALLBACK (exit_status_on_spawned_job_completed),
GINT_TO_POINTER (1));
g_object_unref (job);
g_free (s);
s = g_strdup_printf (UDISKS_TEST_DIR "/udisks-test-helper 3");
- job = udisks_spawned_job_new (s, NULL, getuid (), NULL);
+ job = udisks_spawned_job_new (s, NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "spawned-job-completed", G_CALLBACK (exit_status_on_spawned_job_completed),
GINT_TO_POINTER (2));
g_object_unref (job);
@@ -301,7 +301,7 @@ test_spawned_job_abnormal_termination (void)
gchar *s;
s = g_strdup_printf (UDISKS_TEST_DIR "/udisks-test-helper 4");
- job = udisks_spawned_job_new (s, NULL, getuid (), NULL);
+ job = udisks_spawned_job_new (s, NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "completed", G_CALLBACK (on_completed_expect_failure),
"Command-line `./udisks-test-helper 4' was signaled with signal SIGSEGV (11): "
"OK, deliberately causing a segfault\n");
@@ -309,7 +309,7 @@ test_spawned_job_abnormal_termination (void)
g_free (s);
s = g_strdup_printf (UDISKS_TEST_DIR "/udisks-test-helper 5");
- job = udisks_spawned_job_new (s, NULL, getuid (), NULL);
+ job = udisks_spawned_job_new (s, NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "completed", G_CALLBACK (on_completed_expect_failure),
"Command-line `./udisks-test-helper 5' was signaled with signal SIGABRT (6): "
"OK, deliberately abort()'ing\n");
@@ -350,7 +350,7 @@ test_spawned_job_binary_output (void)
gchar *s;
s = g_strdup_printf (UDISKS_TEST_DIR "/udisks-test-helper 6");
- job = udisks_spawned_job_new (s, NULL, getuid (), NULL);
+ job = udisks_spawned_job_new (s, NULL, getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "spawned-job-completed", G_CALLBACK (binary_output_on_spawned_job_completed), NULL);
g_object_unref (job);
g_free (s);
@@ -381,7 +381,7 @@ test_spawned_job_input_string (void)
gchar *s;
s = g_strdup_printf (UDISKS_TEST_DIR "/udisks-test-helper 7");
- job = udisks_spawned_job_new (s, "foobar", getuid (), NULL);
+ job = udisks_spawned_job_new (s, "foobar", getuid (), geteuid (), NULL);
_g_assert_signal_received (job, "spawned-job-completed", G_CALLBACK (input_string_on_spawned_job_completed), NULL);
g_object_unref (job);
g_free (s);
diff --git a/src/udiskscleanup.c b/src/udiskscleanup.c
index dccb057..6084340 100644
--- a/src/udiskscleanup.c
+++ b/src/udiskscleanup.c
@@ -621,8 +621,10 @@ udisks_cleanup_check_mounted_fs_entry (UDisksCleanup *cleanup,
escaped_mount_point = g_strescape (mount_point, NULL);
/* right now -l is the only way to "force unmount" file systems... */
if (!udisks_daemon_launch_spawned_job_sync (cleanup->daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"umount -l \"%s\"",
@@ -1290,8 +1292,10 @@ udisks_cleanup_check_unlocked_luks_entry (UDisksCleanup *cleanup,
error_message = NULL;
escaped_device_file = g_strescape (device_file_cleartext, NULL);
if (!udisks_daemon_launch_spawned_job_sync (cleanup->daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"cryptsetup luksClose \"%s\"",
@@ -1959,8 +1963,10 @@ udisks_cleanup_check_loop_entry (UDisksCleanup *cleanup,
error_message = NULL;
escaped_loop_device_file = g_strescape (loop_device, NULL);
if (!udisks_daemon_launch_spawned_job_sync (cleanup->daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"losetup -d \"%s\"",
diff --git a/src/udisksdaemon.c b/src/udisksdaemon.c
index 4532746..47c48c2 100644
--- a/src/udisksdaemon.c
+++ b/src/udisksdaemon.c
@@ -598,7 +598,8 @@ udisks_daemon_launch_threaded_job (UDisksDaemon *daemon,
* udisks_daemon_launch_spawned_job:
* @daemon: A #UDisksDaemon.
* @cancellable: A #GCancellable or %NULL.
- * @run_as: The #uid_t to run the command as.
+ * @run_as_uid: The #uid_t to run the command as.
+ * @run_as_euid: The effective #uid_t to run the command as.
* @input_string: A string to write to stdin of the spawned program or %NULL.
* @command_line_format: printf()-style format for the command line to spawn.
* @...: Arguments for @command_line_format.
@@ -618,7 +619,8 @@ udisks_daemon_launch_threaded_job (UDisksDaemon *daemon,
UDisksBaseJob *
udisks_daemon_launch_spawned_job (UDisksDaemon *daemon,
GCancellable *cancellable,
- uid_t run_as,
+ uid_t run_as_uid,
+ uid_t run_as_euid,
const gchar *input_string,
const gchar *command_line_format,
...)
@@ -636,7 +638,7 @@ udisks_daemon_launch_spawned_job (UDisksDaemon *daemon,
va_start (var_args, command_line_format);
command_line = g_strdup_vprintf (command_line_format, var_args);
va_end (var_args);
- job = udisks_spawned_job_new (command_line, input_string, run_as, cancellable);
+ job = udisks_spawned_job_new (command_line, input_string, run_as_uid, run_as_euid, cancellable);
g_free (command_line);
/* TODO: protect job_id by a mutex */
@@ -661,14 +663,28 @@ typedef struct
GMainContext *context;
GMainLoop *loop;
gboolean success;
+ gint status;
gchar *message;
} SpawnedJobSyncData;
+static gboolean
+spawned_job_sync_on_spawned_job_completed (UDisksSpawnedJob *job,
+ GError *error,
+ gint status,
+ GString *standard_output,
+ GString *standard_error,
+ gpointer user_data)
+{
+ SpawnedJobSyncData *data = user_data;
+ data->status = status;
+ return FALSE; /* let other handlers run */
+}
+
static void
-spawned_job_sync_on_job_completed (UDisksJob *job,
- gboolean success,
- const gchar *message,
- gpointer user_data)
+spawned_job_sync_on_completed (UDisksJob *job,
+ gboolean success,
+ const gchar *message,
+ gpointer user_data)
{
SpawnedJobSyncData *data = user_data;
data->success = success;
@@ -680,8 +696,10 @@ spawned_job_sync_on_job_completed (UDisksJob *job,
* udisks_daemon_launch_spawned_job_sync:
* @daemon: A #UDisksDaemon.
* @cancellable: A #GCancellable or %NULL.
- * @run_as: The #uid_t to run the command as.
+ * @run_as_uid: The #uid_t to run the command as.
+ * @run_as_euid: The effective #uid_t to run the command as.
* @input_string: A string to write to stdin of the spawned program or %NULL.
+ * @out_status: Return location for the @status parameter of the #UDisksSpawnedJob::spawned-job-completed signal.
* @out_message: Return location for the @message parameter of the #UDisksJob::completed signal.
* @command_line_format: printf()-style format for the command line to spawn.
* @...: Arguments for @command_line_format.
@@ -689,12 +707,14 @@ spawned_job_sync_on_job_completed (UDisksJob *job,
* Like udisks_daemon_launch_spawned_job() but blocks the calling
* thread until the job completes.
*
- * Returns: The @success parameter of the #UDisksJob::completed.
+ * Returns: The @success parameter of the #UDisksJob::completed signal.
*/
gboolean
udisks_daemon_launch_spawned_job_sync (UDisksDaemon *daemon,
GCancellable *cancellable,
- uid_t run_as,
+ uid_t run_as_uid,
+ uid_t run_as_euid,
+ gint *out_status,
gchar **out_message,
const gchar *input_string,
const gchar *command_line_format,
@@ -713,6 +733,7 @@ udisks_daemon_launch_spawned_job_sync (UDisksDaemon *daemon,
g_main_context_push_thread_default (data.context);
data.loop = g_main_loop_new (data.context, FALSE);
data.success = FALSE;
+ data.status = 0;
data.message = NULL;
va_start (var_args, command_line_format);
@@ -720,17 +741,25 @@ udisks_daemon_launch_spawned_job_sync (UDisksDaemon *daemon,
va_end (var_args);
job = udisks_daemon_launch_spawned_job (daemon,
cancellable,
- run_as,
+ run_as_uid,
+ run_as_euid,
input_string,
"%s",
command_line);
+ g_signal_connect (job,
+ "spawned-job-completed",
+ G_CALLBACK (spawned_job_sync_on_spawned_job_completed),
+ &data);
g_signal_connect_after (job,
"completed",
- G_CALLBACK (spawned_job_sync_on_job_completed),
+ G_CALLBACK (spawned_job_sync_on_completed),
&data);
g_main_loop_run (data.loop);
+ if (out_status != NULL)
+ *out_status = data.status;
+
if (out_message != NULL)
*out_message = data.message;
else
diff --git a/src/udisksdaemon.h b/src/udisksdaemon.h
index 56bbdaf..80805f1 100644
--- a/src/udisksdaemon.h
+++ b/src/udisksdaemon.h
@@ -72,17 +72,20 @@ UDisksBaseJob *udisks_daemon_launch_simple_job (UDisksDaemon *
GCancellable *cancellable);
UDisksBaseJob *udisks_daemon_launch_spawned_job (UDisksDaemon *daemon,
GCancellable *cancellable,
- uid_t run_as,
+ uid_t run_as_uid,
+ uid_t run_as_euid,
const gchar *input_string,
const gchar *command_line_format,
- ...) G_GNUC_PRINTF (5, 6);
+ ...) G_GNUC_PRINTF (6, 7);
gboolean udisks_daemon_launch_spawned_job_sync (UDisksDaemon *daemon,
GCancellable *cancellable,
- uid_t run_as,
+ uid_t run_as_uid,
+ uid_t run_as_euid,
+ gint *out_status,
gchar **out_message,
const gchar *input_string,
const gchar *command_line_format,
- ...) G_GNUC_PRINTF (6, 7);
+ ...) G_GNUC_PRINTF (8, 9);
UDisksBaseJob *udisks_daemon_launch_threaded_job (UDisksDaemon *daemon,
UDisksThreadedJobFunc job_func,
gpointer user_data,
diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c
index 16c54d3..9fd1b5e 100644
--- a/src/udiskslinuxdrive.c
+++ b/src/udiskslinuxdrive.c
@@ -686,8 +686,10 @@ on_eject (UDisksDrive *drive_iface,
goto out;
if (!udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"eject \"%s\"",
diff --git a/src/udiskslinuxencrypted.c b/src/udiskslinuxencrypted.c
index f6cfdff..1d2fed8 100644
--- a/src/udiskslinuxencrypted.c
+++ b/src/udiskslinuxencrypted.c
@@ -221,8 +221,10 @@ handle_unlock (UDisksEncrypted *encrypted,
/* TODO: support a 'readonly' option */
if (!udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
passphrase, /* input_string */
"cryptsetup luksOpen \"%s\" \"%s\"",
@@ -427,8 +429,10 @@ handle_lock (UDisksEncrypted *encrypted,
}
if (!udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"cryptsetup luksClose \"%s\"",
diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c
index f152f1d..72d0a7a 100644
--- a/src/udiskslinuxfilesystem.c
+++ b/src/udiskslinuxfilesystem.c
@@ -829,6 +829,9 @@ handle_mount (UDisksFilesystem *filesystem,
*/
if (system_managed)
{
+ gint status;
+ gboolean mount_fstab_as_root;
+
if (!g_file_test (mount_point_to_use, G_FILE_TEST_IS_DIR))
{
if (g_mkdir_with_parents (mount_point_to_use, 0755) != 0)
@@ -844,14 +847,33 @@ handle_mount (UDisksFilesystem *filesystem,
}
escaped_mount_point_to_use = g_strescape (mount_point_to_use, NULL);
+ mount_fstab_as_root = FALSE;
+ mount_fstab_again:
if (!udisks_daemon_launch_spawned_job_sync (daemon,
NULL, /* GCancellable */
- caller_uid, /* uid_t run_as */
+ mount_fstab_as_root ? 0 : caller_uid, /* uid_t run_as_uid */
+ mount_fstab_as_root ? 0 : caller_uid, /* uid_t run_as_euid */
+ &status,
&error_message,
NULL, /* input_string */
"mount \"%s\"",
escaped_mount_point_to_use))
{
+ /* mount(8) exits with status 1 on "incorrect invocation or permissions" - if this is
+ * is so, try as as root */
+ if (!mount_fstab_as_root && WIFEXITED (status) && WEXITSTATUS (status) == 1)
+ {
+ if (!udisks_daemon_util_check_authorization_sync (daemon,
+ object,
+ "org.freedesktop.udisks2.filesystem-nonuser-fstab",
+ options,
+ N_("Authentication is required to mount the non-user fstab device $(udisks2.device)"),
+ invocation))
+ goto out;
+ mount_fstab_as_root = TRUE;
+ goto mount_fstab_again;
+ }
+
g_dbus_method_invocation_return_error (invocation,
UDISKS_ERROR,
UDISKS_ERROR_FAILED,
@@ -988,8 +1010,10 @@ handle_mount (UDisksFilesystem *filesystem,
/* run mount(8) */
if (!udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"mount -t \"%s\" -o \"%s\" \"%s\" \"%s\"",
@@ -1122,17 +1146,42 @@ handle_unmount (UDisksFilesystem *filesystem,
*/
if (system_managed)
{
+ gint status;
+ gboolean unmount_fstab_as_root;
+
+ unmount_fstab_as_root = FALSE;
+ unmount_fstab_again:
escaped_mount_point = g_strescape (mount_point, NULL);
/* right now -l is the only way to "force unmount" file systems... */
if (!udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- caller_uid, /* uid_t run_as */
+ NULL, /* GCancellable */
+ unmount_fstab_as_root ? 0 : caller_uid, /* uid_t run_as_uid */
+ unmount_fstab_as_root ? 0 : caller_uid, /* uid_t run_as_euid */
+ &status,
&error_message,
NULL, /* input_string */
"umount %s \"%s\"",
opt_force ? "-l" : "",
escaped_mount_point))
{
+ /* umount(8) does not (yet) have a specific exits status for
+ * "insufficient permissions" so just try again as root
+ *
+ * TODO: file bug asking for such an exit status
+ */
+ if (!unmount_fstab_as_root && WIFEXITED (status) && WEXITSTATUS (status) != 0)
+ {
+ if (!udisks_daemon_util_check_authorization_sync (daemon,
+ object,
+ "org.freedesktop.udisks2.filesystem-nonuser-fstab",
+ options,
+ N_("Authentication is required to unmount the non-user fstab device $(udisks2.device)"),
+ invocation))
+ goto out;
+ unmount_fstab_as_root = TRUE;
+ goto unmount_fstab_again;
+ }
+
g_dbus_method_invocation_return_error (invocation,
UDISKS_ERROR,
UDISKS_ERROR_FAILED,
@@ -1202,8 +1251,10 @@ handle_unmount (UDisksFilesystem *filesystem,
}
escaped_mount_point = g_strescape (mount_point, NULL);
rc = udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"umount %s \"%s\"",
@@ -1214,8 +1265,10 @@ handle_unmount (UDisksFilesystem *filesystem,
{
/* mount_point == NULL */
rc = udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"umount %s \"%s\"",
@@ -1400,7 +1453,8 @@ handle_set_label (UDisksFilesystem *filesystem,
escaped_label = g_shell_quote (label);
job = udisks_daemon_launch_spawned_job (daemon,
NULL, /* cancellable */
- 0, /* uid_t run_as */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
NULL, /* input_string */
"e2label %s %s",
udisks_block_device_get_device (block),
diff --git a/src/udiskslinuxloop.c b/src/udiskslinuxloop.c
index 27f243b..61d42f6 100644
--- a/src/udiskslinuxloop.c
+++ b/src/udiskslinuxloop.c
@@ -178,8 +178,10 @@ handle_delete (UDisksLoop *loop,
}
if (!udisks_daemon_launch_spawned_job_sync (daemon,
- NULL, /* GCancellable */
- 0, /* uid_t run_as */
+ NULL, /* GCancellable */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
+ NULL, /* gint *out_status */
&error_message,
NULL, /* input_string */
"losetup -d \"%s\"",
diff --git a/src/udiskslinuxswapspace.c b/src/udiskslinuxswapspace.c
index 43bda2f..32ae054 100644
--- a/src/udiskslinuxswapspace.c
+++ b/src/udiskslinuxswapspace.c
@@ -142,7 +142,8 @@ handle_start (UDisksSwapspace *swapspace,
job = udisks_daemon_launch_spawned_job (daemon,
NULL, /* cancellable */
- 0, /* uid_t run_as */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
NULL, /* input_string */
"swapon %s",
udisks_block_device_get_device (block));
@@ -203,7 +204,8 @@ handle_stop (UDisksSwapspace *swapspace,
job = udisks_daemon_launch_spawned_job (daemon,
NULL, /* cancellable */
- 0, /* uid_t run_as */
+ 0, /* uid_t run_as_uid */
+ 0, /* uid_t run_as_euid */
NULL, /* input_string */
"swapoff %s",
udisks_block_device_get_device (block));
diff --git a/src/udisksspawnedjob.c b/src/udisksspawnedjob.c
index a790cd0..41cbc6c 100644
--- a/src/udisksspawnedjob.c
+++ b/src/udisksspawnedjob.c
@@ -21,6 +21,7 @@
#include "config.h"
#include <glib/gi18n-lib.h>
+#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
@@ -60,7 +61,8 @@ struct _UDisksSpawnedJob
GMainContext *main_context;
gchar *input_string;
- uid_t run_as;
+ uid_t run_as_uid;
+ uid_t run_as_euid;
const gchar *input_string_cursor;
GPid child_pid;
@@ -99,7 +101,8 @@ enum
PROP_0,
PROP_COMMAND_LINE,
PROP_INPUT_STRING,
- PROP_RUN_AS
+ PROP_RUN_AS_UID,
+ PROP_RUN_AS_EUID
};
enum
@@ -184,8 +187,12 @@ udisks_spawned_job_set_property (GObject *object,
job->input_string = g_value_dup_string (value);
break;
- case PROP_RUN_AS:
- job->run_as = g_value_get_uint (value);
+ case PROP_RUN_AS_UID:
+ job->run_as_uid = g_value_get_uint (value);
+ break;
+
+ case PROP_RUN_AS_EUID:
+ job->run_as_euid = g_value_get_uint (value);
break;
default:
@@ -358,22 +365,29 @@ child_watch_cb (GPid pid,
g_object_unref (job);
}
-#include <stdio.h>
-
/* careful, this is in the fork()'ed child so all utility threads etc are not available */
static void
child_setup (gpointer user_data)
{
UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data);
struct passwd *pw;
+ gid_t egid;
- if (job->run_as == getuid ())
+ if (job->run_as_uid == getuid () && job->run_as_euid == geteuid ())
goto out;
- pw = getpwuid (job->run_as);
+ pw = getpwuid (job->run_as_euid);
+ if (pw == NULL)
+ {
+ g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_euid);
+ abort ();
+ }
+ egid = pw->pw_gid;
+
+ pw = getpwuid (job->run_as_uid);
if (pw == NULL)
{
- g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as);
+ g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_uid);
abort ();
}
@@ -392,17 +406,20 @@ child_setup (gpointer user_data)
}
if (initgroups (pw->pw_name, pw->pw_gid) != 0)
{
- g_printerr ("Error initializing groups for uid %d: %m\n", (gint) job->run_as);
+ g_printerr ("Error initializing groups for user %s and group %d: %m\n",
+ pw->pw_name, (gint) pw->pw_gid);
abort ();
}
- if (setregid (pw->pw_gid, pw->pw_gid) != 0)
+ if (setregid (pw->pw_gid, egid) != 0)
{
- g_printerr ("Error setting real+effective gid for uid %d: %m\n", (gint) job->run_as);
+ g_printerr ("Error setting real+effective gid %d and %d: %m\n",
+ (gint) pw->pw_gid, (gint) egid);
abort ();
}
- if (setreuid (pw->pw_uid, pw->pw_uid) != 0)
+ if (setreuid (pw->pw_uid, job->run_as_euid) != 0)
{
- g_printerr ("Error setting real+effective uid for uid %d: %m\n", (gint) job->run_as);
+ g_printerr ("Error setting real+effective uid %d and %d: %m\n",
+ (gint) pw->pw_uid, (gint) job->run_as_euid);
abort ();
}
@@ -565,13 +582,13 @@ udisks_spawned_job_class_init (UDisksSpawnedJobClass *klass)
G_PARAM_STATIC_STRINGS));
/**
- * UDisksSpawnedJob:run-as:
+ * UDisksSpawnedJob:run-as-uid:
*
* The #uid_t to run the program as.
*/
g_object_class_install_property (gobject_class,
- PROP_RUN_AS,
- g_param_spec_uint ("run-as",
+ PROP_RUN_AS_UID,
+ g_param_spec_uint ("run-as-uid",
"Run As",
"The uid_t to run the program as",
0, G_MAXUINT, 0,
@@ -580,6 +597,21 @@ udisks_spawned_job_class_init (UDisksSpawnedJobClass *klass)
G_PARAM_STATIC_STRINGS));
/**
+ * UDisksSpawnedJob:run-as-euid:
+ *
+ * The effective #uid_t to run the program as.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_RUN_AS_EUID,
+ g_param_spec_uint ("run-as-euid",
+ "Run As (effective)",
+ "The effective uid_t to run the program as",
+ 0, G_MAXUINT, 0,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
* UDisksSpawnedJob::spawned-job-completed:
* @job: The #UDisksSpawnedJob emitting the signal.
* @error: %NULL if running the whole command line succeeded, otherwise a #GError that is set.
@@ -628,7 +660,8 @@ udisks_spawned_job_class_init (UDisksSpawnedJobClass *klass)
* udisks_spawned_job_new:
* @command_line: The command line to run.
* @input_string: A string to write to stdin of the spawned program or %NULL.
- * @run_as: The #uid_t to run the program as.
+ * @run_as_uid: The #uid_t to run the program as.
+ * @run_as_euid: The effective #uid_t to run the program as.
* @cancellable: A #GCancellable or %NULL.
*
* Creates a new #UDisksSpawnedJob instance.
@@ -642,7 +675,8 @@ udisks_spawned_job_class_init (UDisksSpawnedJobClass *klass)
UDisksSpawnedJob *
udisks_spawned_job_new (const gchar *command_line,
const gchar *input_string,
- uid_t run_as,
+ uid_t run_as_uid,
+ uid_t run_as_euid,
GCancellable *cancellable)
{
g_return_val_if_fail (command_line != NULL, NULL);
@@ -650,7 +684,8 @@ udisks_spawned_job_new (const gchar *command_line,
return UDISKS_SPAWNED_JOB (g_object_new (UDISKS_TYPE_SPAWNED_JOB,
"command-line", command_line,
"input-string", input_string,
- "run-as", run_as,
+ "run-as-uid", run_as_uid,
+ "run-as-euid", run_as_euid,
"cancellable", cancellable,
NULL));
}
diff --git a/src/udisksspawnedjob.h b/src/udisksspawnedjob.h
index 547ee26..f14e876 100644
--- a/src/udisksspawnedjob.h
+++ b/src/udisksspawnedjob.h
@@ -32,7 +32,8 @@ G_BEGIN_DECLS
GType udisks_spawned_job_get_type (void) G_GNUC_CONST;
UDisksSpawnedJob *udisks_spawned_job_new (const gchar *command_line,
const gchar *input_string,
- uid_t run_as,
+ uid_t run_as_uid,
+ uid_t run_as_euid,
GCancellable *cancellable);
const gchar *udisks_spawned_job_get_command_line (UDisksSpawnedJob *job);