From 65999009bb026972526c756aa62bf0486318ebfe Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Mon, 2 Mar 2009 14:39:30 -0500 Subject: [PATCH] make it possible to inhibit all operations on the daemon This is needed for things like OS installers to inhibit automounting etc. --- doc/man/devkit-disks.xml | 24 ++++ src/devkit-disks-daemon.c | 174 +++++++++++++++++++++---- src/devkit-disks-daemon.h | 10 ++ src/org.freedesktop.DeviceKit.Disks.Device.xml | 1 + src/org.freedesktop.DeviceKit.Disks.xml | 65 +++++++++ tools/devkit-disks.c | 70 +++++++++- 6 files changed, 321 insertions(+), 23 deletions(-) diff --git a/doc/man/devkit-disks.xml b/doc/man/devkit-disks.xml index 1a9c196..422ae94 100644 --- a/doc/man/devkit-disks.xml +++ b/doc/man/devkit-disks.xml @@ -137,6 +137,30 @@ + + + + + + + Inhibits clients from invoking methods on the daemon of + the daemon that require authorization (all methods will + return the + org.freedesktop.DeviceKit.Disks.Error.Inhibited error) if + the caller is not the super user. This is typically used + by OS installers and other programs that expects full + control of the system, specifically to avoid automounting + devices. Only the super user can do this. + + + If no program is given, + polling is inhibited until Ctrl+C is pressed. Otherwise the program is spawned and the polling + is only inhibited until the program terminates. + + + + + diff --git a/src/devkit-disks-daemon.c b/src/devkit-disks-daemon.c index 80abee0..944a231 100644 --- a/src/devkit-disks-daemon.c +++ b/src/devkit-disks-daemon.c @@ -69,6 +69,7 @@ enum { PROP_0, PROP_DAEMON_VERSION, + PROP_DAEMON_IS_INHIBITED, PROP_SUPPORTS_LUKS_DEVICES, PROP_KNOWN_FILESYSTEMS, }; @@ -106,6 +107,8 @@ struct DevkitDisksDaemonPrivate DevkitDisksLogger *logger; GList *polling_inhibitors; + + GList *inhibitors; }; static void devkit_disks_daemon_class_init (DevkitDisksDaemonClass *klass); @@ -115,6 +118,9 @@ static void devkit_disks_daemon_finalize (GObject *object); static void daemon_polling_inhibitor_disconnected_cb (DevkitDisksInhibitor *inhibitor, DevkitDisksDaemon *daemon); +static void daemon_inhibitor_disconnected_cb (DevkitDisksInhibitor *inhibitor, + DevkitDisksDaemon *daemon); + G_DEFINE_TYPE (DevkitDisksDaemon, devkit_disks_daemon, G_TYPE_OBJECT) #define DEVKIT_DISKS_DAEMON_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVKIT_DISKS_TYPE_DAEMON, DevkitDisksDaemonPrivate)) @@ -146,6 +152,7 @@ devkit_disks_error_get_type (void) static const GEnumValue values[] = { ENUM_ENTRY (DEVKIT_DISKS_ERROR_FAILED, "Failed"), + ENUM_ENTRY (DEVKIT_DISKS_ERROR_INHIBITED, "Inhibited"), ENUM_ENTRY (DEVKIT_DISKS_ERROR_BUSY, "Busy"), ENUM_ENTRY (DEVKIT_DISKS_ERROR_CANCELLED, "Cancelled"), ENUM_ENTRY (DEVKIT_DISKS_ERROR_INVALID_OPTION, "InvalidOption"), @@ -382,6 +389,10 @@ get_property (GObject *object, g_value_set_string (value, VERSION); break; + case PROP_DAEMON_IS_INHIBITED: + g_value_set_boolean (value, (daemon->priv->inhibitors != NULL)); + break; + case PROP_SUPPORTS_LUKS_DEVICES: /* TODO: probably Linux only */ g_value_set_boolean (value, TRUE); @@ -473,6 +484,11 @@ devkit_disks_daemon_class_init (DevkitDisksDaemonClass *klass) g_object_class_install_property ( object_class, + PROP_DAEMON_IS_INHIBITED, + g_param_spec_boolean ("daemon-is-inhibited", NULL, NULL, FALSE, G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, PROP_SUPPORTS_LUKS_DEVICES, g_param_spec_boolean ("supports-luks-devices", NULL, NULL, FALSE, G_PARAM_READABLE)); @@ -564,6 +580,13 @@ devkit_disks_daemon_finalize (GObject *object) } g_list_free (daemon->priv->polling_inhibitors); + for (l = daemon->priv->inhibitors; l != NULL; l = l->next) { + DevkitDisksInhibitor *inhibitor = DEVKIT_DISKS_INHIBITOR (l->data); + g_signal_handlers_disconnect_by_func (inhibitor, daemon_inhibitor_disconnected_cb, daemon); + g_object_unref (inhibitor); + } + g_list_free (daemon->priv->inhibitors); + G_OBJECT_CLASS (devkit_disks_daemon_parent_class)->finalize (object); } @@ -1139,6 +1162,30 @@ devkit_disks_damon_local_get_caller_for_context (DevkitDisksDaemon *daemon, return pk_caller; } +/*--------------------------------------------------------------------------------------------------------------*/ + +static gboolean +throw_error (DBusGMethodInvocation *context, int error_code, const char *format, ...) +{ + GError *error; + va_list args; + char *message; + + va_start (args, format); + message = g_strdup_vprintf (format, args); + va_end (args); + + error = g_error_new (DEVKIT_DISKS_ERROR, + error_code, + "%s", message); + dbus_g_method_return_error (context, error); + g_error_free (error); + g_free (message); + return TRUE; +} + +/*--------------------------------------------------------------------------------------------------------------*/ + gboolean devkit_disks_damon_local_check_auth (DevkitDisksDaemon *daemon, PolKitCaller *pk_caller, @@ -1153,6 +1200,18 @@ devkit_disks_damon_local_check_auth (DevkitDisksDaemon *daemon, ret = FALSE; + if (daemon->priv->inhibitors != NULL) { + uid_t uid; + + uid = (uid_t) -1; + if (!polkit_caller_get_uid (pk_caller, &uid) || uid != 0) { + throw_error (context, + DEVKIT_DISKS_ERROR_INHIBITED, + "Daemon is being inhibited"); + } + goto out; + } + pk_action = polkit_action_new (); polkit_action_set_action_id (pk_action, action_id); pk_result = polkit_context_is_caller_authorized (daemon->priv->pk_context, @@ -1173,6 +1232,8 @@ devkit_disks_damon_local_check_auth (DevkitDisksDaemon *daemon, dbus_error_free (&d_error); } polkit_action_unref (pk_action); + + out: return ret; } @@ -1199,28 +1260,6 @@ devkit_disks_daemon_local_update_poller (DevkitDisksDaemon *daemon) } /*--------------------------------------------------------------------------------------------------------------*/ - -static gboolean -throw_error (DBusGMethodInvocation *context, int error_code, const char *format, ...) -{ - GError *error; - va_list args; - char *message; - - va_start (args, format); - message = g_strdup_vprintf (format, args); - va_end (args); - - error = g_error_new (DEVKIT_DISKS_ERROR, - error_code, - "%s", message); - dbus_g_method_return_error (context, error); - g_error_free (error); - g_free (message); - return TRUE; -} - -/*--------------------------------------------------------------------------------------------------------------*/ /* exported methods */ static void @@ -1387,3 +1426,94 @@ devkit_disks_daemon_drive_uninhibit_all_polling (DevkitDisksDaemon *daemon, } /*--------------------------------------------------------------------------------------------------------------*/ + +static void +daemon_inhibitor_disconnected_cb (DevkitDisksInhibitor *inhibitor, + DevkitDisksDaemon *daemon) +{ + daemon->priv->inhibitors = g_list_remove (daemon->priv->inhibitors, inhibitor); + g_signal_handlers_disconnect_by_func (inhibitor, daemon_inhibitor_disconnected_cb, daemon); + g_object_unref (inhibitor); +} + +gboolean +devkit_disks_daemon_local_has_inhibitors (DevkitDisksDaemon *daemon) +{ + return daemon->priv->inhibitors != NULL; +} + +gboolean +devkit_disks_daemon_inhibit (DevkitDisksDaemon *daemon, + DBusGMethodInvocation *context) +{ + DevkitDisksInhibitor *inhibitor; + PolKitCaller *pk_caller; + uid_t uid; + + + if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (daemon, context)) == NULL) + goto out; + + uid = (uid_t) -1; + if (!polkit_caller_get_uid (pk_caller, &uid) || uid != 0) { + throw_error (context, + DEVKIT_DISKS_ERROR_FAILED, + "Only uid 0 is authorized to inhibit the daemon"); + goto out; + } + + inhibitor = devkit_disks_inhibitor_new (context); + + daemon->priv->inhibitors = g_list_prepend (daemon->priv->inhibitors, inhibitor); + g_signal_connect (inhibitor, "disconnected", G_CALLBACK (daemon_inhibitor_disconnected_cb), daemon); + + dbus_g_method_return (context, devkit_disks_inhibitor_get_cookie (inhibitor)); + +out: + if (pk_caller != NULL) + polkit_caller_unref (pk_caller); + return TRUE; +} + + +/*--------------------------------------------------------------------------------------------------------------*/ + +gboolean +devkit_disks_daemon_uninhibit (DevkitDisksDaemon *daemon, + char *cookie, + DBusGMethodInvocation *context) +{ + const gchar *sender; + DevkitDisksInhibitor *inhibitor; + GList *l; + + sender = dbus_g_method_get_sender (context); + + inhibitor = NULL; + for (l = daemon->priv->inhibitors; l != NULL; l = l->next) { + DevkitDisksInhibitor *i = DEVKIT_DISKS_INHIBITOR (l->data); + + if (g_strcmp0 (devkit_disks_inhibitor_get_unique_dbus_name (i), sender) == 0 && + g_strcmp0 (devkit_disks_inhibitor_get_cookie (i), cookie) == 0) { + inhibitor = i; + break; + } + } + + if (inhibitor == NULL) { + throw_error (context, + DEVKIT_DISKS_ERROR_FAILED, + "No such inhibitor"); + goto out; + } + + daemon->priv->inhibitors = g_list_remove (daemon->priv->inhibitors, inhibitor); + g_object_unref (inhibitor); + + dbus_g_method_return (context); + + out: + return TRUE; +} + +/*--------------------------------------------------------------------------------------------------------------*/ diff --git a/src/devkit-disks-daemon.h b/src/devkit-disks-daemon.h index 735a0ec..a31cc28 100644 --- a/src/devkit-disks-daemon.h +++ b/src/devkit-disks-daemon.h @@ -53,6 +53,7 @@ struct DevkitDisksDaemonClass typedef enum { DEVKIT_DISKS_ERROR_FAILED, + DEVKIT_DISKS_ERROR_INHIBITED, DEVKIT_DISKS_ERROR_BUSY, DEVKIT_DISKS_ERROR_CANCELLED, DEVKIT_DISKS_ERROR_INVALID_OPTION, @@ -115,6 +116,8 @@ void devkit_disks_daemon_local_update_poller (DevkitDisksDae gboolean devkit_disks_daemon_local_has_polling_inhibitors (DevkitDisksDaemon *daemon); +gboolean devkit_disks_daemon_local_has_inhibitors (DevkitDisksDaemon *daemon); + DevkitDisksLogger *devkit_disks_daemon_local_get_logger (DevkitDisksDaemon *daemon); DevkitDisksMountMonitor *devkit_disks_daemon_local_get_mount_monitor (DevkitDisksDaemon *daemon); @@ -161,6 +164,13 @@ gboolean devkit_disks_daemon_drive_uninhibit_all_polling (DevkitDisksDaemon char *cookie, DBusGMethodInvocation *context); +gboolean devkit_disks_daemon_inhibit (DevkitDisksDaemon *daemon, + DBusGMethodInvocation *context); + +gboolean devkit_disks_daemon_uninhibit (DevkitDisksDaemon *daemon, + char *cookie, + DBusGMethodInvocation *context); + G_END_DECLS #endif /* __DEVKIT_DISKS_DAEMON_H__ */ diff --git a/src/org.freedesktop.DeviceKit.Disks.Device.xml b/src/org.freedesktop.DeviceKit.Disks.Device.xml index 898acd8..fa1e9de 100644 --- a/src/org.freedesktop.DeviceKit.Disks.Device.xml +++ b/src/org.freedesktop.DeviceKit.Disks.Device.xml @@ -2,6 +2,7 @@ "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [ + diff --git a/src/org.freedesktop.DeviceKit.Disks.xml b/src/org.freedesktop.DeviceKit.Disks.xml index c18c101..e5d3822 100644 --- a/src/org.freedesktop.DeviceKit.Disks.xml +++ b/src/org.freedesktop.DeviceKit.Disks.xml @@ -2,6 +2,7 @@ "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [ + @@ -180,6 +181,64 @@ + + + + + A cookie that can be used in the + Uninhibit() method. + to stop inhibiting the daemon. + + + + + + + Inhibits clients from invoking methods on the daemon + of the daemon that require authorization (all methods + will return the &ERROR_INHIBITED; error) + if the caller is not the super user. + This is typically used by OS installers and other + programs that expects full control of the system, specifically + to avoid automounting devices. + + + + Only the super user can invoke this method. + + + if the caller is not the super user + + + + + + + + + + + + A cookie obtained from the + Inhibit() method. + + + + + + + Uninhibits other clients from using the daemon. + + + + if the given cookie is malformed + + + + + + + Object path of device that was added. @@ -271,6 +330,12 @@ + + + TRUE only if the daemon is inhibited. + + + TRUE only if the daemon can create encrypted LUKS block devices, see the diff --git a/tools/devkit-disks.c b/tools/devkit-disks.c index f283571..5ad1d78 100644 --- a/tools/devkit-disks.c +++ b/tools/devkit-disks.c @@ -58,6 +58,7 @@ static gboolean opt_monitor = FALSE; static gboolean opt_monitor_detail = FALSE; static char *opt_show_info = NULL; static char *opt_inhibit_polling = NULL; +static gboolean opt_inhibit = FALSE; static gboolean opt_inhibit_all_polling = FALSE; static char *opt_mount = NULL; static char *opt_mount_fstype = NULL; @@ -1107,7 +1108,6 @@ out: /* ---------------------------------------------------------------------------------------------------- */ - static gint do_inhibit_all_polling (gint argc, gchar *argv[]) @@ -1175,6 +1175,70 @@ out: /* ---------------------------------------------------------------------------------------------------- */ +static gint +do_inhibit (gint argc, + gchar *argv[]) +{ + char *cookie; + DBusGProxy *proxy; + GError *error; + gint ret; + + cookie = NULL; + ret = 127; + + proxy = dbus_g_proxy_new_for_name (bus, + "org.freedesktop.DeviceKit.Disks", + "/", + "org.freedesktop.DeviceKit.Disks"); + + error = NULL; + if (!org_freedesktop_DeviceKit_Disks_inhibit (proxy, + &cookie, + &error)) { + g_print ("Inhibit all polling failed: %s\n", error->message); + g_error_free (error); + goto out; + } + + if (argc == 0) { + g_print ("Inhibiting the daemon. Press Ctrl+C to exit.\n"); + while (TRUE) + sleep (100000000); + } else { + GError *error; + gint exit_status; + + error = NULL; + if (!g_spawn_sync (NULL, /* working dir */ + argv, + NULL, /* envp */ + G_SPAWN_SEARCH_PATH, + NULL, /* child_setup */ + NULL, /* user_data */ + NULL, /* standard_output */ + NULL, /* standard_error */ + &exit_status, /* exit_status */ + &error)) { + g_printerr ("Error launching program: %s\n", error->message); + g_error_free (error); + ret = 126; + goto out; + } + + if (WIFEXITED (exit_status)) + ret = WEXITSTATUS (exit_status); + else + ret = 125; + } + +out: + g_free (cookie); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + int main (int argc, char **argv) { @@ -1189,6 +1253,7 @@ main (int argc, char **argv) { "show-info", 0, 0, G_OPTION_ARG_STRING, &opt_show_info, "Show information about object path", NULL }, { "inhibit-polling", 0, 0, G_OPTION_ARG_STRING, &opt_inhibit_polling, "Inhibit polling", NULL }, { "inhibit-all-polling", 0, 0, G_OPTION_ARG_NONE, &opt_inhibit_all_polling, "Inhibit all polling", NULL }, + { "inhibit", 0, 0, G_OPTION_ARG_NONE, &opt_inhibit, "Inhibit the daemon", NULL }, { "mount", 0, 0, G_OPTION_ARG_STRING, &opt_mount, "Mount the device given by the object path", NULL }, { "mount-fstype", 0, 0, G_OPTION_ARG_STRING, &opt_mount_fstype, "Specify file system type", NULL }, @@ -1278,6 +1343,9 @@ main (int argc, char **argv) } else if (opt_inhibit_all_polling) { ret = do_inhibit_all_polling (argc - 1, argv + 1); goto out; + } else if (opt_inhibit) { + ret = do_inhibit (argc - 1, argv + 1); + goto out; } else if (opt_mount != NULL) { do_mount (opt_mount, opt_mount_fstype, opt_mount_options); } else if (opt_unmount != NULL) { -- 2.7.4