From f508e76a7abb2afa655ff94de6e348ff01a3d497 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Fri, 27 Feb 2015 12:49:36 +0000 Subject: [PATCH] Use PolicyKit to check the authorisation of the firmware update --- src/fu-main.c | 173 +++++++++++++++++++++++++++++++++++------ src/fu-provider-uefi.c | 5 +- src/fu-util.c | 4 +- 3 files changed, 158 insertions(+), 24 deletions(-) diff --git a/src/fu-main.c b/src/fu-main.c index b55ac2512..767d2ec8a 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "fu-cleanup.h" #include "fu-common.h" @@ -40,8 +41,14 @@ typedef struct { GMainLoop *loop; GPtrArray *devices; GPtrArray *providers; + PolkitAuthority *authority; } FuMainPrivate; +typedef struct { + FuDevice *device; + FuProvider *provider; +} FuDeviceItem; + /** * fu_main_get_device_list_as_strv: **/ @@ -61,22 +68,112 @@ fu_main_get_device_list_as_strv (FuMainPrivate *priv) } /** - * fu_main_get_device_by_id: + * fu_main_item_free: **/ -static FuDevice * -fu_main_get_device_by_id (FuMainPrivate *priv, const gchar *id) +static void +fu_main_item_free (FuDeviceItem *item) { - FuDevice *device_tmp; + g_object_unref (item->device); + g_object_unref (item->provider); + g_free (item); +} + +/** + * fu_main_get_item_by_id: + **/ +static FuDeviceItem * +fu_main_get_item_by_id (FuMainPrivate *priv, const gchar *id) +{ + FuDeviceItem *item; guint i; for (i = 0; i < priv->devices->len; i++) { - device_tmp = g_ptr_array_index (priv->devices, i); - if (g_strcmp0 (fu_device_get_id (device_tmp), id) == 0) - return device_tmp; + item = g_ptr_array_index (priv->devices, i); + if (g_strcmp0 (fu_device_get_id (item->device), id) == 0) + return item; } return NULL; } +typedef struct { + GDBusMethodInvocation *invocation; + FuMainPrivate *priv; + gint fd; + gchar *id; +} FuMainAuthHelper; + +/** + * fu_main_helper_free: + **/ +static void +fu_main_helper_free (FuMainAuthHelper *helper) +{ + g_object_unref (helper->invocation); + g_free (helper->id); + g_free (helper); +} + +/** + * fu_main_check_authorization_cb: + **/ +static void +fu_main_check_authorization_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + FuMainAuthHelper *helper = (FuMainAuthHelper *) user_data; + FuDeviceItem *item; + _cleanup_error_free_ GError *error = NULL; + _cleanup_object_unref_ PolkitAuthorizationResult *auth = NULL; + + /* get result */ + auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), + res, &error); + if (auth == NULL) { + g_dbus_method_invocation_return_error (helper->invocation, + FU_ERROR, + FU_ERROR_INTERNAL, + "could not check for auth: %s", + error->message); + fu_main_helper_free (helper); + return; + } + + /* did not auth */ + if (!polkit_authorization_result_get_is_authorized (auth)) { + g_dbus_method_invocation_return_error (helper->invocation, + FU_ERROR, + FU_ERROR_INTERNAL, + "failed to obtain auth"); + fu_main_helper_free (helper); + return; + } + + /* check the device still exists */ + item = fu_main_get_item_by_id (helper->priv, helper->id); + if (item == NULL) { + g_dbus_method_invocation_return_error (helper->invocation, + FU_ERROR, + FU_ERROR_INTERNAL, + "device %s was removed", + helper->id); + fu_main_helper_free (helper); + return; + } + + /* run the correct provider that added this */ + if (!fu_provider_update_offline (item->provider, + item->device, + helper->fd, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, + error); + fu_main_helper_free (helper); + return; + } + + /* success */ + g_dbus_method_invocation_return_value (helper->invocation, NULL); + fu_main_helper_free (helper); +} + /** * fu_main_daemon_method_call: **/ @@ -89,11 +186,10 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, FuMainPrivate *priv = (FuMainPrivate *) user_data; GVariant *val; - g_debug ("Called %s()", method_name); - /* return 'as' */ if (g_strcmp0 (method_name, "GetDevices") == 0) { _cleanup_strv_free_ gchar **devices = NULL; + g_debug ("Called %s()", method_name); devices = fu_main_get_device_list_as_strv (priv); val = g_variant_new ("(^as)", devices); g_dbus_method_invocation_return_value (invocation, val); @@ -104,16 +200,19 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, if (g_strcmp0 (method_name, "UpdateOffline") == 0) { GDBusMessage *message; GUnixFDList *fd_list; - FuDevice *device; + FuDeviceItem *item; + FuMainAuthHelper *helper; const gchar *id = NULL; gint32 fd_handle = 0; gint fd; _cleanup_error_free_ GError *error = NULL; + _cleanup_object_unref_ PolkitSubject *subject = NULL; /* check the id exists */ g_variant_get (parameters, "(&sh)", &id, &fd_handle); - device = fu_main_get_device_by_id (priv, id); - if (device == NULL) { + g_debug ("Called %s(%s,%i)", method_name, id, fd_handle); + item = fu_main_get_item_by_id (priv, id); + if (item == NULL) { g_dbus_method_invocation_return_error (invocation, FU_ERROR, FU_ERROR_INTERNAL, @@ -139,13 +238,21 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, return; } - /* TODO: run the correct provider that can handle this */ -// if (!fu_provider_update_offline (provider, device, fd, &error)) { -// g_dbus_method_invocation_return_gerror (invocation, -// error); -// return; -// } - g_dbus_method_invocation_return_value (invocation, NULL); + + /* do authorization async */ + helper = g_new0 (FuMainAuthHelper, 1); + helper->invocation = g_object_ref (invocation); + helper->fd = fd; + helper->id = g_strdup (id); + helper->priv = priv; + subject = polkit_system_bus_name_new (sender); + polkit_authority_check_authorization (priv->authority, subject, + "org.freedesktop.fwupd.update", + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, + fu_main_check_authorization_cb, + helper); return; } @@ -281,7 +388,12 @@ cd_main_provider_device_added_cb (FuProvider *provider, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; - g_ptr_array_add (priv->devices, g_object_ref (device)); + FuDeviceItem *item; + + item = g_new0 (FuDeviceItem, 1); + item->device = g_object_ref (device); + item->provider = g_object_ref (provider); + g_ptr_array_add (priv->devices, item); } /** @@ -293,7 +405,14 @@ cd_main_provider_device_removed_cb (FuProvider *provider, gpointer user_data) { FuMainPrivate *priv = (FuMainPrivate *) user_data; - g_ptr_array_remove (priv->devices, g_object_ref (device)); + FuDeviceItem *item; + + item = fu_main_get_item_by_id (priv, fu_device_get_id (device)); + if (item == NULL) { + g_warning ("can't remove device %s", fu_device_get_id (device)); + return; + } + g_ptr_array_remove (priv->devices, item); } /** @@ -356,7 +475,7 @@ main (int argc, char *argv[]) /* create new objects */ priv = g_new0 (FuMainPrivate, 1); - priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); + priv->devices = g_ptr_array_new_with_free_func ((GDestroyNotify) fu_main_item_free); priv->loop = g_main_loop_new (NULL, FALSE); /* add providers */ @@ -372,6 +491,14 @@ main (int argc, char *argv[]) goto out; } + /* get authority */ + priv->authority = polkit_authority_get_sync (NULL, &error); + if (priv->authority == NULL) { + g_warning ("FuMain: failed to load polkit authority: %s", + error->message); + goto out; + } + /* own the object */ owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, FWUPD_DBUS_SERVICE, @@ -404,6 +531,8 @@ out: g_main_loop_unref (priv->loop); if (priv->connection != NULL) g_object_unref (priv->connection); + if (priv->authority != NULL) + g_object_unref (priv->authority); if (priv->introspection_daemon != NULL) g_dbus_node_info_unref (priv->introspection_daemon); g_ptr_array_unref (priv->providers); diff --git a/src/fu-provider-uefi.c b/src/fu-provider-uefi.c index 82efeb600..5c062f92c 100644 --- a/src/fu-provider-uefi.c +++ b/src/fu-provider-uefi.c @@ -73,7 +73,10 @@ fu_provider_uefi_update_offline (FuProvider *provider, gint fd, GError **error) { +// FuProviderUefi *provider_uefi = FU_PROVIDER_UEFI (provider); + //FIXME + g_debug ("DOING UEFI UPDATE USING FD %i", fd); return TRUE; } @@ -89,7 +92,7 @@ fu_provider_uefi_coldplug (FuProvider *provider, GError **error) //FIXME g_debug ("Adding fake UEFI device"); dev = fu_device_new (); - fu_device_set_id (dev, "819b858e-c52c-402f-80e1-5b311b6c1959"); + fu_device_set_id (dev, "UEFI-819b858e-c52c-402f-80e1-5b311b6c1959-dev1"); fu_provider_emit_added (provider, dev); return TRUE; } diff --git a/src/fu-util.c b/src/fu-util.c index aaebc99e2..334d6b15d 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -281,7 +281,7 @@ fu_util_update_offline (FuUtilPrivate *priv, gchar **values, GError **error) close (fd); /* send message */ - body = g_variant_new ("(sh)", values[0], fd); + body = g_variant_new ("(sh)", values[0], fd > -1 ? 0 : -1); g_dbus_message_set_body (request, body); message = g_dbus_connection_send_message_with_reply_sync (conn, request, @@ -292,6 +292,8 @@ fu_util_update_offline (FuUtilPrivate *priv, gchar **values, GError **error) error); if (message == NULL) return FALSE; + if (g_dbus_message_to_gerror (message, error)) + return FALSE; return TRUE; }