From 20ab6550fbf88b6e89d7243c08fe1ba12bf44fdf Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Fri, 10 Jan 2020 14:47:40 +0100 Subject: auth-provider: refactor and simplify The auth provider setup is a bit over-engineered. Simplify it by making a single MMAuthProvider object that may or may not use polkit, depending on configure options. This object is also setup as a singleton object using the helper MM_DEFINE_SINGLETON_GETTER(). --- src/mm-auth-provider.c | 198 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 151 insertions(+), 47 deletions(-) (limited to 'src/mm-auth-provider.c') diff --git a/src/mm-auth-provider.c b/src/mm-auth-provider.c index 4d8766c0..bea27d01 100644 --- a/src/mm-auth-provider.c +++ b/src/mm-auth-provider.c @@ -12,75 +12,153 @@ * * Copyright (C) 2010 - 2012 Red Hat, Inc. * Copyright (C) 2012 Google, Inc. + * Copyright (C) 2020 Aleksander Morgado */ +#include + +#include +#include "mm-errors-types.h" +#include "mm-log.h" +#include "mm-utils.h" #include "mm-auth-provider.h" -G_DEFINE_TYPE (MMAuthProvider, mm_auth_provider, G_TYPE_OBJECT) +#if defined WITH_POLKIT +# include +#endif -/*****************************************************************************/ +struct _MMAuthProvider { + GObject parent; +#if defined WITH_POLKIT + PolkitAuthority *authority; +#endif +}; -MMAuthProvider * -mm_auth_provider_new (void) -{ - return g_object_new (MM_TYPE_AUTH_PROVIDER, NULL); -} +struct _MMAuthProviderClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE (MMAuthProvider, mm_auth_provider, G_TYPE_OBJECT) /*****************************************************************************/ gboolean -mm_auth_provider_authorize_finish (MMAuthProvider *self, - GAsyncResult *res, - GError **error) +mm_auth_provider_authorize_finish (MMAuthProvider *self, + GAsyncResult *res, + GError **error) { - g_return_val_if_fail (MM_IS_AUTH_PROVIDER (self), FALSE); - - return MM_AUTH_PROVIDER_GET_CLASS (self)->authorize_finish (self, res, error); + return g_task_propagate_boolean (G_TASK (res), error); } -void -mm_auth_provider_authorize (MMAuthProvider *self, - GDBusMethodInvocation *invocation, - const gchar *authorization, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_return_if_fail (MM_IS_AUTH_PROVIDER (self)); - - MM_AUTH_PROVIDER_GET_CLASS (self)->authorize (self, - invocation, - authorization, - cancellable, - callback, - user_data); -} +#if defined WITH_POLKIT -/*****************************************************************************/ +typedef struct { + PolkitSubject *subject; + gchar *authorization; + GDBusMethodInvocation *invocation; +} AuthorizeContext; -static gboolean -authorize_finish (MMAuthProvider *self, - GAsyncResult *res, - GError **error) +static void +authorize_context_free (AuthorizeContext *ctx) { - /* Null auth; everything passes */ - return TRUE; + g_object_unref (ctx->invocation); + g_object_unref (ctx->subject); + g_free (ctx->authorization); + g_free (ctx); } static void -authorize (MMAuthProvider *self, - GDBusMethodInvocation *invocation, - const gchar *authorization, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +check_authorization_ready (PolkitAuthority *authority, + GAsyncResult *res, + GTask *task) +{ + PolkitAuthorizationResult *pk_result; + GError *error = NULL; + AuthorizeContext *ctx; + + if (g_task_return_error_if_cancelled (task)) { + g_object_unref (task); + return; + } + + ctx = g_task_get_task_data (task); + pk_result = polkit_authority_check_authorization_finish (authority, res, &error); + if (!pk_result) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_FAILED, + "PolicyKit authorization failed: '%s'", + error->message); + g_error_free (error); + } else { + if (polkit_authorization_result_get_is_authorized (pk_result)) + /* Good! */ + g_task_return_boolean (task, TRUE); + else if (polkit_authorization_result_get_is_challenge (pk_result)) + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_UNAUTHORIZED, + "PolicyKit authorization failed: challenge needed for '%s'", + ctx->authorization); + else + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_UNAUTHORIZED, + "PolicyKit authorization failed: not authorized for '%s'", + ctx->authorization); + g_object_unref (pk_result); + } + + g_object_unref (task); +} +#endif + +void +mm_auth_provider_authorize (MMAuthProvider *self, + GDBusMethodInvocation *invocation, + const gchar *authorization, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { GTask *task; - /* Just create the result and complete it */ task = g_task_new (self, cancellable, callback, user_data); + +#if defined WITH_POLKIT + { + 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 (!self->authority) { + g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, + "PolicyKit authorization error: 'authority not found'"); + g_object_unref (task); + return; + } + + ctx = g_new (AuthorizeContext, 1); + ctx->invocation = g_object_ref (invocation); + ctx->authorization = g_strdup (authorization); + ctx->subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (ctx->invocation)); + g_task_set_task_data (task, ctx, (GDestroyNotify)authorize_context_free); + + polkit_authority_check_authorization (self->authority, + ctx->subject, + authorization, + NULL, /* details */ + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + cancellable, + (GAsyncReadyCallback)check_authorization_ready, + task); + } +#else + /* Just create the result and complete it */ g_task_return_boolean (task, TRUE); g_object_unref (task); +#endif } /*****************************************************************************/ @@ -88,12 +166,38 @@ authorize (MMAuthProvider *self, static void mm_auth_provider_init (MMAuthProvider *self) { +#if defined WITH_POLKIT + { + GError *error = NULL; + + self->authority = polkit_authority_get_sync (NULL, &error); + if (!self->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); + } + } +#endif +} + +static void +dispose (GObject *object) +{ +#if defined WITH_POLKIT + g_clear_object (&(MM_AUTH_PROVIDER (object)->authority)); +#endif + + G_OBJECT_CLASS (mm_auth_provider_parent_class)->dispose (object); } static void mm_auth_provider_class_init (MMAuthProviderClass *class) { - /* Virtual methods */ - class->authorize = authorize; - class->authorize_finish = authorize_finish; + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->dispose = dispose; } + +MM_DEFINE_SINGLETON_GETTER (MMAuthProvider, mm_auth_provider_get, MM_TYPE_AUTH_PROVIDER) -- cgit v1.2.3-70-g09d2