diff options
Diffstat (limited to 'src/mm-auth-provider-polkit.c')
-rw-r--r-- | src/mm-auth-provider-polkit.c | 232 |
1 files changed, 133 insertions, 99 deletions
diff --git a/src/mm-auth-provider-polkit.c b/src/mm-auth-provider-polkit.c index 05c3bf35..9c1a11ea 100644 --- a/src/mm-auth-provider-polkit.c +++ b/src/mm-auth-provider-polkit.c @@ -10,32 +10,28 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details: * - * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2010 - 2012 Red Hat, Inc. + * Copyright (C) 2012 Google, Inc. */ #include <polkit/polkit.h> #include <config.h> -#include "mm-auth-request-polkit.h" + +#include <libmm-common.h> + +#include "mm-log.h" #include "mm-auth-provider-polkit.h" G_DEFINE_TYPE (MMAuthProviderPolkit, mm_auth_provider_polkit, MM_TYPE_AUTH_PROVIDER) -#define MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_AUTH_PROVIDER_POLKIT, MMAuthProviderPolkitPrivate)) - -typedef struct { +struct _MMAuthProviderPolkitPrivate { PolkitAuthority *authority; - guint auth_changed_id; -} MMAuthProviderPolkitPrivate; - -enum { - PROP_NAME = 1000, }; /*****************************************************************************/ -GObject * +MMAuthProvider * mm_auth_provider_polkit_new (void) { return g_object_new (MM_TYPE_AUTH_PROVIDER_POLKIT, NULL); @@ -43,112 +39,155 @@ mm_auth_provider_polkit_new (void) /*****************************************************************************/ -static void -pk_authority_changed_cb (GObject *object, gpointer user_data) -{ - /* Let clients know they should re-check their authorization */ -} - -/*****************************************************************************/ +typedef struct { + MMAuthProvider *self; + GCancellable *cancellable; + PolkitSubject *subject; + gchar *authorization; + GDBusMethodInvocation *invocation; + GSimpleAsyncResult *result; +} AuthorizeContext; -static MMAuthRequest * -real_create_request (MMAuthProvider *provider, - const char *authorization, - GObject *owner, - GDBusMethodInvocation *context, - MMAuthRequestCb callback, - gpointer callback_data, - GDestroyNotify notify) +static void +authorize_context_complete_and_free (AuthorizeContext *ctx) { - MMAuthProviderPolkitPrivate *priv = MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE (provider); - - return (MMAuthRequest *) mm_auth_request_polkit_new (priv->authority, - authorization, - owner, - context, - callback, - callback_data, - notify); + g_simple_async_result_complete (ctx->result); + g_object_unref (ctx->result); + if (ctx->cancellable) + g_object_unref (ctx->cancellable); + g_object_unref (ctx->invocation); + g_object_unref (ctx->subject); + g_object_unref (ctx->self); + g_free (ctx->authorization); + g_free (ctx); } -/*****************************************************************************/ - -/* Fix for polkit 0.97 and later */ -#if !HAVE_POLKIT_AUTHORITY_GET_SYNC -static inline PolkitAuthority * -polkit_authority_get_sync (GCancellable *cancellable, GError **error) +static gboolean +authorize_finish (MMAuthProvider *self, + GAsyncResult *res, + GError **error) { - PolkitAuthority *authority; - - authority = polkit_authority_get (); - if (!authority) - g_set_error (error, 0, 0, "failed to get the PolicyKit authority"); - return authority; + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); } -#endif static void -mm_auth_provider_polkit_init (MMAuthProviderPolkit *self) +check_authorization_ready (PolkitAuthority *authority, + GAsyncResult *res, + AuthorizeContext *ctx) { - MMAuthProviderPolkitPrivate *priv = MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE (self); - GError *error = NULL; + PolkitAuthorizationResult *pk_result; + GError *error = NULL; + + if (g_cancellable_is_cancelled (ctx->cancellable)) { + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_CANCELLED, + "PolicyKit authorization attempt cancelled"); + authorize_context_complete_and_free (ctx); + return; + } - priv->authority = polkit_authority_get_sync (NULL, &error); - if (priv->authority) { - priv->auth_changed_id = g_signal_connect (priv->authority, - "changed", - G_CALLBACK (pk_authority_changed_cb), - self); + pk_result = polkit_authority_check_authorization_finish (authority, res, &error); + if (!pk_result) { + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "PolicyKit authorization failed: '%s'", + error->message); + g_error_free (error); } else { - g_warning ("%s: failed to create PolicyKit authority: (%d) %s", - __func__, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); + if (polkit_authorization_result_get_is_authorized (pk_result)) + /* Good! */ + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + else if (polkit_authorization_result_get_is_challenge (pk_result)) + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_UNAUTHORIZED, + "PolicyKit authorization failed: challenge needed for '%s'", + ctx->authorization); + else + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_UNAUTHORIZED, + "PolicyKit authorization failed: not authorized for '%s'", + ctx->authorization); + g_object_unref (pk_result); } + + authorize_context_complete_and_free (ctx); } static void -set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +authorize (MMAuthProvider *self, + GDBusMethodInvocation *invocation, + const gchar *authorization, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - switch (prop_id) { - case PROP_NAME: - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + MMAuthProviderPolkit *polkit = MM_AUTH_PROVIDER_POLKIT (self); + AuthorizeContext *ctx; + + /* When creating the object, we actually allowed errors when looking for the + * authority. If that is the case, we'll just forbid any incoming + * authentication request */ + if (!polkit->priv->authority) { + g_simple_async_report_error_in_idle (G_OBJECT (self), + callback, + user_data, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "PolicyKit authorization error: " + "'authority not found'"); + return; } + + ctx = g_new (AuthorizeContext, 1); + ctx->self = g_object_ref (self); + ctx->invocation = g_object_ref (invocation); + ctx->authorization = g_strdup (authorization); + ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + authorize); + ctx->subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (ctx->invocation)); + + polkit_authority_check_authorization (polkit->priv->authority, + ctx->subject, + authorization, + NULL, /* details */ + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + ctx->cancellable, + (GAsyncReadyCallback)check_authorization_ready, + ctx); } +/*****************************************************************************/ + static void -get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +mm_auth_provider_polkit_init (MMAuthProviderPolkit *self) { - switch (prop_id) { - case PROP_NAME: - g_value_set_string (value, "polkit"); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + GError *error = NULL; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), + MM_TYPE_AUTH_PROVIDER_POLKIT, + MMAuthProviderPolkitPrivate); + + self->priv->authority = polkit_authority_get_sync (NULL, &error); + if (!self->priv->authority) { + /* NOTE: we failed to create the polkit authority, but we still create + * our AuthProvider. Every request will fail, though. */ + mm_warn ("failed to create PolicyKit authority: '%s'", + error ? error->message : "unknown"); + g_clear_error (&error); } } static void dispose (GObject *object) { - MMAuthProviderPolkit *self = MM_AUTH_PROVIDER_POLKIT (object); - MMAuthProviderPolkitPrivate *priv = MM_AUTH_PROVIDER_POLKIT_GET_PRIVATE (self); - - if (priv->auth_changed_id) { - g_signal_handler_disconnect (priv->authority, priv->auth_changed_id); - priv->auth_changed_id = 0; - } + g_clear_object (MM_AUTH_PROVIDER_POLKIT (object)->priv->authority); G_OBJECT_CLASS (mm_auth_provider_polkit_parent_class)->dispose (object); } @@ -157,17 +196,12 @@ static void mm_auth_provider_polkit_class_init (MMAuthProviderPolkitClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); - MMAuthProviderClass *ap_class = MM_AUTH_PROVIDER_CLASS (class); + MMAuthProviderClass *auth_provider_class = MM_AUTH_PROVIDER_CLASS (class); - mm_auth_provider_polkit_parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (MMAuthProviderPolkitPrivate)); /* Virtual methods */ - object_class->set_property = set_property; - object_class->get_property = get_property; object_class->dispose = dispose; - ap_class->create_request = real_create_request; - - /* Properties */ - g_object_class_override_property (object_class, PROP_NAME, MM_AUTH_PROVIDER_NAME); + auth_provider_class->authorize = authorize; + auth_provider_class->authorize_finish = authorize_finish; } |