diff options
author | Milan Bouchet-Valat <nalimilan@club.fr> | 2010-01-16 13:27:07 +0100 |
---|---|---|
committer | Milan Bouchet-Valat <nalimilan@club.fr> | 2010-01-17 22:08:47 +0100 |
commit | cf76198a2e90806bdbdb510df464e5fdd773fc8c (patch) | |
tree | 8b8ac733fa4a41164de8c9d0b9c1f189baa1c710 | |
parent | 7bde7d0939d0c4b483203d9ca3969c7e3eff66f8 (diff) |
Add PolicyKit authentication D-Bus method
New org.freedesktop.SystemToolsBackends.Authenticate interface, which can be called on all modules. This method takes no arguments, and returns a boolean, or error for cancelled or failed. It's implemented via dispatcher_filter_func(), calling dispatch_auth_message().
New check_polkit_auth() function to centralize PolicyKit authorizations handling, returning error when needed. We now require PolicyKit instead of it being an optional dependency, and need version 0.94 so that we can remove the PID checking workaround.
PolicyKit action for SelfConfig is now really used, so set it to "yes" since settings that can be changed that way are minor (just like the old behavior).
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.in | 23 | ||||
-rw-r--r-- | dispatcher/Makefile.am | 3 | ||||
-rw-r--r-- | dispatcher/dispatcher.c | 227 | ||||
-rw-r--r-- | org.freedesktop.SystemToolsBackends.policy.in | 2 |
5 files changed, 136 insertions, 121 deletions
diff --git a/Makefile.am b/Makefile.am index 6736b3e..2b7babe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -60,10 +60,8 @@ systemd_DATA = org.freedesktop.SystemToolsBackends.conf policy_in_files = org.freedesktop.SystemToolsBackends.policy.in -if HAVE_POLKIT policydir = $(POLKIT_POLICY_DIR) policy_DATA = $(policy_in_files:.policy.in=.policy) @INTLTOOL_POLICY_RULE@ -endif diff --git a/configure.in b/configure.in index 23f2a4e..21d263f 100644 --- a/configure.in +++ b/configure.in @@ -12,7 +12,7 @@ IT_PROG_INTLTOOL([0.40.0]) DBUS_REQUIRED=1.1.2 DBUS_GLIB_REQUIRED=0.74 GLIB_REQUIRED=2.4.0 -POLICYKIT_REQUIRED=0.92 +POLICYKIT_REQUIRED=0.94 GIO_REQUIRED=2.15.2 dnl get prefix in $prefix, yes, this sucks @@ -115,6 +115,7 @@ AC_SUBST([DBUS_LIBS]) dnl check for the dispatcher deps PKG_CHECK_MODULES(DISPATCHER, [ + polkit-gobject-1 >= $POLICYKIT_REQUIRED dbus-glib-1 >= $DBUS_GLIB_REQUIRED glib-2.0 >= $GLIB_REQUIRED ]) @@ -122,17 +123,6 @@ DISPATCHER_CFLAGS="-DDBUS_API_SUBJECT_TO_CHANGE $DISPATCHER_CFLAGS" AC_SUBST(DISPATCHER_LIBS) AC_SUBST(DISPATCHER_CFLAGS) -dnl check for PolicyKit -PKG_CHECK_MODULES(POLKIT, polkit-gobject-1 >= $POLICYKIT_REQUIRED, have_polkit=yes, have_polkit=no) - -if test "$have_polkit" = "yes"; then - AC_DEFINE(HAVE_POLKIT, [1], [whether PolicyKit was found]) -fi - -AC_SUBST(POLKIT_LIBS) -AC_SUBST(POLKIT_CFLAGS) -AM_CONDITIONAL(HAVE_POLKIT, test x$have_polkit = xyes) - dnl check for Gio PKG_CHECK_MODULES(GIO, gio-2.0 >= $GIO_REQUIRED, have_gio=yes, have_gio=no) @@ -176,17 +166,19 @@ Utils/Makefile SystemToolsBackends.pl test-backends services/Makefile -services/org.freedesktop.SystemToolsBackends.GroupsConfig.service +services/org.freedesktop.SystemToolsBackends.GroupConfig2.service +services/org.freedesktop.SystemToolsBackends.GroupsConfig2.service services/org.freedesktop.SystemToolsBackends.HostsConfig.service services/org.freedesktop.SystemToolsBackends.IfacesConfig.service services/org.freedesktop.SystemToolsBackends.NFSConfig.service services/org.freedesktop.SystemToolsBackends.NTPConfig.service services/org.freedesktop.SystemToolsBackends.Platform.service +services/org.freedesktop.SystemToolsBackends.SelfConfig2.service services/org.freedesktop.SystemToolsBackends.ServicesConfig.service services/org.freedesktop.SystemToolsBackends.SMBConfig.service services/org.freedesktop.SystemToolsBackends.TimeConfig.service -services/org.freedesktop.SystemToolsBackends.UserConfig.service -services/org.freedesktop.SystemToolsBackends.UsersConfig.service +services/org.freedesktop.SystemToolsBackends.UserConfig2.service +services/org.freedesktop.SystemToolsBackends.UsersConfig2.service org.freedesktop.SystemToolsBackends.service Net-DBus/Makefile Net-DBus/lib/Makefile @@ -205,7 +197,6 @@ Configuration (BACKENDS): The backends will be installed in : ${scriptsdir} The files will be installed in : ${filesdir} Using internal copy of Net::Dbus : ${internalnetdbus} - Use PolicyKit : ${have_polkit} File notification : ${have_gio} DBus system.d directory : ${DBUS_SYSTEMD_DIR} diff --git a/dispatcher/Makefile.am b/dispatcher/Makefile.am index d515077..c4aecc2 100644 --- a/dispatcher/Makefile.am +++ b/dispatcher/Makefile.am @@ -1,7 +1,6 @@ INCLUDES = \ -Wall \ $(DISPATCHER_CFLAGS) \ - $(POLKIT_CFLAGS) \ $(GIO_CFLAGS) sbin_PROGRAMS = system-tools-backends @@ -10,7 +9,7 @@ if HAVE_GIO file_monitor_sources = file-monitor.c file-monitor.h endif -system_tools_backends_LDADD = $(DISPATCHER_LIBS) $(POLKIT_LIBS) $(GIO_LIBS) +system_tools_backends_LDADD = $(DISPATCHER_LIBS) $(GIO_LIBS) system_tools_backends_SOURCES = \ $(file_monitor_sources) \ dispatcher.c dispatcher.h \ diff --git a/dispatcher/dispatcher.c b/dispatcher/dispatcher.c index 15b8eb9..2bac840 100644 --- a/dispatcher/dispatcher.c +++ b/dispatcher/dispatcher.c @@ -31,9 +31,7 @@ #include "config.h" #include "dispatcher.h" -#ifdef HAVE_POLKIT #include <polkit/polkit.h> -#endif #ifdef HAVE_GIO #include "file-monitor.h" @@ -42,6 +40,7 @@ #define DBUS_ADDRESS_ENVVAR "DBUS_SESSION_BUS_ADDRESS" #define DBUS_INTERFACE_STB "org.freedesktop.SystemToolsBackends" #define DBUS_INTERFACE_STB_PLATFORM "org.freedesktop.SystemToolsBackends.Platform" +#define DBUS_INTERFACE_STB_AUTH "org.freedesktop.SystemToolsBackends.Authentication" #define DBUS_PATH_SELF_CONFIG "/org/freedesktop/SystemToolsBackends/SelfConfig2" #define STB_DISPATCHER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), STB_TYPE_DISPATCHER, StbDispatcherPrivate)) @@ -65,9 +64,7 @@ struct StbDispatcherPrivate DBusConnection *connection; gchar *platform; -#ifdef HAVE_POLKIT PolkitAuthority *polkit_authority; -#endif #ifdef HAVE_GIO StbFileMonitor *file_monitor; @@ -311,98 +308,149 @@ get_destination (DBusMessage *message) return destination; } +static void +return_error (StbDispatcher *dispatcher, + DBusMessage *message, + const gchar *error_name, + const gchar *error_message) +{ + DBusMessage *reply; + StbDispatcherPrivate *priv; + + priv = STB_DISPATCHER_GET_PRIVATE (dispatcher); + + DEBUG (dispatcher, "sending error %s from: %s", error_name, dbus_message_get_path (message)); + + reply = dbus_message_new_error (message, error_name, error_message); + dbus_connection_send (priv->connection, reply, NULL); + dbus_message_unref (reply); +} + static gboolean -can_caller_do_action (StbDispatcher *dispatcher, - DBusMessage *message, - const gchar *name) +check_polkit_auth (StbDispatcher *dispatcher, + DBusMessage *message, + GError **ret_error) { -#ifdef HAVE_POLKIT StbDispatcherPrivate *priv; PolkitSubject *subject; PolkitAuthorizationResult *result; + GError *error; + gchar **path; gchar *action_id; - gulong caller_pid; gboolean retval; - GError *gerror = NULL; - DBusError dbus_error; - DBusMessage *call, *reply; - const gchar *connection_name; - - /* Allow getting information */ - if (dbus_message_has_member (message, "get")) - return TRUE; - - /* Do not allow anything besides "set", "add" or "del" past this point */ - if (!(dbus_message_has_member (message, "set") - || dbus_message_has_member (message, "add") - || dbus_message_has_member (message, "del"))) - return FALSE; priv = STB_DISPATCHER_GET_PRIVATE (dispatcher); - if (name) - action_id = g_strdup_printf ("org.freedesktop.systemtoolsbackends.%s.set", name); + if (dbus_message_get_path_decomposed (message, &path) + && path[0] && path[1] && path[2] && path[3] + && strcmp (path[3], "SelfConfig2") == 0) + action_id = g_strdup_printf ("org.freedesktop.systemtoolsbackends.self.set"); else action_id = g_strdup_printf ("org.freedesktop.systemtoolsbackends.set"); - /* Get the caller's PID using the connection name */ - call = dbus_message_new_method_call ("org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus", - "GetConnectionUnixProcessID"); - connection_name = dbus_message_get_sender (message); - dbus_message_append_args (call, DBUS_TYPE_STRING, &connection_name, DBUS_TYPE_INVALID); - - dbus_error_init (&dbus_error); - - reply = dbus_connection_send_with_reply_and_block (priv->connection, call, -1, &dbus_error); - if (dbus_error_is_set (&dbus_error)) - goto dbus_error; - - dbus_message_get_args (reply, &dbus_error, DBUS_TYPE_UINT32, &caller_pid, DBUS_TYPE_INVALID); - if (dbus_error_is_set (&dbus_error)) - goto dbus_error; - - dbus_message_unref (call); - dbus_message_unref (reply); - - /* We need to identify the subject using its PID - * because it's how PolkitLockButton works on the client side */ - subject = polkit_unix_process_new (caller_pid); + subject = polkit_system_bus_name_new (dbus_message_get_sender (message)); result = polkit_authority_check_authorization_sync (priv->polkit_authority, subject, action_id, NULL, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, - NULL, &gerror); + NULL, &error); + if (result) + { + retval = polkit_authorization_result_get_is_authorized (result); + g_object_unref (result); + } + else + { + retval = FALSE; - g_object_unref (subject); + if (error->code == POLKIT_ERROR_CANCELLED) + /* Clients need to hanle this case separately to avoid showing an error dialog */ + return_error (dispatcher, message, + "org.freedesktop.SystemToolsBackends.AuthenticationCancelled", + "Authentication cancelled by user"); + else + return_error (dispatcher, message, + "org.freedesktop.SystemToolsBackends.AuthenticationFailed", + error->message); - if (gerror) - { - g_critical ("%s", gerror->message); - g_error_free (gerror); - g_free (action_id); + g_warning ("Error checking PolicyKit authorization: %s", error->message); - return FALSE; + if (!ret_error) + g_error_free (error); + else + *ret_error = error; } - retval = polkit_authorization_result_get_is_authorized (result); - DEBUG (dispatcher, (retval) ? "subject is allowed to do action '%s'" : "subject can't do action '%s'", action_id); g_free (action_id); + g_object_unref (subject); + + if (path) + g_strfreev (path); return retval; +} + +static gboolean +can_caller_do_action (StbDispatcher *dispatcher, + DBusMessage *message) +{ + gboolean retval; - dbus_error: - g_critical ("Could not get PID of the caller: %s", dbus_error.message); - dbus_error_free (&dbus_error); - g_free (action_id); + /* Allow getting information */ + if (dbus_message_has_member (message, "get")) + return TRUE; + /* Do not allow anything besides "set", "add" or "del" past this point */ + if (!(dbus_message_has_member (message, "set") + || dbus_message_has_member (message, "add") + || dbus_message_has_member (message, "del"))) return FALSE; -#else - return TRUE; -#endif /* HAVE_POLKIT */ + + /* Replies with an error if needed, in which case retval is FALSE */ + retval = check_polkit_auth (dispatcher, message, NULL); + + return retval; +} + +/* + * Handles all messages with DBUS_INTERFACE_STB_AUTH, which check authorizations + * for all modules. + */ +static void +dispatch_auth_message (StbDispatcher *dispatcher, + DBusMessage *message) +{ + StbDispatcherPrivate *priv; + GError *error = NULL; + + priv = dispatcher->_priv; + + if (!dbus_message_has_interface (message, DBUS_INTERFACE_STB_AUTH)) + return; + + if (dbus_message_has_member (message, "authenticate")) + { + DBusMessage *reply; + DBusMessageIter iter; + gboolean authorized; + + /* Replies with an error if needed */ + authorized = check_polkit_auth (dispatcher, message, &error); + + if (!error) + { + /* Create a reply with the authorization result */ + reply = dbus_message_new_method_return (message); + + dbus_message_iter_init_append (reply, &iter); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_BOOLEAN, &authorized); + + dbus_connection_send (priv->connection, reply, NULL); + dbus_message_unref (reply); + } + } } static void @@ -450,24 +498,6 @@ dispatch_stb_message (StbDispatcher *dispatcher, } static void -return_error (StbDispatcher *dispatcher, - DBusMessage *message, - const gchar *error_name) -{ - DBusMessage *reply; - StbDispatcherPrivate *priv; - - priv = STB_DISPATCHER_GET_PRIVATE (dispatcher); - - DEBUG (dispatcher, "sending error %s from: %s", error_name, dbus_message_get_path (message)); - - reply = dbus_message_new_error (message, error_name, - "No permissions to perform the task."); - dbus_connection_send (priv->connection, reply, NULL); - dbus_message_unref (reply); -} - -static void dispatch_platform_message (StbDispatcher *dispatcher, DBusMessage *message) { @@ -505,26 +535,27 @@ dispatch_self_config (StbDispatcher *dispatcher, { StbDispatcherPrivate *priv; const gchar *sender; - uid_t uid, message_uid; + gulong uid, message_uid; priv = dispatcher->_priv; sender = dbus_message_get_sender (message); uid = dbus_bus_get_unix_user (priv->connection, sender, NULL); - /* Absolutely avoid UID 0 being allowed */ + /* Absolutely avoid passing UID 0 */ g_return_if_fail (uid > 0); if (dbus_message_get_args (message, NULL, - DBUS_TYPE_UINT32, &uid, + DBUS_TYPE_UINT32, &message_uid, DBUS_TYPE_INVALID) && message_uid == uid) { dbus_message_set_sender (message, sender); - dispatch_stb_message (dispatcher, message, dbus_message_get_serial (message)); - dbus_message_unref (message); + dispatch_stb_message (dispatcher, message, 0); } else - return_error (dispatcher, message, DBUS_ERROR_ACCESS_DENIED); + return_error (dispatcher, message, + "org.freedesktop.SystemToolsBackends.InvalidMessage", + "Malformed message was sent"); } static DBusHandlerResult @@ -546,19 +577,19 @@ dispatcher_filter_func (DBusConnection *connection, dispatch_stb_message (dispatcher, message, 0); else if (dbus_message_has_interface (message, DBUS_INTERFACE_STB_PLATFORM)) dispatch_platform_message (dispatcher, message); + else if (dbus_message_has_interface (message, DBUS_INTERFACE_STB_AUTH)) + dispatch_auth_message (dispatcher, message); else if (dbus_message_has_path (message, DBUS_PATH_SELF_CONFIG)) { - if (can_caller_do_action (dispatcher, message, "self")) + /* Error is returned from can_caller_do_action() in case of failure */ + if (can_caller_do_action (dispatcher, message)) dispatch_self_config (dispatcher, message); - else - return_error (dispatcher, message, DBUS_ERROR_ACCESS_DENIED); } else if (dbus_message_has_interface (message, DBUS_INTERFACE_STB)) { - if (can_caller_do_action (dispatcher, message, NULL)) + /* Error is returned from can_caller_do_action() in case of failure */ + if (can_caller_do_action (dispatcher, message)) dispatch_stb_message (dispatcher, message, 0); - else - return_error (dispatcher, message, DBUS_ERROR_ACCESS_DENIED); } return DBUS_HANDLER_RESULT_HANDLED; @@ -607,9 +638,7 @@ stb_dispatcher_init (StbDispatcher *dispatcher) /* we're screwed if we don't have this */ g_assert (priv->connection != NULL); -#ifdef HAVE_POLKIT priv->polkit_authority = polkit_authority_get (); -#endif #ifdef HAVE_GIO priv->file_monitor = stb_file_monitor_new (); @@ -662,9 +691,7 @@ stb_dispatcher_finalize (GObject *object) dbus_connection_unref (priv->connection); -#ifdef HAVE_POLKIT g_object_unref (priv->polkit_authority); -#endif #ifdef HAVE_GIO g_object_unref (priv->file_monitor); diff --git a/org.freedesktop.SystemToolsBackends.policy.in b/org.freedesktop.SystemToolsBackends.policy.in index f45ef58..a53aefb 100644 --- a/org.freedesktop.SystemToolsBackends.policy.in +++ b/org.freedesktop.SystemToolsBackends.policy.in @@ -19,7 +19,7 @@ <_message>You need to authenticate to modify your user account information</_message> <defaults> <allow_inactive>no</allow_inactive> - <allow_active>auth_self</allow_active> + <allow_active>yes</allow_active> </defaults> </action> </policyconfig> |