blob: e342bbb90b424a1b80a8dd83c0388dd8f0079e1d [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughesf29a6ee2017-06-02 19:50:37 +01002 * Copyright (C) 2015-2017 Richard Hughes <richard@hughsie.com>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuMain"
8
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00009#include "config.h"
10
Richard Hughes481aa2a2018-09-18 20:51:46 +010011#include <xmlb.h>
Richard Hughes9945edb2017-06-19 10:03:55 +010012#include <fwupd.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000013#include <gio/gunixfdlist.h>
14#include <glib/gi18n.h>
Mario Limonciello6754f5a2018-10-11 10:50:03 -050015#include <glib-unix.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000016#include <locale.h>
Richard Hughesf508e762015-02-27 12:49:36 +000017#include <polkit/polkit.h>
Richard Hughes67ec8982015-03-03 11:39:27 +000018#include <stdlib.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000019
Richard Hughes68982c62017-09-13 15:40:14 +010020#include "fwupd-device-private.h"
Richard Hughes1642b3b2017-06-05 17:40:08 +010021#include "fwupd-release-private.h"
Richard Hughes4c369702017-06-16 15:31:38 +010022#include "fwupd-remote-private.h"
Richard Hughesd6db6b42017-04-12 15:03:10 +010023#include "fwupd-resources.h"
Richard Hughes8e9762d2016-03-17 10:14:15 +000024
Richard Hughes943d2c92017-06-21 09:04:39 +010025#include "fu-common.h"
Richard Hughes8bbfdf42015-02-26 22:28:09 +000026#include "fu-debug.h"
Richard Hughes68982c62017-09-13 15:40:14 +010027#include "fu-device-private.h"
Richard Hughes9945edb2017-06-19 10:03:55 +010028#include "fu-engine.h"
Richard Hughes4ad41f02018-05-08 14:35:36 +010029#include "fu-install-task.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000030
Philip Withnallbc339aa2016-11-22 16:13:22 +000031#ifndef HAVE_POLKIT_0_114
Mario Limoncielloa98df552018-04-16 12:15:51 -050032#pragma clang diagnostic push
33#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes60f48c22015-10-08 20:25:51 +010034G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
35G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
Mario Limoncielloa98df552018-04-16 12:15:51 -050036#pragma clang diagnostic pop
Richard Hughes60f48c22015-10-08 20:25:51 +010037#endif
38
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000039typedef struct {
40 GDBusConnection *connection;
41 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000042 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000043 GMainLoop *loop;
Richard Hughesf508e762015-02-27 12:49:36 +000044 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000045 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010046 FuEngine *engine;
Mario Limonciello6754f5a2018-10-11 10:50:03 -050047 gboolean update_in_progress;
48 gboolean pending_sigterm;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000049} FuMainPrivate;
50
Mario Limonciello6754f5a2018-10-11 10:50:03 -050051static gboolean
52fu_main_sigterm_cb (gpointer user_data)
53{
54 FuMainPrivate *priv = (FuMainPrivate *) user_data;
55 if (!priv->update_in_progress) {
56 g_main_loop_quit (priv->loop);
57 return G_SOURCE_REMOVE;
58 }
59 g_warning ("Received SIGTERM during a firmware update, ignoring");
60 priv->pending_sigterm = TRUE;
61 return G_SOURCE_CONTINUE;
62}
63
Richard Hughesd7022b52015-03-11 19:47:06 +000064static void
Richard Hughes9945edb2017-06-19 10:03:55 +010065fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000066{
67 /* not yet connected */
68 if (priv->connection == NULL)
69 return;
70 g_dbus_connection_emit_signal (priv->connection,
71 NULL,
72 FWUPD_DBUS_PATH,
73 FWUPD_DBUS_INTERFACE,
74 "Changed",
75 NULL, NULL);
76}
77
Richard Hughes8ca33782016-04-28 15:04:31 +010078static void
Richard Hughes9945edb2017-06-19 10:03:55 +010079fu_main_engine_device_added_cb (FuEngine *engine,
80 FuDevice *device,
81 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010082{
83 GVariant *val;
84
85 /* not yet connected */
86 if (priv->connection == NULL)
87 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +010088 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +010089 g_dbus_connection_emit_signal (priv->connection,
90 NULL,
91 FWUPD_DBUS_PATH,
92 FWUPD_DBUS_INTERFACE,
93 "DeviceAdded",
Richard Hughese0bd53e2017-09-17 08:29:02 +010094 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +010095}
96
Richard Hughes8ca33782016-04-28 15:04:31 +010097static void
Richard Hughes9945edb2017-06-19 10:03:55 +010098fu_main_engine_device_removed_cb (FuEngine *engine,
99 FuDevice *device,
100 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100101{
102 GVariant *val;
103
104 /* not yet connected */
105 if (priv->connection == NULL)
106 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100107 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100108 g_dbus_connection_emit_signal (priv->connection,
109 NULL,
110 FWUPD_DBUS_PATH,
111 FWUPD_DBUS_INTERFACE,
112 "DeviceRemoved",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100113 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100114}
115
Richard Hughes8ca33782016-04-28 15:04:31 +0100116static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100117fu_main_engine_device_changed_cb (FuEngine *engine,
118 FuDevice *device,
119 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100120{
121 GVariant *val;
122
123 /* not yet connected */
124 if (priv->connection == NULL)
125 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100126 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100127 g_dbus_connection_emit_signal (priv->connection,
128 NULL,
129 FWUPD_DBUS_PATH,
130 FWUPD_DBUS_INTERFACE,
131 "DeviceChanged",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100132 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100133}
134
Richard Hughes773ce982015-03-09 22:40:57 +0000135static void
136fu_main_emit_property_changed (FuMainPrivate *priv,
137 const gchar *property_name,
138 GVariant *property_value)
139{
140 GVariantBuilder builder;
141 GVariantBuilder invalidated_builder;
142
143 /* not yet connected */
Richard Hughes34fcc022018-09-19 16:16:15 +0100144 if (priv->connection == NULL) {
145 g_variant_unref (g_variant_ref_sink (property_value));
Richard Hughes773ce982015-03-09 22:40:57 +0000146 return;
Richard Hughes34fcc022018-09-19 16:16:15 +0100147 }
Richard Hughes773ce982015-03-09 22:40:57 +0000148
149 /* build the dict */
150 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
151 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
152 g_variant_builder_add (&builder,
153 "{sv}",
154 property_name,
155 property_value);
156 g_dbus_connection_emit_signal (priv->connection,
157 NULL,
158 FWUPD_DBUS_PATH,
159 "org.freedesktop.DBus.Properties",
160 "PropertiesChanged",
161 g_variant_new ("(sa{sv}as)",
162 FWUPD_DBUS_INTERFACE,
163 &builder,
164 &invalidated_builder),
165 NULL);
166 g_variant_builder_clear (&builder);
167 g_variant_builder_clear (&invalidated_builder);
168}
169
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100170static void
171fu_main_set_status (FuMainPrivate *priv, FwupdStatus status)
172{
173 g_debug ("Emitting PropertyChanged('Status'='%s')",
174 fwupd_status_to_string (status));
175 fu_main_emit_property_changed (priv, "Status",
176 g_variant_new_uint32 (status));
177}
Richard Hughes773ce982015-03-09 22:40:57 +0000178
Richard Hughes9945edb2017-06-19 10:03:55 +0100179static void
180fu_main_engine_status_changed_cb (FuEngine *engine,
181 FwupdStatus status,
182 FuMainPrivate *priv)
183{
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100184 fu_main_set_status (priv, status);
Richard Hughes75b965d2018-11-15 13:51:21 +0000185
186 /* engine has gone idle */
187 if (status == FWUPD_STATUS_SHUTDOWN)
188 g_main_loop_quit (priv->loop);
Richard Hughes773ce982015-03-09 22:40:57 +0000189}
190
Richard Hughes876c0072016-08-17 14:51:03 +0100191static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100192fu_main_engine_percentage_changed_cb (FuEngine *engine,
193 guint percentage,
194 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100195{
Richard Hughes876c0072016-08-17 14:51:03 +0100196 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
197 fu_main_emit_property_changed (priv, "Percentage",
198 g_variant_new_uint32 (percentage));
199}
200
Mario Limoncielloe3016602018-09-06 11:20:59 -0500201static gboolean
202fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender,
203 FwupdDeviceFlags *flags, GError **error)
204{
205 uid_t calling_uid;
206 g_autoptr(GVariant) value = NULL;
207
208 g_return_val_if_fail (sender != NULL, FALSE);
209 g_return_val_if_fail (flags != NULL, FALSE);
210
211 value = g_dbus_proxy_call_sync (priv->proxy_uid,
212 "GetConnectionUnixUser",
213 g_variant_new ("(s)", sender),
214 G_DBUS_CALL_FLAGS_NONE,
215 2000,
216 NULL,
217 error);
218 if (value == NULL) {
219 g_prefix_error (error, "failed to read user id of caller: ");
220 return FALSE;
221 }
222 g_variant_get (value, "(u)", &calling_uid);
223 if (calling_uid == 0)
224 *flags |= FWUPD_DEVICE_FLAG_TRUSTED;
225
226 return TRUE;
227}
228
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000229static GVariant *
Mario Limoncielloe3016602018-09-06 11:20:59 -0500230fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender,
231 GPtrArray *devices, GError **error)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000232{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000233 GVariantBuilder builder;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500234 FwupdDeviceFlags flags = FWUPD_DEVICE_FLAG_NONE;
235
Richard Hughes9945edb2017-06-19 10:03:55 +0100236 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000237 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500238
239 if (!fu_main_get_device_flags_for_sender (priv, sender, &flags, error))
Richard Hughes83cce1b2018-09-10 16:42:30 +0100240 return NULL;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500241
Richard Hughesf192bf02016-07-22 08:26:43 +0100242 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100243 FuDevice *device = g_ptr_array_index (devices, i);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500244 GVariant *tmp = fwupd_device_to_variant_full (FWUPD_DEVICE (device),
245 flags);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000246 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000247 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100248 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000249}
250
Richard Hughes9945edb2017-06-19 10:03:55 +0100251static GVariant *
252fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100253{
Richard Hughes9945edb2017-06-19 10:03:55 +0100254 GVariantBuilder builder;
255 g_return_val_if_fail (results->len > 0, NULL);
256 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
257 for (guint i = 0; i < results->len; i++) {
258 FwupdRelease *rel = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100259 GVariant *tmp = fwupd_release_to_variant (rel);
Richard Hughes9945edb2017-06-19 10:03:55 +0100260 g_variant_builder_add_value (&builder, tmp);
261 }
262 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100263}
264
Richard Hughes9945edb2017-06-19 10:03:55 +0100265static GVariant *
266fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100267{
Richard Hughes9945edb2017-06-19 10:03:55 +0100268 GVariantBuilder builder;
269 g_return_val_if_fail (remotes->len > 0, NULL);
270 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
271 for (guint i = 0; i < remotes->len; i++) {
272 FwupdRemote *remote = g_ptr_array_index (remotes, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100273 GVariant *tmp = fwupd_remote_to_variant (remote);
Richard Hughes9945edb2017-06-19 10:03:55 +0100274 g_variant_builder_add_value (&builder, tmp);
275 }
276 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100277}
278
Richard Hughes9945edb2017-06-19 10:03:55 +0100279static GVariant *
280fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000281{
Richard Hughes9945edb2017-06-19 10:03:55 +0100282 GVariantBuilder builder;
283 g_return_val_if_fail (results->len > 0, NULL);
284 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
285 for (guint i = 0; i < results->len; i++) {
Richard Hughes93b15762017-09-15 11:05:23 +0100286 FwupdDevice *result = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100287 GVariant *tmp = fwupd_device_to_variant (result);
Richard Hughes9945edb2017-06-19 10:03:55 +0100288 g_variant_builder_add_value (&builder, tmp);
289 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100290 return g_variant_new ("(aa{sv})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000291}
292
Richard Hughesf508e762015-02-27 12:49:36 +0000293typedef struct {
294 GDBusMethodInvocation *invocation;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100295 PolkitSubject *subject;
296 GPtrArray *install_tasks;
297 GPtrArray *action_ids;
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000298 GPtrArray *checksums;
Richard Hughes3d607622019-03-07 16:59:27 +0000299 guint64 flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100300 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000301 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100302 gchar *device_id;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100303 gchar *remote_id;
304 gchar *key;
305 gchar *value;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100306 XbSilo *silo;
Richard Hughesf508e762015-02-27 12:49:36 +0000307} FuMainAuthHelper;
308
Richard Hughesf508e762015-02-27 12:49:36 +0000309static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100310fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000311{
Richard Hughes4ced4662016-08-26 11:02:31 +0100312 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100313 g_bytes_unref (helper->blob_cab);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100314 if (helper->subject != NULL)
315 g_object_unref (helper->subject);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100316 if (helper->silo != NULL)
317 g_object_unref (helper->silo);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100318 if (helper->install_tasks != NULL)
319 g_ptr_array_unref (helper->install_tasks);
320 if (helper->action_ids != NULL)
321 g_ptr_array_unref (helper->action_ids);
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000322 if (helper->checksums != NULL)
323 g_ptr_array_unref (helper->checksums);
Richard Hughes9945edb2017-06-19 10:03:55 +0100324 g_free (helper->device_id);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100325 g_free (helper->remote_id);
326 g_free (helper->key);
327 g_free (helper->value);
Richard Hughes67ec8982015-03-03 11:39:27 +0000328 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000329 g_free (helper);
330}
331
Mario Limoncielloa98df552018-04-16 12:15:51 -0500332#pragma clang diagnostic push
333#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes9945edb2017-06-19 10:03:55 +0100334G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -0500335#pragma clang diagnostic pop
Richard Hughes9945edb2017-06-19 10:03:55 +0100336
337/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000338static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100339fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000340{
Richard Hughes9945edb2017-06-19 10:03:55 +0100341 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000342 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100343 g_autofree gchar *message = g_strdup ((*error)->message);
344 g_clear_error (error);
345 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100346 FWUPD_ERROR,
347 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100348 "Could not check for auth: %s", message);
349 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000350 }
351
352 /* did not auth */
353 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100354 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100355 FWUPD_ERROR,
356 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100357 "Failed to obtain auth");
358 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000359 }
360
361 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100362 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100363}
364
Richard Hughesdf7950b2016-01-31 10:18:40 +0000365static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100366fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100367{
Richard Hughes9945edb2017-06-19 10:03:55 +0100368 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
369 g_autoptr(GError) error = NULL;
370 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100371
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100372
Richard Hughes9945edb2017-06-19 10:03:55 +0100373 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100374 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100375 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
376 res, &error);
377 if (!fu_main_authorization_is_valid (auth, &error)) {
378 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100379 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100380 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100381
382 /* authenticated */
383 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
384 g_dbus_method_invocation_return_gerror (helper->invocation, error);
385 return;
386 }
387
388 /* success */
389 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100390}
391
392static void
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000393fu_main_authorize_set_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data)
394{
395 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
396 g_autoptr(GError) error = NULL;
397 g_autoptr(PolkitAuthorizationResult) auth = NULL;
398
399 /* get result */
400 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
401 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
402 res, &error);
403 if (!fu_main_authorization_is_valid (auth, &error)) {
404 g_dbus_method_invocation_return_gerror (helper->invocation, error);
405 return;
406 }
407
408 /* success */
409 for (guint i = 0; i < helper->checksums->len; i++) {
410 const gchar *csum = g_ptr_array_index (helper->checksums, i);
411 fu_engine_add_approved_firmware (helper->priv->engine, csum);
412 }
413 g_dbus_method_invocation_return_value (helper->invocation, NULL);
414}
415
416static void
Richard Hughes3d607622019-03-07 16:59:27 +0000417fu_main_authorize_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data)
418{
419 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
420 g_autofree gchar *sig = NULL;
421 g_autoptr(GError) error = NULL;
422 g_autoptr(PolkitAuthorizationResult) auth = NULL;
423
424 /* get result */
425 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
426 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
427 res, &error);
428 if (!fu_main_authorization_is_valid (auth, &error)) {
429 g_dbus_method_invocation_return_gerror (helper->invocation, error);
430 return;
431 }
432
433 /* authenticated */
434 sig = fu_engine_self_sign (helper->priv->engine, helper->value, helper->flags, &error);
435 if (sig == NULL) {
436 g_dbus_method_invocation_return_gerror (helper->invocation, error);
437 return;
438 }
439
440 /* success */
441 g_dbus_method_invocation_return_value (helper->invocation, g_variant_new ("(s)", sig));
442}
443
444static void
Mario Limonciello96a0dd52019-02-25 13:50:03 -0600445fu_main_authorize_activate_cb (GObject *source, GAsyncResult *res, gpointer user_data)
446{
447 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
448 g_autoptr(GError) error = NULL;
449 g_autoptr(PolkitAuthorizationResult) auth = NULL;
450
451 /* get result */
452 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
453 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
454 res, &error);
455 if (!fu_main_authorization_is_valid (auth, &error)) {
456 g_dbus_method_invocation_return_gerror (helper->invocation, error);
457 return;
458 }
459
460 /* authenticated */
461 if (!fu_engine_activate (helper->priv->engine, helper->device_id, &error)) {
462 g_dbus_method_invocation_return_gerror (helper->invocation, error);
463 return;
464 }
465
466 /* success */
467 g_dbus_method_invocation_return_value (helper->invocation, NULL);
468}
469
470static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100471fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000472{
Richard Hughes9945edb2017-06-19 10:03:55 +0100473 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
474 g_autoptr(GError) error = NULL;
475 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000476
Richard Hughes9945edb2017-06-19 10:03:55 +0100477 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100478 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100479 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
480 res, &error);
481 if (!fu_main_authorization_is_valid (auth, &error)) {
482 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000483 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100484 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000485
Richard Hughes9945edb2017-06-19 10:03:55 +0100486 /* authenticated */
487 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
488 g_dbus_method_invocation_return_gerror (helper->invocation, error);
489 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000490 }
491
492 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100493 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100494}
495
Richard Hughes9945edb2017-06-19 10:03:55 +0100496static void
Richard Hughesa6bd5582017-09-07 14:32:22 +0100497fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data)
498{
499 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
500 g_autoptr(GError) error = NULL;
501 g_autoptr(PolkitAuthorizationResult) auth = NULL;
502
503 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100504 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100505 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
506 res, &error);
507 if (!fu_main_authorization_is_valid (auth, &error)) {
508 g_dbus_method_invocation_return_gerror (helper->invocation, error);
509 return;
510 }
511
512 /* authenticated */
513 if (!fu_engine_modify_remote (helper->priv->engine,
514 helper->remote_id,
515 helper->key,
516 helper->value,
517 &error)) {
518 g_dbus_method_invocation_return_gerror (helper->invocation, error);
519 return;
520 }
521
522 /* success */
523 g_dbus_method_invocation_return_value (helper->invocation, NULL);
524}
525
Richard Hughes4ad41f02018-05-08 14:35:36 +0100526static void fu_main_authorize_install_queue (FuMainAuthHelper *helper);
527
Richard Hughesa6bd5582017-09-07 14:32:22 +0100528static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100529fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000530{
Richard Hughes9945edb2017-06-19 10:03:55 +0100531 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100532 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100533 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000534
Richard Hughes9945edb2017-06-19 10:03:55 +0100535 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100536 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100537 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
538 res, &error);
539 if (!fu_main_authorization_is_valid (auth, &error)) {
540 g_dbus_method_invocation_return_gerror (helper->invocation, error);
541 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000542 }
543
Richard Hughes4ad41f02018-05-08 14:35:36 +0100544 /* do the next authentication action ID */
545 fu_main_authorize_install_queue (g_steal_pointer (&helper));
546}
547
548static void
549fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref)
550{
551 FuMainPrivate *priv = helper_ref->priv;
552 g_autoptr(FuMainAuthHelper) helper = helper_ref;
553 g_autoptr(GError) error = NULL;
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500554 gboolean ret;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100555
556 /* still more things to to authenticate */
557 if (helper->action_ids->len > 0) {
558 g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0));
559 g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject);
560 g_ptr_array_remove_index (helper->action_ids, 0);
561 polkit_authority_check_authorization (priv->authority, subject,
562 action_id, NULL,
563 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
564 NULL,
565 fu_main_authorize_install_cb,
566 g_steal_pointer (&helper));
Richard Hughes9945edb2017-06-19 10:03:55 +0100567 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100568 }
569
Richard Hughes4ad41f02018-05-08 14:35:36 +0100570 /* all authenticated, so install all the things */
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500571 priv->update_in_progress = TRUE;
572 ret = fu_engine_install_tasks (helper->priv->engine,
573 helper->install_tasks,
574 helper->blob_cab,
575 helper->flags,
576 &error);
577 priv->update_in_progress = FALSE;
578 if (priv->pending_sigterm)
579 g_main_loop_quit (priv->loop);
580 if (!ret) {
Richard Hughesdbd8c762018-06-15 20:31:40 +0100581 g_dbus_method_invocation_return_gerror (helper->invocation, error);
582 return;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100583 }
584
Richard Hughes654f6b82016-04-25 12:29:48 +0100585 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100586 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100587}
588
Richard Hughes4ad41f02018-05-08 14:35:36 +0100589#if !GLIB_CHECK_VERSION(2,54,0)
590static gboolean
591g_ptr_array_find (GPtrArray *haystack, gconstpointer needle, guint *index_)
592{
593 for (guint i = 0; i < haystack->len; i++) {
594 gconstpointer *tmp = g_ptr_array_index (haystack, i);
595 if (tmp == needle) {
596 if (index_ != NULL) {
597 *index_ = i;
598 return TRUE;
599 }
600 }
601 }
602 return FALSE;
603}
604#endif
605
Richard Hughes9f86ade2018-05-10 21:11:22 +0100606static gint
607fu_main_install_task_sort_cb (gconstpointer a, gconstpointer b)
608{
609 FuInstallTask *task_a = *((FuInstallTask **) a);
610 FuInstallTask *task_b = *((FuInstallTask **) b);
Richard Hughesc02cb832018-05-20 10:31:04 +0100611 return fu_install_task_compare (task_a, task_b);
Richard Hughes9f86ade2018-05-10 21:11:22 +0100612}
613
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500614static GPtrArray *
615fu_main_get_device_family (FuMainAuthHelper *helper, GError **error)
616{
617 FuDevice *parent;
618 GPtrArray *children;
619 g_autoptr(FuDevice) device = NULL;
620 g_autoptr(GPtrArray) devices_possible = NULL;
621
622 /* get the device */
623 device = fu_engine_get_device (helper->priv->engine, helper->device_id, error);
624 if (device == NULL)
625 return NULL;
626
627 /* device itself */
628 devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
629 g_ptr_array_add (devices_possible, g_object_ref (device));
630
631 /* add device children */
632 children = fu_device_get_children (device);
633 for (guint i = 0; i < children->len; i++) {
634 FuDevice *child = g_ptr_array_index (children, i);
635 g_ptr_array_add (devices_possible, g_object_ref (child));
636 }
637
638 /* add parent and siblings, not including the device itself */
639 parent = fu_device_get_parent (device);
640 if (parent != NULL) {
641 GPtrArray *siblings = fu_device_get_children (parent);
642 g_ptr_array_add (devices_possible, g_object_ref (parent));
643 for (guint i = 0; i < siblings->len; i++) {
644 FuDevice *sibling = g_ptr_array_index (siblings, i);
645 if (sibling == device)
646 continue;
647 g_ptr_array_add (devices_possible, g_object_ref (sibling));
648 }
649 }
650
651 /* success */
652 return g_steal_pointer (&devices_possible);
653}
654
Richard Hughes4ad41f02018-05-08 14:35:36 +0100655static gboolean
656fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error)
657{
658 FuMainPrivate *priv = helper_ref->priv;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100659 g_autoptr(FuMainAuthHelper) helper = helper_ref;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100660 g_autoptr(GPtrArray) components = NULL;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100661 g_autoptr(GPtrArray) devices_possible = NULL;
662 g_autoptr(GPtrArray) errors = NULL;
663
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500664 /* get a list of devices that in some way match the device_id */
Richard Hughes4ad41f02018-05-08 14:35:36 +0100665 if (g_strcmp0 (helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) {
666 devices_possible = fu_engine_get_devices (priv->engine, error);
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500667 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100668 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100669 } else {
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500670 devices_possible = fu_main_get_device_family (helper, error);
671 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100672 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100673 }
674
Richard Hughes481aa2a2018-09-18 20:51:46 +0100675 /* parse silo */
676 helper->silo = fu_engine_get_silo_from_blob (priv->engine,
677 helper->blob_cab,
678 error);
679 if (helper->silo == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100680 return FALSE;
681
Richard Hughes481aa2a2018-09-18 20:51:46 +0100682 /* for each component in the silo */
Mario Limonciello51ddf182019-01-26 00:31:58 -0600683 components = xb_silo_query (helper->silo, "components/component", 0, error);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100684 if (components == NULL)
685 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100686 helper->action_ids = g_ptr_array_new_with_free_func (g_free);
687 helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
688 errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100689 for (guint i = 0; i < components->len; i++) {
690 XbNode *component = g_ptr_array_index (components, i);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100691
692 /* do any devices pass the requirements */
693 for (guint j = 0; j < devices_possible->len; j++) {
694 FuDevice *device = g_ptr_array_index (devices_possible, j);
695 const gchar *action_id;
696 g_autoptr(FuInstallTask) task = NULL;
697 g_autoptr(GError) error_local = NULL;
698
699 /* is this component valid for the device */
Richard Hughes481aa2a2018-09-18 20:51:46 +0100700 task = fu_install_task_new (device, component);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100701 if (!fu_engine_check_requirements (priv->engine,
Richard Hughes1d1f5cf2018-05-19 23:06:03 +0100702 task,
703 helper->flags,
Richard Hughes4ad41f02018-05-08 14:35:36 +0100704 &error_local)) {
705 g_debug ("requirement on %s:%s failed: %s",
706 fu_device_get_id (device),
Richard Hughes481aa2a2018-09-18 20:51:46 +0100707 xb_node_query_text (component, "id", NULL),
Richard Hughes4ad41f02018-05-08 14:35:36 +0100708 error_local->message);
709 g_ptr_array_add (errors, g_steal_pointer (&error_local));
710 continue;
711 }
712
Mario Limonciello7a3df4b2019-01-31 10:27:22 -0600713 /* if component should have an update message from CAB */
714 fu_device_incorporate_from_component (device, component);
715
Richard Hughes4ad41f02018-05-08 14:35:36 +0100716 /* get the action IDs for the valid device */
717 action_id = fu_install_task_get_action_id (task);
718 if (!g_ptr_array_find (helper->action_ids, action_id, NULL))
719 g_ptr_array_add (helper->action_ids, g_strdup (action_id));
720 g_ptr_array_add (helper->install_tasks, g_steal_pointer (&task));
721 }
722 }
723
Richard Hughes9f86ade2018-05-10 21:11:22 +0100724 /* order the install tasks by the device priority */
725 g_ptr_array_sort (helper->install_tasks, fu_main_install_task_sort_cb);
726
Richard Hughes4ad41f02018-05-08 14:35:36 +0100727 /* nothing suitable */
728 if (helper->install_tasks->len == 0) {
Richard Hughese82eef32018-05-20 10:41:26 +0100729 GError *error_tmp = fu_common_error_array_get_best (errors);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100730 g_propagate_error (error, error_tmp);
731 return FALSE;
732 }
733
734 /* authenticate all things in the action_ids */
735 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
736 fu_main_authorize_install_queue (g_steal_pointer (&helper));
737 return TRUE;
738}
739
Richard Hughesb6f79552017-11-11 07:58:17 +0000740static gboolean
741fu_main_device_id_valid (const gchar *device_id, GError **error)
742{
743 if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0)
744 return TRUE;
745 if (device_id != NULL && strlen (device_id) >= 4)
746 return TRUE;
747 g_set_error (error,
748 FWUPD_ERROR,
749 FWUPD_ERROR_INTERNAL,
750 "invalid device ID: %s",
751 device_id);
752 return FALSE;
753}
754
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000755static void
756fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
757 const gchar *object_path, const gchar *interface_name,
758 const gchar *method_name, GVariant *parameters,
759 GDBusMethodInvocation *invocation, gpointer user_data)
760{
761 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100762 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100763 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000764
Richard Hughes75b965d2018-11-15 13:51:21 +0000765 /* activity */
766 fu_engine_idle_reset (priv->engine);
767
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000768 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100769 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000770 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100771 devices = fu_engine_get_devices (priv->engine, &error);
772 if (devices == NULL) {
773 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100774 return;
775 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500776 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
777 if (val == NULL) {
778 g_dbus_method_invocation_return_gerror (invocation, error);
779 return;
780 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100781 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100782 return;
783 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100784 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100785 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100786 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100787 g_variant_get (parameters, "(&s)", &device_id);
788 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000789 if (!fu_main_device_id_valid (device_id, &error)) {
790 g_dbus_method_invocation_return_gerror (invocation, error);
791 return;
792 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100793 releases = fu_engine_get_releases (priv->engine, device_id, &error);
794 if (releases == NULL) {
795 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100796 return;
797 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100798 val = fu_main_release_array_to_variant (releases);
799 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100800 return;
801 }
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000802 if (g_strcmp0 (method_name, "GetApprovedFirmware") == 0) {
803 GVariantBuilder builder;
804 GPtrArray *checksums = fu_engine_get_approved_firmware (priv->engine);
805 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
806 for (guint i = 0; i < checksums->len; i++) {
807 const gchar *checksum = g_ptr_array_index (checksums, i);
808 g_variant_builder_add_value (&builder, g_variant_new_string (checksum));
809 }
810 val = g_variant_builder_end (&builder);
811 g_dbus_method_invocation_return_value (invocation,
812 g_variant_new_tuple (&val, 1));
813 return;
814 }
815 if (g_strcmp0 (method_name, "SetApprovedFirmware") == 0) {
816 g_autofree gchar *checksums_str = NULL;
817 g_auto(GStrv) checksums = NULL;
818 g_autoptr(FuMainAuthHelper) helper = NULL;
819 g_autoptr(PolkitSubject) subject = NULL;
820
821 g_variant_get (parameters, "(^as)", &checksums);
822 checksums_str = g_strjoinv (",", checksums);
823 g_debug ("Called %s(%s)", method_name, checksums_str);
824
825 /* authenticate */
826 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
827 helper = g_new0 (FuMainAuthHelper, 1);
828 helper->priv = priv;
829 helper->invocation = g_object_ref (invocation);
830 helper->checksums = g_ptr_array_new_with_free_func (g_free);
831 for (guint i = 0; checksums[i] != NULL; i++)
832 g_ptr_array_add (helper->checksums, g_strdup (checksums[i]));
833 subject = polkit_system_bus_name_new (sender);
834 polkit_authority_check_authorization (priv->authority, subject,
835 "org.freedesktop.fwupd.set-approved-firmware",
836 NULL,
837 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
838 NULL,
839 fu_main_authorize_set_approved_firmware_cb,
840 g_steal_pointer (&helper));
841 return;
842 }
Richard Hughes3d607622019-03-07 16:59:27 +0000843 if (g_strcmp0 (method_name, "SelfSign") == 0) {
844 GVariant *prop_value;
845 gchar *prop_key;
846 g_autofree gchar *value = NULL;
847 g_autoptr(FuMainAuthHelper) helper = NULL;
848 g_autoptr(PolkitSubject) subject = NULL;
849 g_autoptr(GVariantIter) iter = NULL;
850
851 g_variant_get (parameters, "(sa{sv})", &value, &iter);
852 g_debug ("Called %s(%s)", method_name, value);
853
854 /* get flags */
855 helper = g_new0 (FuMainAuthHelper, 1);
856 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
857 g_debug ("got option %s", prop_key);
858 if (g_strcmp0 (prop_key, "add-timestamp") == 0 &&
859 g_variant_get_boolean (prop_value) == TRUE)
860 helper->flags |= FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP;
861 if (g_strcmp0 (prop_key, "add-cert") == 0 &&
862 g_variant_get_boolean (prop_value) == TRUE)
863 helper->flags |= FU_KEYRING_SIGN_FLAG_ADD_CERT;
864 g_variant_unref (prop_value);
865 }
866
867 /* authenticate */
868 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
869 helper->priv = priv;
870 helper->value = g_steal_pointer (&value);
871 helper->invocation = g_object_ref (invocation);
872 subject = polkit_system_bus_name_new (sender);
873 polkit_authority_check_authorization (priv->authority, subject,
874 "org.freedesktop.fwupd.self-sign",
875 NULL,
876 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
877 NULL,
878 fu_main_authorize_self_sign_cb,
879 g_steal_pointer (&helper));
880 return;
881 }
Richard Hughes97284b12017-09-13 17:07:58 +0100882 if (g_strcmp0 (method_name, "GetDowngrades") == 0) {
883 const gchar *device_id;
884 g_autoptr(GPtrArray) releases = NULL;
885 g_variant_get (parameters, "(&s)", &device_id);
886 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000887 if (!fu_main_device_id_valid (device_id, &error)) {
888 g_dbus_method_invocation_return_gerror (invocation, error);
889 return;
890 }
Richard Hughes97284b12017-09-13 17:07:58 +0100891 releases = fu_engine_get_downgrades (priv->engine, device_id, &error);
892 if (releases == NULL) {
893 g_dbus_method_invocation_return_gerror (invocation, error);
894 return;
895 }
896 val = fu_main_release_array_to_variant (releases);
897 g_dbus_method_invocation_return_value (invocation, val);
898 return;
899 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100900 if (g_strcmp0 (method_name, "GetUpgrades") == 0) {
901 const gchar *device_id;
902 g_autoptr(GPtrArray) releases = NULL;
903 g_variant_get (parameters, "(&s)", &device_id);
904 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000905 if (!fu_main_device_id_valid (device_id, &error)) {
906 g_dbus_method_invocation_return_gerror (invocation, error);
907 return;
908 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100909 releases = fu_engine_get_upgrades (priv->engine, device_id, &error);
910 if (releases == NULL) {
911 g_dbus_method_invocation_return_gerror (invocation, error);
912 return;
913 }
914 val = fu_main_release_array_to_variant (releases);
915 g_dbus_method_invocation_return_value (invocation, val);
916 return;
917 }
Richard Hughes4c369702017-06-16 15:31:38 +0100918 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100919 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100920 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100921 remotes = fu_engine_get_remotes (priv->engine, &error);
922 if (remotes == NULL) {
923 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100924 return;
925 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100926 val = fu_main_remote_array_to_variant (remotes);
927 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100928 return;
929 }
Richard Hughes476363a2018-01-11 10:08:58 +0000930 if (g_strcmp0 (method_name, "GetHistory") == 0) {
931 g_autoptr(GPtrArray) devices = NULL;
932 g_debug ("Called %s()", method_name);
933 devices = fu_engine_get_history (priv->engine, &error);
934 if (devices == NULL) {
935 g_dbus_method_invocation_return_gerror (invocation, error);
936 return;
937 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500938 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
939 if (val == NULL) {
940 g_dbus_method_invocation_return_gerror (invocation, error);
941 return;
942 }
Richard Hughes476363a2018-01-11 10:08:58 +0000943 g_dbus_method_invocation_return_value (invocation, val);
944 return;
945 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000946 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100947 const gchar *device_id;
948 g_variant_get (parameters, "(&s)", &device_id);
949 g_debug ("Called %s(%s)", method_name, device_id);
950 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
951 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000952 return;
953 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100954 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000955 return;
956 }
Richard Hughes6b222952018-01-11 10:20:48 +0000957 if (g_strcmp0 (method_name, "ModifyDevice") == 0) {
958 const gchar *device_id;
959 const gchar *key = NULL;
960 const gchar *value = NULL;
961
962 /* check the id exists */
963 g_variant_get (parameters, "(&s&s&s)", &device_id, &key, &value);
964 g_debug ("Called %s(%s,%s=%s)", method_name, device_id, key, value);
965 if (!fu_engine_modify_device (priv->engine, device_id, key, value, &error)) {
966 g_dbus_method_invocation_return_gerror (invocation, error);
967 return;
968 }
969 g_dbus_method_invocation_return_value (invocation, NULL);
970 return;
971 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000972 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100973 const gchar *device_id = NULL;
Richard Hughes93b15762017-09-15 11:05:23 +0100974 g_autoptr(FwupdDevice) result = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100975 g_variant_get (parameters, "(&s)", &device_id);
976 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000977 if (!fu_main_device_id_valid (device_id, &error)) {
978 g_dbus_method_invocation_return_gerror (invocation, error);
979 return;
980 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100981 result = fu_engine_get_results (priv->engine, device_id, &error);
982 if (result == NULL) {
983 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000984 return;
985 }
Richard Hughese0bd53e2017-09-17 08:29:02 +0100986 val = fwupd_device_to_variant (result);
987 g_dbus_method_invocation_return_value (invocation,
988 g_variant_new_tuple (&val, 1));
Richard Hughes0e883ee2015-03-18 17:22:33 +0000989 return;
990 }
Richard Hughesba73c762017-09-15 14:31:17 +0100991 if (g_strcmp0 (method_name, "UpdateMetadata") == 0) {
Richard Hughes1b50d962017-06-02 12:23:00 +0100992 GDBusMessage *message;
993 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +0100994 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +0100995 gint fd_data;
996 gint fd_sig;
997
Richard Hughes9945edb2017-06-19 10:03:55 +0100998 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
999 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +01001000
Richard Hughes5935ebd2017-06-16 15:40:31 +01001001 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +01001002 message = g_dbus_method_invocation_get_message (invocation);
1003 fd_list = g_dbus_message_get_unix_fd_list (message);
1004 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
1005 g_set_error (&error,
1006 FWUPD_ERROR,
1007 FWUPD_ERROR_INTERNAL,
1008 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001009 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001010 return;
1011 }
1012 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
1013 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001014 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001015 return;
1016 }
1017 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
1018 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001019 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001020 return;
1021 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001022
1023 /* store new metadata (will close the fds when done) */
1024 if (!fu_engine_update_metadata (priv->engine, remote_id,
1025 fd_data, fd_sig, &error)) {
Richard Hughesf3d46c62017-11-28 14:01:30 +00001026 g_prefix_error (&error, "Failed to update metadata for %s: ", remote_id);
Richard Hughes9945edb2017-06-19 10:03:55 +01001027 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +01001028 return;
1029 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001030 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +01001031 return;
1032 }
Richard Hughes9a410ce2016-02-28 15:58:54 +00001033 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001034 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001035 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +00001036 g_autoptr(PolkitSubject) subject = NULL;
1037
Richard Hughes9945edb2017-06-19 10:03:55 +01001038 g_variant_get (parameters, "(&s)", &device_id);
1039 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001040 if (!fu_main_device_id_valid (device_id, &error)) {
1041 g_dbus_method_invocation_return_gerror (invocation, error);
1042 return;
1043 }
Richard Hughesfe5cc902016-06-29 10:00:00 +01001044
Richard Hughes9a410ce2016-02-28 15:58:54 +00001045 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001046 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes9945edb2017-06-19 10:03:55 +01001047 helper = g_new0 (FuMainAuthHelper, 1);
1048 helper->priv = priv;
1049 helper->invocation = g_object_ref (invocation);
1050 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +00001051 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +01001052 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +00001053 "org.freedesktop.fwupd.device-unlock",
1054 NULL,
1055 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1056 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +01001057 fu_main_authorize_unlock_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001058 g_steal_pointer (&helper));
Richard Hughes9a410ce2016-02-28 15:58:54 +00001059 return;
1060 }
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001061 if (g_strcmp0 (method_name, "Activate") == 0) {
1062 const gchar *device_id = NULL;
1063 g_autoptr(FuMainAuthHelper) helper = NULL;
1064 g_autoptr(PolkitSubject) subject = NULL;
1065
1066 g_variant_get (parameters, "(&s)", &device_id);
1067 g_debug ("Called %s(%s)", method_name, device_id);
1068 if (!fu_main_device_id_valid (device_id, &error)) {
1069 g_dbus_method_invocation_return_gerror (invocation, error);
1070 return;
1071 }
1072
1073 /* authenticate */
1074 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
1075 helper = g_new0 (FuMainAuthHelper, 1);
1076 helper->priv = priv;
1077 helper->invocation = g_object_ref (invocation);
1078 helper->device_id = g_strdup (device_id);
1079 subject = polkit_system_bus_name_new (sender);
1080 polkit_authority_check_authorization (priv->authority, subject,
1081 "org.freedesktop.fwupd.device-activate",
1082 NULL,
1083 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1084 NULL,
1085 fu_main_authorize_activate_cb,
1086 g_steal_pointer (&helper));
1087 return;
1088 }
Richard Hughesa6bd5582017-09-07 14:32:22 +01001089 if (g_strcmp0 (method_name, "ModifyRemote") == 0) {
Richard Hughesa6bd5582017-09-07 14:32:22 +01001090 const gchar *remote_id = NULL;
1091 const gchar *key = NULL;
1092 const gchar *value = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001093 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughesa6bd5582017-09-07 14:32:22 +01001094 g_autoptr(PolkitSubject) subject = NULL;
1095
1096 /* check the id exists */
1097 g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value);
1098 g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value);
1099
1100 /* create helper object */
1101 helper = g_new0 (FuMainAuthHelper, 1);
1102 helper->invocation = g_object_ref (invocation);
1103 helper->remote_id = g_strdup (remote_id);
1104 helper->key = g_strdup (key);
1105 helper->value = g_strdup (value);
1106 helper->priv = priv;
1107
1108 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001109 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughesa6bd5582017-09-07 14:32:22 +01001110 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -05001111 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughesa6bd5582017-09-07 14:32:22 +01001112 "org.freedesktop.fwupd.modify-remote",
1113 NULL,
1114 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1115 NULL,
1116 fu_main_authorize_modify_remote_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001117 g_steal_pointer (&helper));
Richard Hughesa6bd5582017-09-07 14:32:22 +01001118 return;
1119 }
Richard Hughes29c220d2016-12-14 17:09:54 +00001120 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001121 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001122 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +00001123 g_autoptr(PolkitSubject) subject = NULL;
1124
1125 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +01001126 g_variant_get (parameters, "(&s)", &device_id);
1127 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001128 if (!fu_main_device_id_valid (device_id, &error)) {
1129 g_dbus_method_invocation_return_gerror (invocation, error);
1130 return;
1131 }
Richard Hughes29c220d2016-12-14 17:09:54 +00001132
Richard Hughes9945edb2017-06-19 10:03:55 +01001133 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +00001134 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +00001135 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +01001136 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +00001137 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +00001138
1139 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001140 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes29c220d2016-12-14 17:09:54 +00001141 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -05001142 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes29c220d2016-12-14 17:09:54 +00001143 "org.freedesktop.fwupd.verify-update",
1144 NULL,
1145 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1146 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +01001147 fu_main_authorize_verify_update_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001148 g_steal_pointer (&helper));
Richard Hughes29c220d2016-12-14 17:09:54 +00001149 return;
1150 }
Richard Hughesa043c2e2015-06-29 08:43:18 +01001151 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001152 const gchar *device_id = NULL;
1153 g_variant_get (parameters, "(&s)", &device_id);
1154 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001155 if (!fu_main_device_id_valid (device_id, &error)) {
1156 g_dbus_method_invocation_return_gerror (invocation, error);
1157 return;
1158 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001159 if (!fu_engine_verify (priv->engine, device_id, &error)) {
1160 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001161 return;
1162 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001163 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001164 return;
1165 }
Richard Hughes63a407a2015-07-22 08:54:14 +01001166 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001167 GVariant *prop_value;
Richard Hughes9945edb2017-06-19 10:03:55 +01001168 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +00001169 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001170 gint32 fd_handle = 0;
1171 gint fd;
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001172 guint64 archive_size_max;
Richard Hughes9945edb2017-06-19 10:03:55 +01001173 GDBusMessage *message;
1174 GUnixFDList *fd_list;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001175 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001176 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001177
1178 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +01001179 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
1180 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughesb6f79552017-11-11 07:58:17 +00001181 if (!fu_main_device_id_valid (device_id, &error)) {
1182 g_dbus_method_invocation_return_gerror (invocation, error);
1183 return;
1184 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001185
Richard Hughes9945edb2017-06-19 10:03:55 +01001186 /* create helper object */
1187 helper = g_new0 (FuMainAuthHelper, 1);
1188 helper->invocation = g_object_ref (invocation);
1189 helper->device_id = g_strdup (device_id);
1190 helper->priv = priv;
1191
1192 /* get flags */
1193 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001194 g_debug ("got option %s", prop_key);
1195 if (g_strcmp0 (prop_key, "offline") == 0 &&
1196 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001197 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +00001198 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
1199 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001200 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +00001201 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
1202 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001203 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -05001204 if (g_strcmp0 (prop_key, "force") == 0 &&
1205 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001206 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes76e0f942018-05-14 16:24:00 +01001207 if (g_strcmp0 (prop_key, "no-history") == 0 &&
1208 g_variant_get_boolean (prop_value) == TRUE)
1209 helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY;
Richard Hughes1ffde6c2015-03-02 22:44:48 +00001210 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +00001211 }
1212
Richard Hughes9945edb2017-06-19 10:03:55 +01001213
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001214 /* get the fd */
1215 message = g_dbus_method_invocation_get_message (invocation);
1216 fd_list = g_dbus_message_get_unix_fd_list (message);
1217 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001218 g_set_error (&error,
1219 FWUPD_ERROR,
1220 FWUPD_ERROR_INTERNAL,
1221 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001222 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001223 return;
1224 }
Richard Hughes7419e962016-11-22 19:48:06 +00001225 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001226 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001227 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001228 return;
1229 }
1230
Richard Hughes9945edb2017-06-19 10:03:55 +01001231 /* parse the cab file before authenticating so we can work out
1232 * what action ID to use, for instance, if this is trusted --
1233 * this will also close the fd when done */
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001234 archive_size_max = fu_engine_get_archive_size_max (priv->engine);
1235 helper->blob_cab = fu_common_get_contents_fd (fd, archive_size_max, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001236 if (helper->blob_cab == NULL) {
1237 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +01001238 return;
1239 }
Richard Hughes4ad41f02018-05-08 14:35:36 +01001240
1241 /* install all the things in the store */
1242 helper->subject = polkit_system_bus_name_new (sender);
1243 if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001244 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +00001245 return;
1246 }
1247
Richard Hughes4ad41f02018-05-08 14:35:36 +01001248 /* async return */
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001249 return;
1250 }
Richard Hughes07f963a2017-09-15 14:28:47 +01001251 if (g_strcmp0 (method_name, "GetDetails") == 0) {
Richard Hughes7289a6b2016-05-29 09:27:47 +01001252 GDBusMessage *message;
1253 GUnixFDList *fd_list;
1254 gint32 fd_handle = 0;
1255 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +01001256 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +01001257
1258 /* get parameters */
1259 g_variant_get (parameters, "(h)", &fd_handle);
1260 g_debug ("Called %s(%i)", method_name, fd_handle);
1261
1262 /* get the fd */
1263 message = g_dbus_method_invocation_get_message (invocation);
1264 fd_list = g_dbus_message_get_unix_fd_list (message);
1265 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001266 g_set_error (&error,
1267 FWUPD_ERROR,
1268 FWUPD_ERROR_INTERNAL,
1269 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001270 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001271 return;
1272 }
Richard Hughes7419e962016-11-22 19:48:06 +00001273 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001274 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001275 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001276 return;
1277 }
1278
Richard Hughes9945edb2017-06-19 10:03:55 +01001279 /* get details about the file (will close the fd when done) */
Richard Hughes07f963a2017-09-15 14:28:47 +01001280 results = fu_engine_get_details (priv->engine, fd, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001281 if (results == NULL) {
1282 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001283 return;
1284 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001285 val = fu_main_result_array_to_variant (results);
1286 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001287 return;
1288 }
Richard Hughes060af612016-08-17 17:32:34 +01001289 g_set_error (&error,
1290 G_DBUS_ERROR,
1291 G_DBUS_ERROR_UNKNOWN_METHOD,
1292 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +01001293 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001294}
1295
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001296static GVariant *
1297fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
1298 const gchar *object_path, const gchar *interface_name,
1299 const gchar *property_name, GError **error,
1300 gpointer user_data)
1301{
Richard Hughes773ce982015-03-09 22:40:57 +00001302 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1303
Richard Hughes75b965d2018-11-15 13:51:21 +00001304 /* activity */
1305 fu_engine_idle_reset (priv->engine);
1306
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001307 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
1308 return g_variant_new_string (VERSION);
1309
Richard Hughesf425d292019-01-18 17:57:39 +00001310 if (g_strcmp0 (property_name, "Tainted") == 0)
1311 return g_variant_new_boolean (fu_engine_get_tainted (priv->engine));
1312
Richard Hughes773ce982015-03-09 22:40:57 +00001313 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +01001314 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +00001315
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001316 /* return an error */
1317 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +00001318 G_DBUS_ERROR,
1319 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001320 "failed to get daemon property %s",
1321 property_name);
1322 return NULL;
1323}
1324
Richard Hughesfd468842015-04-22 16:44:08 +01001325static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001326fu_main_on_bus_acquired_cb (GDBusConnection *connection,
1327 const gchar *name,
1328 gpointer user_data)
1329{
1330 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1331 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +01001332 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001333 static const GDBusInterfaceVTable interface_vtable = {
1334 fu_main_daemon_method_call,
1335 fu_main_daemon_get_property,
1336 NULL
1337 };
1338
1339 priv->connection = g_object_ref (connection);
1340 registration_id = g_dbus_connection_register_object (connection,
1341 FWUPD_DBUS_PATH,
1342 priv->introspection_daemon->interfaces[0],
1343 &interface_vtable,
1344 priv, /* user_data */
1345 NULL, /* user_data_free_func */
1346 NULL); /* GError** */
1347 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +00001348
1349 /* connect to D-Bus directly */
1350 priv->proxy_uid =
1351 g_dbus_proxy_new_sync (priv->connection,
1352 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1353 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1354 NULL,
1355 "org.freedesktop.DBus",
1356 "/org/freedesktop/DBus",
1357 "org.freedesktop.DBus",
1358 NULL,
1359 &error);
1360 if (priv->proxy_uid == NULL) {
1361 g_warning ("cannot connect to DBus: %s", error->message);
1362 return;
1363 }
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001364}
1365
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001366static void
1367fu_main_on_name_acquired_cb (GDBusConnection *connection,
1368 const gchar *name,
1369 gpointer user_data)
1370{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001371 g_debug ("FuMain: acquired name: %s", name);
1372}
1373
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001374static void
1375fu_main_on_name_lost_cb (GDBusConnection *connection,
1376 const gchar *name,
1377 gpointer user_data)
1378{
1379 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1380 g_debug ("FuMain: lost name: %s", name);
1381 g_main_loop_quit (priv->loop);
1382}
1383
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001384static gboolean
1385fu_main_timed_exit_cb (gpointer user_data)
1386{
1387 GMainLoop *loop = (GMainLoop *) user_data;
1388 g_main_loop_quit (loop);
1389 return G_SOURCE_REMOVE;
1390}
1391
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001392static GDBusNodeInfo *
1393fu_main_load_introspection (const gchar *filename, GError **error)
1394{
Richard Hughes46832432015-09-11 13:43:15 +01001395 g_autoptr(GBytes) data = NULL;
1396 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001397
1398 /* lookup data */
1399 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
1400 data = g_resource_lookup_data (fu_get_resource (),
1401 path,
1402 G_RESOURCE_LOOKUP_FLAGS_NONE,
1403 error);
1404 if (data == NULL)
1405 return NULL;
1406
1407 /* build introspection from XML */
1408 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
1409}
1410
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001411static void
1412fu_main_private_free (FuMainPrivate *priv)
1413{
1414 if (priv->loop != NULL)
1415 g_main_loop_unref (priv->loop);
1416 if (priv->owner_id > 0)
1417 g_bus_unown_name (priv->owner_id);
1418 if (priv->proxy_uid != NULL)
1419 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +01001420 if (priv->engine != NULL)
1421 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001422 if (priv->connection != NULL)
1423 g_object_unref (priv->connection);
1424 if (priv->authority != NULL)
1425 g_object_unref (priv->authority);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001426 if (priv->introspection_daemon != NULL)
1427 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001428 g_free (priv);
1429}
1430
Mario Limoncielloa98df552018-04-16 12:15:51 -05001431#pragma clang diagnostic push
1432#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001433G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -05001434#pragma clang diagnostic pop
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001435
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001436int
1437main (int argc, char *argv[])
1438{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001439 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001440 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001441 const GOptionEntry options[] = {
1442 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
1443 /* TRANSLATORS: exit after we've started up, used for user profiling */
1444 _("Exit after a small delay"), NULL },
1445 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
1446 /* TRANSLATORS: exit straight away, used for automatic profiling */
1447 _("Exit after the engine has loaded"), NULL },
1448 { NULL}
1449 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001450 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001451 g_autoptr(GError) error = NULL;
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001452 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001453
1454 setlocale (LC_ALL, "");
1455
1456 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1457 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1458 textdomain (GETTEXT_PACKAGE);
1459
1460 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +01001461 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001462 context = g_option_context_new (NULL);
1463 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001464 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +00001465 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001466 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001467 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1468 g_printerr ("Failed to parse command line: %s\n", error->message);
1469 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001470 }
1471
1472 /* create new objects */
1473 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001474 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001475
Richard Hughes9945edb2017-06-19 10:03:55 +01001476 /* load engine */
Richard Hughes5b5f6552018-05-18 10:22:39 +01001477 priv->engine = fu_engine_new (FU_APP_FLAGS_NONE);
Richard Hughes9945edb2017-06-19 10:03:55 +01001478 g_signal_connect (priv->engine, "changed",
1479 G_CALLBACK (fu_main_engine_changed_cb),
1480 priv);
1481 g_signal_connect (priv->engine, "device-added",
1482 G_CALLBACK (fu_main_engine_device_added_cb),
1483 priv);
1484 g_signal_connect (priv->engine, "device-removed",
1485 G_CALLBACK (fu_main_engine_device_removed_cb),
1486 priv);
1487 g_signal_connect (priv->engine, "device-changed",
1488 G_CALLBACK (fu_main_engine_device_changed_cb),
1489 priv);
1490 g_signal_connect (priv->engine, "status-changed",
1491 G_CALLBACK (fu_main_engine_status_changed_cb),
1492 priv);
1493 g_signal_connect (priv->engine, "percentage-changed",
1494 G_CALLBACK (fu_main_engine_percentage_changed_cb),
1495 priv);
Richard Hughesc8cc77c2019-03-07 11:57:24 +00001496 if (!fu_engine_load (priv->engine, FU_ENGINE_LOAD_FLAG_NONE, &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001497 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001498 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +01001499 }
1500
Mario Limonciello6754f5a2018-10-11 10:50:03 -05001501 g_unix_signal_add_full (G_PRIORITY_DEFAULT,
1502 SIGTERM, fu_main_sigterm_cb,
1503 priv, NULL);
1504
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001505 /* load introspection from file */
1506 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1507 &error);
1508 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001509 g_printerr ("Failed to load introspection: %s\n", error->message);
1510 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001511 }
1512
Richard Hughesf508e762015-02-27 12:49:36 +00001513 /* get authority */
1514 priv->authority = polkit_authority_get_sync (NULL, &error);
1515 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001516 g_printerr ("Failed to load authority: %s\n", error->message);
1517 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +00001518 }
1519
Richard Hughesebae3962018-09-09 13:40:49 +01001520 /* own the object */
1521 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1522 FWUPD_DBUS_SERVICE,
1523 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1524 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1525 fu_main_on_bus_acquired_cb,
1526 fu_main_on_name_acquired_cb,
1527 fu_main_on_name_lost_cb,
1528 priv, NULL);
1529
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001530 /* Only timeout and close the mainloop if we have specified it
1531 * on the command line */
1532 if (immediate_exit)
1533 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1534 else if (timed_exit)
1535 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1536
Mario Limonciello46bb4e92019-01-07 09:44:31 -06001537 g_debug ("Started with locale %s", g_getenv ("LANG"));
1538
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001539 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +01001540 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001541 g_main_loop_run (priv->loop);
1542
1543 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001544 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001545}