blob: c8d2b055d6bf8385edd709fdfc8beb33016ab589 [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>
Mario Limoncielloeb4c7642019-11-11 10:31:29 -060018#include <stdio.h>
Richard Hughes67ec8982015-03-03 11:39:27 +000019#include <stdlib.h>
Richard Hughesd5aab652020-02-25 12:47:50 +000020#include <jcat.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000021
Richard Hughes68982c62017-09-13 15:40:14 +010022#include "fwupd-device-private.h"
Richard Hughes196c6c62020-05-11 19:42:47 +010023#include "fwupd-security-attr-private.h"
Richard Hughes1642b3b2017-06-05 17:40:08 +010024#include "fwupd-release-private.h"
Richard Hughes4c369702017-06-16 15:31:38 +010025#include "fwupd-remote-private.h"
Richard Hughesd6db6b42017-04-12 15:03:10 +010026#include "fwupd-resources.h"
Richard Hughes8e9762d2016-03-17 10:14:15 +000027
Richard Hughes943d2c92017-06-21 09:04:39 +010028#include "fu-common.h"
Richard Hughes8bbfdf42015-02-26 22:28:09 +000029#include "fu-debug.h"
Richard Hughes68982c62017-09-13 15:40:14 +010030#include "fu-device-private.h"
Richard Hughes9945edb2017-06-19 10:03:55 +010031#include "fu-engine.h"
Richard Hughes4ad41f02018-05-08 14:35:36 +010032#include "fu-install-task.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000033
Philip Withnallbc339aa2016-11-22 16:13:22 +000034#ifndef HAVE_POLKIT_0_114
Mario Limoncielloa98df552018-04-16 12:15:51 -050035#pragma clang diagnostic push
36#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes60f48c22015-10-08 20:25:51 +010037G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
38G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
Mario Limoncielloa98df552018-04-16 12:15:51 -050039#pragma clang diagnostic pop
Richard Hughes60f48c22015-10-08 20:25:51 +010040#endif
41
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000042typedef struct {
43 GDBusConnection *connection;
44 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000045 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000046 GMainLoop *loop;
Richard Hughesf3dc1622019-03-27 12:48:39 +000047 GFileMonitor *argv0_monitor;
Richard Hughes603e4f62019-12-11 13:44:09 +000048#if GLIB_CHECK_VERSION(2,63,3)
49 GMemoryMonitor *memory_monitor;
50#endif
Richard Hughesf508e762015-02-27 12:49:36 +000051 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000052 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010053 FuEngine *engine;
Mario Limonciello6754f5a2018-10-11 10:50:03 -050054 gboolean update_in_progress;
55 gboolean pending_sigterm;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000056} FuMainPrivate;
57
Mario Limonciello6754f5a2018-10-11 10:50:03 -050058static gboolean
59fu_main_sigterm_cb (gpointer user_data)
60{
61 FuMainPrivate *priv = (FuMainPrivate *) user_data;
62 if (!priv->update_in_progress) {
63 g_main_loop_quit (priv->loop);
64 return G_SOURCE_REMOVE;
65 }
66 g_warning ("Received SIGTERM during a firmware update, ignoring");
67 priv->pending_sigterm = TRUE;
68 return G_SOURCE_CONTINUE;
69}
70
Richard Hughesd7022b52015-03-11 19:47:06 +000071static void
Richard Hughes9945edb2017-06-19 10:03:55 +010072fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000073{
74 /* not yet connected */
75 if (priv->connection == NULL)
76 return;
77 g_dbus_connection_emit_signal (priv->connection,
78 NULL,
79 FWUPD_DBUS_PATH,
80 FWUPD_DBUS_INTERFACE,
81 "Changed",
82 NULL, NULL);
83}
84
Richard Hughes8ca33782016-04-28 15:04:31 +010085static void
Richard Hughes9945edb2017-06-19 10:03:55 +010086fu_main_engine_device_added_cb (FuEngine *engine,
87 FuDevice *device,
88 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010089{
90 GVariant *val;
91
92 /* not yet connected */
93 if (priv->connection == NULL)
94 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +010095 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +010096 g_dbus_connection_emit_signal (priv->connection,
97 NULL,
98 FWUPD_DBUS_PATH,
99 FWUPD_DBUS_INTERFACE,
100 "DeviceAdded",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100101 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100102}
103
Richard Hughes8ca33782016-04-28 15:04:31 +0100104static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100105fu_main_engine_device_removed_cb (FuEngine *engine,
106 FuDevice *device,
107 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100108{
109 GVariant *val;
110
111 /* not yet connected */
112 if (priv->connection == NULL)
113 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100114 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100115 g_dbus_connection_emit_signal (priv->connection,
116 NULL,
117 FWUPD_DBUS_PATH,
118 FWUPD_DBUS_INTERFACE,
119 "DeviceRemoved",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100120 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100121}
122
Richard Hughes8ca33782016-04-28 15:04:31 +0100123static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100124fu_main_engine_device_changed_cb (FuEngine *engine,
125 FuDevice *device,
126 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100127{
128 GVariant *val;
129
130 /* not yet connected */
131 if (priv->connection == NULL)
132 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100133 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100134 g_dbus_connection_emit_signal (priv->connection,
135 NULL,
136 FWUPD_DBUS_PATH,
137 FWUPD_DBUS_INTERFACE,
138 "DeviceChanged",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100139 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100140}
141
Richard Hughes773ce982015-03-09 22:40:57 +0000142static void
143fu_main_emit_property_changed (FuMainPrivate *priv,
144 const gchar *property_name,
145 GVariant *property_value)
146{
147 GVariantBuilder builder;
148 GVariantBuilder invalidated_builder;
149
150 /* not yet connected */
Richard Hughes34fcc022018-09-19 16:16:15 +0100151 if (priv->connection == NULL) {
152 g_variant_unref (g_variant_ref_sink (property_value));
Richard Hughes773ce982015-03-09 22:40:57 +0000153 return;
Richard Hughes34fcc022018-09-19 16:16:15 +0100154 }
Richard Hughes773ce982015-03-09 22:40:57 +0000155
156 /* build the dict */
157 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
Richard Hughes8356a832019-03-21 17:04:38 +0000158 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
Richard Hughes773ce982015-03-09 22:40:57 +0000159 g_variant_builder_add (&builder,
160 "{sv}",
161 property_name,
162 property_value);
163 g_dbus_connection_emit_signal (priv->connection,
164 NULL,
165 FWUPD_DBUS_PATH,
166 "org.freedesktop.DBus.Properties",
167 "PropertiesChanged",
168 g_variant_new ("(sa{sv}as)",
169 FWUPD_DBUS_INTERFACE,
170 &builder,
171 &invalidated_builder),
172 NULL);
173 g_variant_builder_clear (&builder);
174 g_variant_builder_clear (&invalidated_builder);
175}
176
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100177static void
178fu_main_set_status (FuMainPrivate *priv, FwupdStatus status)
179{
180 g_debug ("Emitting PropertyChanged('Status'='%s')",
181 fwupd_status_to_string (status));
182 fu_main_emit_property_changed (priv, "Status",
183 g_variant_new_uint32 (status));
184}
Richard Hughes773ce982015-03-09 22:40:57 +0000185
Richard Hughes9945edb2017-06-19 10:03:55 +0100186static void
187fu_main_engine_status_changed_cb (FuEngine *engine,
188 FwupdStatus status,
189 FuMainPrivate *priv)
190{
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100191 fu_main_set_status (priv, status);
Richard Hughes75b965d2018-11-15 13:51:21 +0000192
193 /* engine has gone idle */
194 if (status == FWUPD_STATUS_SHUTDOWN)
195 g_main_loop_quit (priv->loop);
Richard Hughes773ce982015-03-09 22:40:57 +0000196}
197
Richard Hughes876c0072016-08-17 14:51:03 +0100198static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100199fu_main_engine_percentage_changed_cb (FuEngine *engine,
200 guint percentage,
201 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100202{
Richard Hughes876c0072016-08-17 14:51:03 +0100203 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
204 fu_main_emit_property_changed (priv, "Percentage",
205 g_variant_new_uint32 (percentage));
206}
207
Mario Limoncielloe3016602018-09-06 11:20:59 -0500208static gboolean
209fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender,
210 FwupdDeviceFlags *flags, GError **error)
211{
212 uid_t calling_uid;
213 g_autoptr(GVariant) value = NULL;
214
215 g_return_val_if_fail (sender != NULL, FALSE);
216 g_return_val_if_fail (flags != NULL, FALSE);
217
218 value = g_dbus_proxy_call_sync (priv->proxy_uid,
219 "GetConnectionUnixUser",
220 g_variant_new ("(s)", sender),
221 G_DBUS_CALL_FLAGS_NONE,
222 2000,
223 NULL,
224 error);
225 if (value == NULL) {
226 g_prefix_error (error, "failed to read user id of caller: ");
227 return FALSE;
228 }
229 g_variant_get (value, "(u)", &calling_uid);
230 if (calling_uid == 0)
231 *flags |= FWUPD_DEVICE_FLAG_TRUSTED;
232
233 return TRUE;
234}
235
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000236static GVariant *
Mario Limoncielloe3016602018-09-06 11:20:59 -0500237fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender,
238 GPtrArray *devices, GError **error)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000239{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000240 GVariantBuilder builder;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500241 FwupdDeviceFlags flags = FWUPD_DEVICE_FLAG_NONE;
242
Richard Hughes9945edb2017-06-19 10:03:55 +0100243 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000244 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500245
246 if (!fu_main_get_device_flags_for_sender (priv, sender, &flags, error))
Richard Hughes83cce1b2018-09-10 16:42:30 +0100247 return NULL;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500248
Richard Hughesf192bf02016-07-22 08:26:43 +0100249 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100250 FuDevice *device = g_ptr_array_index (devices, i);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500251 GVariant *tmp = fwupd_device_to_variant_full (FWUPD_DEVICE (device),
252 flags);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000253 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000254 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100255 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000256}
257
Richard Hughes9945edb2017-06-19 10:03:55 +0100258static GVariant *
Richard Hughes196c6c62020-05-11 19:42:47 +0100259fu_main_security_attr_array_to_variant (FuMainPrivate *priv, GPtrArray *attrs)
260{
261 GVariantBuilder builder;
262
263 g_return_val_if_fail (attrs->len > 0, NULL);
264 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
265
266 for (guint i = 0; i < attrs->len; i++) {
267 FwupdSecurityAttr *security_attr = g_ptr_array_index (attrs, i);
268 GVariant *tmp = fwupd_security_attr_to_variant (security_attr);
269 g_variant_builder_add_value (&builder, tmp);
270 }
271 return g_variant_new ("(aa{sv})", &builder);
272}
273
274static GVariant *
Richard Hughes9945edb2017-06-19 10:03:55 +0100275fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100276{
Richard Hughes9945edb2017-06-19 10:03:55 +0100277 GVariantBuilder builder;
278 g_return_val_if_fail (results->len > 0, NULL);
279 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
280 for (guint i = 0; i < results->len; i++) {
281 FwupdRelease *rel = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100282 GVariant *tmp = fwupd_release_to_variant (rel);
Richard Hughes9945edb2017-06-19 10:03:55 +0100283 g_variant_builder_add_value (&builder, tmp);
284 }
285 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100286}
287
Richard Hughes9945edb2017-06-19 10:03:55 +0100288static GVariant *
289fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100290{
Richard Hughes9945edb2017-06-19 10:03:55 +0100291 GVariantBuilder builder;
292 g_return_val_if_fail (remotes->len > 0, NULL);
293 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
294 for (guint i = 0; i < remotes->len; i++) {
295 FwupdRemote *remote = g_ptr_array_index (remotes, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100296 GVariant *tmp = fwupd_remote_to_variant (remote);
Richard Hughes9945edb2017-06-19 10:03:55 +0100297 g_variant_builder_add_value (&builder, tmp);
298 }
299 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100300}
301
Richard Hughes9945edb2017-06-19 10:03:55 +0100302static GVariant *
303fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000304{
Richard Hughes9945edb2017-06-19 10:03:55 +0100305 GVariantBuilder builder;
306 g_return_val_if_fail (results->len > 0, NULL);
307 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
308 for (guint i = 0; i < results->len; i++) {
Richard Hughes93b15762017-09-15 11:05:23 +0100309 FwupdDevice *result = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100310 GVariant *tmp = fwupd_device_to_variant (result);
Richard Hughes9945edb2017-06-19 10:03:55 +0100311 g_variant_builder_add_value (&builder, tmp);
312 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100313 return g_variant_new ("(aa{sv})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000314}
315
Richard Hughesf508e762015-02-27 12:49:36 +0000316typedef struct {
317 GDBusMethodInvocation *invocation;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100318 PolkitSubject *subject;
319 GPtrArray *install_tasks;
320 GPtrArray *action_ids;
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000321 GPtrArray *checksums;
Richard Hughes3d607622019-03-07 16:59:27 +0000322 guint64 flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100323 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000324 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100325 gchar *device_id;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100326 gchar *remote_id;
327 gchar *key;
328 gchar *value;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100329 XbSilo *silo;
Richard Hughesf508e762015-02-27 12:49:36 +0000330} FuMainAuthHelper;
331
Richard Hughesf508e762015-02-27 12:49:36 +0000332static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100333fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000334{
Richard Hughes4ced4662016-08-26 11:02:31 +0100335 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100336 g_bytes_unref (helper->blob_cab);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100337 if (helper->subject != NULL)
338 g_object_unref (helper->subject);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100339 if (helper->silo != NULL)
340 g_object_unref (helper->silo);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100341 if (helper->install_tasks != NULL)
342 g_ptr_array_unref (helper->install_tasks);
343 if (helper->action_ids != NULL)
344 g_ptr_array_unref (helper->action_ids);
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000345 if (helper->checksums != NULL)
346 g_ptr_array_unref (helper->checksums);
Richard Hughes9945edb2017-06-19 10:03:55 +0100347 g_free (helper->device_id);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100348 g_free (helper->remote_id);
349 g_free (helper->key);
350 g_free (helper->value);
Richard Hughes67ec8982015-03-03 11:39:27 +0000351 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000352 g_free (helper);
353}
354
Mario Limoncielloa98df552018-04-16 12:15:51 -0500355#pragma clang diagnostic push
356#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes9945edb2017-06-19 10:03:55 +0100357G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -0500358#pragma clang diagnostic pop
Richard Hughes9945edb2017-06-19 10:03:55 +0100359
360/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000361static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100362fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000363{
Richard Hughes9945edb2017-06-19 10:03:55 +0100364 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000365 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100366 g_autofree gchar *message = g_strdup ((*error)->message);
367 g_clear_error (error);
368 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100369 FWUPD_ERROR,
370 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100371 "Could not check for auth: %s", message);
372 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000373 }
374
375 /* did not auth */
376 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100377 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100378 FWUPD_ERROR,
379 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100380 "Failed to obtain auth");
381 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000382 }
383
384 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100385 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100386}
387
Richard Hughesdf7950b2016-01-31 10:18:40 +0000388static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100389fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100390{
Richard Hughes9945edb2017-06-19 10:03:55 +0100391 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
392 g_autoptr(GError) error = NULL;
393 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100394
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100395
Richard Hughes9945edb2017-06-19 10:03:55 +0100396 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100397 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100398 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
399 res, &error);
400 if (!fu_main_authorization_is_valid (auth, &error)) {
401 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100402 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100403 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100404
405 /* authenticated */
406 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
407 g_dbus_method_invocation_return_gerror (helper->invocation, error);
408 return;
409 }
410
411 /* success */
412 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100413}
414
415static void
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000416fu_main_authorize_set_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data)
417{
418 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
419 g_autoptr(GError) error = NULL;
420 g_autoptr(PolkitAuthorizationResult) auth = NULL;
421
422 /* get result */
423 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
424 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
425 res, &error);
426 if (!fu_main_authorization_is_valid (auth, &error)) {
427 g_dbus_method_invocation_return_gerror (helper->invocation, error);
428 return;
429 }
430
431 /* success */
432 for (guint i = 0; i < helper->checksums->len; i++) {
433 const gchar *csum = g_ptr_array_index (helper->checksums, i);
434 fu_engine_add_approved_firmware (helper->priv->engine, csum);
435 }
436 g_dbus_method_invocation_return_value (helper->invocation, NULL);
437}
438
439static void
Richard Hughes3d607622019-03-07 16:59:27 +0000440fu_main_authorize_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data)
441{
442 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
443 g_autofree gchar *sig = NULL;
444 g_autoptr(GError) error = NULL;
445 g_autoptr(PolkitAuthorizationResult) auth = NULL;
446
447 /* get result */
448 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
449 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
450 res, &error);
451 if (!fu_main_authorization_is_valid (auth, &error)) {
452 g_dbus_method_invocation_return_gerror (helper->invocation, error);
453 return;
454 }
455
456 /* authenticated */
457 sig = fu_engine_self_sign (helper->priv->engine, helper->value, helper->flags, &error);
458 if (sig == NULL) {
459 g_dbus_method_invocation_return_gerror (helper->invocation, error);
460 return;
461 }
462
463 /* success */
464 g_dbus_method_invocation_return_value (helper->invocation, g_variant_new ("(s)", sig));
465}
466
467static void
Mario Limonciellobfcf75b2019-04-17 15:05:39 +0100468fu_main_modify_config_cb (GObject *source, GAsyncResult *res, gpointer user_data)
469{
470 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
471 g_autoptr(GError) error = NULL;
472 g_autoptr(PolkitAuthorizationResult) auth = NULL;
473
474 /* get result */
475 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
476 res, &error);
477 if (!fu_main_authorization_is_valid (auth, &error)) {
478 g_dbus_method_invocation_return_gerror (helper->invocation, error);
479 return;
480 }
481
482 if (!fu_engine_modify_config (helper->priv->engine, helper->key, helper->value, &error)) {
483 g_dbus_method_invocation_return_gerror (helper->invocation, error);
484 return;
485 }
486
487 /* success */
488 g_dbus_method_invocation_return_value (helper->invocation, NULL);
489}
490
491static void
Mario Limonciello96a0dd52019-02-25 13:50:03 -0600492fu_main_authorize_activate_cb (GObject *source, GAsyncResult *res, gpointer user_data)
493{
494 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
495 g_autoptr(GError) error = NULL;
496 g_autoptr(PolkitAuthorizationResult) auth = NULL;
497
498 /* get result */
499 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
500 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
501 res, &error);
502 if (!fu_main_authorization_is_valid (auth, &error)) {
503 g_dbus_method_invocation_return_gerror (helper->invocation, error);
504 return;
505 }
506
507 /* authenticated */
508 if (!fu_engine_activate (helper->priv->engine, helper->device_id, &error)) {
509 g_dbus_method_invocation_return_gerror (helper->invocation, error);
510 return;
511 }
512
513 /* success */
514 g_dbus_method_invocation_return_value (helper->invocation, NULL);
515}
516
517static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100518fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000519{
Richard Hughes9945edb2017-06-19 10:03:55 +0100520 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
521 g_autoptr(GError) error = NULL;
522 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000523
Richard Hughes9945edb2017-06-19 10:03:55 +0100524 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100525 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100526 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
527 res, &error);
528 if (!fu_main_authorization_is_valid (auth, &error)) {
529 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000530 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100531 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000532
Richard Hughes9945edb2017-06-19 10:03:55 +0100533 /* authenticated */
534 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
535 g_dbus_method_invocation_return_gerror (helper->invocation, error);
536 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000537 }
538
539 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100540 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100541}
542
Richard Hughes9945edb2017-06-19 10:03:55 +0100543static void
Richard Hughesa6bd5582017-09-07 14:32:22 +0100544fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data)
545{
546 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
547 g_autoptr(GError) error = NULL;
548 g_autoptr(PolkitAuthorizationResult) auth = NULL;
549
550 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100551 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100552 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
553 res, &error);
554 if (!fu_main_authorization_is_valid (auth, &error)) {
555 g_dbus_method_invocation_return_gerror (helper->invocation, error);
556 return;
557 }
558
559 /* authenticated */
560 if (!fu_engine_modify_remote (helper->priv->engine,
561 helper->remote_id,
562 helper->key,
563 helper->value,
564 &error)) {
565 g_dbus_method_invocation_return_gerror (helper->invocation, error);
566 return;
567 }
568
569 /* success */
570 g_dbus_method_invocation_return_value (helper->invocation, NULL);
571}
572
Richard Hughes4ad41f02018-05-08 14:35:36 +0100573static void fu_main_authorize_install_queue (FuMainAuthHelper *helper);
574
Richard Hughesa6bd5582017-09-07 14:32:22 +0100575static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100576fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000577{
Richard Hughes9945edb2017-06-19 10:03:55 +0100578 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100579 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100580 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000581
Richard Hughes9945edb2017-06-19 10:03:55 +0100582 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100583 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100584 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
585 res, &error);
586 if (!fu_main_authorization_is_valid (auth, &error)) {
587 g_dbus_method_invocation_return_gerror (helper->invocation, error);
588 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000589 }
590
Richard Hughes4ad41f02018-05-08 14:35:36 +0100591 /* do the next authentication action ID */
592 fu_main_authorize_install_queue (g_steal_pointer (&helper));
593}
594
595static void
596fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref)
597{
598 FuMainPrivate *priv = helper_ref->priv;
599 g_autoptr(FuMainAuthHelper) helper = helper_ref;
600 g_autoptr(GError) error = NULL;
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500601 gboolean ret;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100602
603 /* still more things to to authenticate */
604 if (helper->action_ids->len > 0) {
605 g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0));
606 g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject);
607 g_ptr_array_remove_index (helper->action_ids, 0);
608 polkit_authority_check_authorization (priv->authority, subject,
609 action_id, NULL,
610 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
611 NULL,
612 fu_main_authorize_install_cb,
613 g_steal_pointer (&helper));
Richard Hughes9945edb2017-06-19 10:03:55 +0100614 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100615 }
616
Richard Hughes4ad41f02018-05-08 14:35:36 +0100617 /* all authenticated, so install all the things */
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500618 priv->update_in_progress = TRUE;
619 ret = fu_engine_install_tasks (helper->priv->engine,
620 helper->install_tasks,
621 helper->blob_cab,
622 helper->flags,
623 &error);
624 priv->update_in_progress = FALSE;
625 if (priv->pending_sigterm)
626 g_main_loop_quit (priv->loop);
627 if (!ret) {
Richard Hughesdbd8c762018-06-15 20:31:40 +0100628 g_dbus_method_invocation_return_gerror (helper->invocation, error);
629 return;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100630 }
631
Richard Hughes654f6b82016-04-25 12:29:48 +0100632 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100633 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100634}
635
Richard Hughes4ad41f02018-05-08 14:35:36 +0100636#if !GLIB_CHECK_VERSION(2,54,0)
637static gboolean
638g_ptr_array_find (GPtrArray *haystack, gconstpointer needle, guint *index_)
639{
640 for (guint i = 0; i < haystack->len; i++) {
641 gconstpointer *tmp = g_ptr_array_index (haystack, i);
642 if (tmp == needle) {
643 if (index_ != NULL) {
644 *index_ = i;
645 return TRUE;
646 }
647 }
648 }
649 return FALSE;
650}
651#endif
652
Richard Hughes9f86ade2018-05-10 21:11:22 +0100653static gint
654fu_main_install_task_sort_cb (gconstpointer a, gconstpointer b)
655{
656 FuInstallTask *task_a = *((FuInstallTask **) a);
657 FuInstallTask *task_b = *((FuInstallTask **) b);
Richard Hughesc02cb832018-05-20 10:31:04 +0100658 return fu_install_task_compare (task_a, task_b);
Richard Hughes9f86ade2018-05-10 21:11:22 +0100659}
660
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500661static GPtrArray *
662fu_main_get_device_family (FuMainAuthHelper *helper, GError **error)
663{
664 FuDevice *parent;
665 GPtrArray *children;
666 g_autoptr(FuDevice) device = NULL;
667 g_autoptr(GPtrArray) devices_possible = NULL;
668
669 /* get the device */
670 device = fu_engine_get_device (helper->priv->engine, helper->device_id, error);
671 if (device == NULL)
672 return NULL;
673
674 /* device itself */
675 devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
676 g_ptr_array_add (devices_possible, g_object_ref (device));
677
678 /* add device children */
679 children = fu_device_get_children (device);
680 for (guint i = 0; i < children->len; i++) {
681 FuDevice *child = g_ptr_array_index (children, i);
682 g_ptr_array_add (devices_possible, g_object_ref (child));
683 }
684
685 /* add parent and siblings, not including the device itself */
686 parent = fu_device_get_parent (device);
687 if (parent != NULL) {
688 GPtrArray *siblings = fu_device_get_children (parent);
689 g_ptr_array_add (devices_possible, g_object_ref (parent));
690 for (guint i = 0; i < siblings->len; i++) {
691 FuDevice *sibling = g_ptr_array_index (siblings, i);
692 if (sibling == device)
693 continue;
694 g_ptr_array_add (devices_possible, g_object_ref (sibling));
695 }
696 }
697
698 /* success */
699 return g_steal_pointer (&devices_possible);
700}
701
Richard Hughes4ad41f02018-05-08 14:35:36 +0100702static gboolean
703fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error)
704{
705 FuMainPrivate *priv = helper_ref->priv;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100706 g_autoptr(FuMainAuthHelper) helper = helper_ref;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100707 g_autoptr(GPtrArray) components = NULL;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100708 g_autoptr(GPtrArray) devices_possible = NULL;
709 g_autoptr(GPtrArray) errors = NULL;
710
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500711 /* get a list of devices that in some way match the device_id */
Richard Hughes4ad41f02018-05-08 14:35:36 +0100712 if (g_strcmp0 (helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) {
713 devices_possible = fu_engine_get_devices (priv->engine, error);
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500714 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100715 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100716 } else {
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500717 devices_possible = fu_main_get_device_family (helper, error);
718 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100719 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100720 }
721
Richard Hughes481aa2a2018-09-18 20:51:46 +0100722 /* parse silo */
723 helper->silo = fu_engine_get_silo_from_blob (priv->engine,
724 helper->blob_cab,
725 error);
726 if (helper->silo == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100727 return FALSE;
728
Richard Hughes481aa2a2018-09-18 20:51:46 +0100729 /* for each component in the silo */
Mario Limonciello51ddf182019-01-26 00:31:58 -0600730 components = xb_silo_query (helper->silo, "components/component", 0, error);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100731 if (components == NULL)
732 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100733 helper->action_ids = g_ptr_array_new_with_free_func (g_free);
734 helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
735 errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100736 for (guint i = 0; i < components->len; i++) {
737 XbNode *component = g_ptr_array_index (components, i);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100738
739 /* do any devices pass the requirements */
740 for (guint j = 0; j < devices_possible->len; j++) {
741 FuDevice *device = g_ptr_array_index (devices_possible, j);
742 const gchar *action_id;
743 g_autoptr(FuInstallTask) task = NULL;
744 g_autoptr(GError) error_local = NULL;
745
746 /* is this component valid for the device */
Richard Hughes481aa2a2018-09-18 20:51:46 +0100747 task = fu_install_task_new (device, component);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100748 if (!fu_engine_check_requirements (priv->engine,
Richard Hughes1d1f5cf2018-05-19 23:06:03 +0100749 task,
Mario Limonciello537da0e2020-03-09 15:38:17 -0500750 helper->flags | FWUPD_INSTALL_FLAG_FORCE,
751 &error_local)) {
752 g_debug ("first pass requirement on %s:%s failed: %s",
753 fu_device_get_id (device),
754 xb_node_query_text (component, "id", NULL),
755 error_local->message);
756 g_ptr_array_add (errors, g_steal_pointer (&error_local));
757 continue;
758 }
759
760 /* make a second pass using possibly updated version format now */
761 fu_engine_md_refresh_device_from_component (priv->engine, device, component);
762 if (!fu_engine_check_requirements (priv->engine,
763 task,
Richard Hughes1d1f5cf2018-05-19 23:06:03 +0100764 helper->flags,
Richard Hughes4ad41f02018-05-08 14:35:36 +0100765 &error_local)) {
Mario Limonciello537da0e2020-03-09 15:38:17 -0500766 g_debug ("second pass requirement on %s:%s failed: %s",
Richard Hughes4ad41f02018-05-08 14:35:36 +0100767 fu_device_get_id (device),
Richard Hughes481aa2a2018-09-18 20:51:46 +0100768 xb_node_query_text (component, "id", NULL),
Richard Hughes4ad41f02018-05-08 14:35:36 +0100769 error_local->message);
770 g_ptr_array_add (errors, g_steal_pointer (&error_local));
771 continue;
772 }
773
Mario Limonciello7a3df4b2019-01-31 10:27:22 -0600774 /* if component should have an update message from CAB */
775 fu_device_incorporate_from_component (device, component);
776
Richard Hughes4ad41f02018-05-08 14:35:36 +0100777 /* get the action IDs for the valid device */
778 action_id = fu_install_task_get_action_id (task);
779 if (!g_ptr_array_find (helper->action_ids, action_id, NULL))
780 g_ptr_array_add (helper->action_ids, g_strdup (action_id));
781 g_ptr_array_add (helper->install_tasks, g_steal_pointer (&task));
782 }
783 }
784
Richard Hughes9f86ade2018-05-10 21:11:22 +0100785 /* order the install tasks by the device priority */
786 g_ptr_array_sort (helper->install_tasks, fu_main_install_task_sort_cb);
787
Richard Hughes4ad41f02018-05-08 14:35:36 +0100788 /* nothing suitable */
789 if (helper->install_tasks->len == 0) {
Richard Hughese82eef32018-05-20 10:41:26 +0100790 GError *error_tmp = fu_common_error_array_get_best (errors);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100791 g_propagate_error (error, error_tmp);
792 return FALSE;
793 }
794
795 /* authenticate all things in the action_ids */
796 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
797 fu_main_authorize_install_queue (g_steal_pointer (&helper));
798 return TRUE;
799}
800
Richard Hughesb6f79552017-11-11 07:58:17 +0000801static gboolean
802fu_main_device_id_valid (const gchar *device_id, GError **error)
803{
804 if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0)
805 return TRUE;
806 if (device_id != NULL && strlen (device_id) >= 4)
807 return TRUE;
808 g_set_error (error,
809 FWUPD_ERROR,
810 FWUPD_ERROR_INTERNAL,
811 "invalid device ID: %s",
812 device_id);
813 return FALSE;
814}
815
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000816static void
817fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
818 const gchar *object_path, const gchar *interface_name,
819 const gchar *method_name, GVariant *parameters,
820 GDBusMethodInvocation *invocation, gpointer user_data)
821{
822 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100823 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100824 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000825
Richard Hughes75b965d2018-11-15 13:51:21 +0000826 /* activity */
827 fu_engine_idle_reset (priv->engine);
828
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000829 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100830 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000831 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100832 devices = fu_engine_get_devices (priv->engine, &error);
833 if (devices == NULL) {
834 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100835 return;
836 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500837 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
838 if (val == NULL) {
839 g_dbus_method_invocation_return_gerror (invocation, error);
840 return;
841 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100842 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100843 return;
844 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100845 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100846 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100847 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100848 g_variant_get (parameters, "(&s)", &device_id);
849 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000850 if (!fu_main_device_id_valid (device_id, &error)) {
851 g_dbus_method_invocation_return_gerror (invocation, error);
852 return;
853 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100854 releases = fu_engine_get_releases (priv->engine, device_id, &error);
855 if (releases == NULL) {
856 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100857 return;
858 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100859 val = fu_main_release_array_to_variant (releases);
860 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100861 return;
862 }
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000863 if (g_strcmp0 (method_name, "GetApprovedFirmware") == 0) {
864 GVariantBuilder builder;
865 GPtrArray *checksums = fu_engine_get_approved_firmware (priv->engine);
866 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
867 for (guint i = 0; i < checksums->len; i++) {
868 const gchar *checksum = g_ptr_array_index (checksums, i);
869 g_variant_builder_add_value (&builder, g_variant_new_string (checksum));
870 }
871 val = g_variant_builder_end (&builder);
872 g_dbus_method_invocation_return_value (invocation,
873 g_variant_new_tuple (&val, 1));
874 return;
875 }
876 if (g_strcmp0 (method_name, "SetApprovedFirmware") == 0) {
877 g_autofree gchar *checksums_str = NULL;
878 g_auto(GStrv) checksums = NULL;
879 g_autoptr(FuMainAuthHelper) helper = NULL;
880 g_autoptr(PolkitSubject) subject = NULL;
881
882 g_variant_get (parameters, "(^as)", &checksums);
883 checksums_str = g_strjoinv (",", checksums);
884 g_debug ("Called %s(%s)", method_name, checksums_str);
885
886 /* authenticate */
887 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
888 helper = g_new0 (FuMainAuthHelper, 1);
889 helper->priv = priv;
890 helper->invocation = g_object_ref (invocation);
891 helper->checksums = g_ptr_array_new_with_free_func (g_free);
892 for (guint i = 0; checksums[i] != NULL; i++)
893 g_ptr_array_add (helper->checksums, g_strdup (checksums[i]));
894 subject = polkit_system_bus_name_new (sender);
895 polkit_authority_check_authorization (priv->authority, subject,
896 "org.freedesktop.fwupd.set-approved-firmware",
897 NULL,
898 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
899 NULL,
900 fu_main_authorize_set_approved_firmware_cb,
901 g_steal_pointer (&helper));
902 return;
903 }
Richard Hughes3d607622019-03-07 16:59:27 +0000904 if (g_strcmp0 (method_name, "SelfSign") == 0) {
905 GVariant *prop_value;
906 gchar *prop_key;
907 g_autofree gchar *value = NULL;
908 g_autoptr(FuMainAuthHelper) helper = NULL;
909 g_autoptr(PolkitSubject) subject = NULL;
910 g_autoptr(GVariantIter) iter = NULL;
911
912 g_variant_get (parameters, "(sa{sv})", &value, &iter);
913 g_debug ("Called %s(%s)", method_name, value);
914
915 /* get flags */
916 helper = g_new0 (FuMainAuthHelper, 1);
917 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
918 g_debug ("got option %s", prop_key);
919 if (g_strcmp0 (prop_key, "add-timestamp") == 0 &&
920 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughesd5aab652020-02-25 12:47:50 +0000921 helper->flags |= JCAT_SIGN_FLAG_ADD_TIMESTAMP;
Richard Hughes3d607622019-03-07 16:59:27 +0000922 if (g_strcmp0 (prop_key, "add-cert") == 0 &&
923 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughesd5aab652020-02-25 12:47:50 +0000924 helper->flags |= JCAT_SIGN_FLAG_ADD_CERT;
Richard Hughes3d607622019-03-07 16:59:27 +0000925 g_variant_unref (prop_value);
926 }
927
928 /* authenticate */
929 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
930 helper->priv = priv;
931 helper->value = g_steal_pointer (&value);
932 helper->invocation = g_object_ref (invocation);
933 subject = polkit_system_bus_name_new (sender);
934 polkit_authority_check_authorization (priv->authority, subject,
935 "org.freedesktop.fwupd.self-sign",
936 NULL,
937 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
938 NULL,
939 fu_main_authorize_self_sign_cb,
940 g_steal_pointer (&helper));
941 return;
942 }
Richard Hughes97284b12017-09-13 17:07:58 +0100943 if (g_strcmp0 (method_name, "GetDowngrades") == 0) {
944 const gchar *device_id;
945 g_autoptr(GPtrArray) releases = NULL;
946 g_variant_get (parameters, "(&s)", &device_id);
947 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000948 if (!fu_main_device_id_valid (device_id, &error)) {
949 g_dbus_method_invocation_return_gerror (invocation, error);
950 return;
951 }
Richard Hughes97284b12017-09-13 17:07:58 +0100952 releases = fu_engine_get_downgrades (priv->engine, device_id, &error);
953 if (releases == NULL) {
954 g_dbus_method_invocation_return_gerror (invocation, error);
955 return;
956 }
957 val = fu_main_release_array_to_variant (releases);
958 g_dbus_method_invocation_return_value (invocation, val);
959 return;
960 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100961 if (g_strcmp0 (method_name, "GetUpgrades") == 0) {
962 const gchar *device_id;
963 g_autoptr(GPtrArray) releases = NULL;
964 g_variant_get (parameters, "(&s)", &device_id);
965 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000966 if (!fu_main_device_id_valid (device_id, &error)) {
967 g_dbus_method_invocation_return_gerror (invocation, error);
968 return;
969 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100970 releases = fu_engine_get_upgrades (priv->engine, device_id, &error);
971 if (releases == NULL) {
972 g_dbus_method_invocation_return_gerror (invocation, error);
973 return;
974 }
975 val = fu_main_release_array_to_variant (releases);
976 g_dbus_method_invocation_return_value (invocation, val);
977 return;
978 }
Richard Hughes4c369702017-06-16 15:31:38 +0100979 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100980 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100981 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100982 remotes = fu_engine_get_remotes (priv->engine, &error);
983 if (remotes == NULL) {
984 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100985 return;
986 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100987 val = fu_main_remote_array_to_variant (remotes);
988 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100989 return;
990 }
Richard Hughes476363a2018-01-11 10:08:58 +0000991 if (g_strcmp0 (method_name, "GetHistory") == 0) {
992 g_autoptr(GPtrArray) devices = NULL;
993 g_debug ("Called %s()", method_name);
994 devices = fu_engine_get_history (priv->engine, &error);
995 if (devices == NULL) {
996 g_dbus_method_invocation_return_gerror (invocation, error);
997 return;
998 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500999 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
1000 if (val == NULL) {
1001 g_dbus_method_invocation_return_gerror (invocation, error);
1002 return;
1003 }
Richard Hughes476363a2018-01-11 10:08:58 +00001004 g_dbus_method_invocation_return_value (invocation, val);
1005 return;
1006 }
Richard Hughes196c6c62020-05-11 19:42:47 +01001007 if (g_strcmp0 (method_name, "GetHostSecurityAttrs") == 0) {
1008 g_autoptr(GPtrArray) attrs = NULL;
1009 g_debug ("Called %s()", method_name);
1010 attrs = fu_engine_get_host_security_attrs (priv->engine, &error);
1011 if (attrs == NULL) {
1012 g_dbus_method_invocation_return_gerror (invocation, error);
1013 return;
1014 }
1015 val = fu_main_security_attr_array_to_variant (priv, attrs);
1016 g_dbus_method_invocation_return_value (invocation, val);
1017 return;
1018 }
Richard Hughes0e883ee2015-03-18 17:22:33 +00001019 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001020 const gchar *device_id;
1021 g_variant_get (parameters, "(&s)", &device_id);
1022 g_debug ("Called %s(%s)", method_name, device_id);
1023 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
1024 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +00001025 return;
1026 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001027 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +00001028 return;
1029 }
Richard Hughes6b222952018-01-11 10:20:48 +00001030 if (g_strcmp0 (method_name, "ModifyDevice") == 0) {
1031 const gchar *device_id;
1032 const gchar *key = NULL;
1033 const gchar *value = NULL;
1034
1035 /* check the id exists */
1036 g_variant_get (parameters, "(&s&s&s)", &device_id, &key, &value);
1037 g_debug ("Called %s(%s,%s=%s)", method_name, device_id, key, value);
1038 if (!fu_engine_modify_device (priv->engine, device_id, key, value, &error)) {
1039 g_dbus_method_invocation_return_gerror (invocation, error);
1040 return;
1041 }
1042 g_dbus_method_invocation_return_value (invocation, NULL);
1043 return;
1044 }
Richard Hughes0e883ee2015-03-18 17:22:33 +00001045 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001046 const gchar *device_id = NULL;
Richard Hughes93b15762017-09-15 11:05:23 +01001047 g_autoptr(FwupdDevice) result = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +01001048 g_variant_get (parameters, "(&s)", &device_id);
1049 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001050 if (!fu_main_device_id_valid (device_id, &error)) {
1051 g_dbus_method_invocation_return_gerror (invocation, error);
1052 return;
1053 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001054 result = fu_engine_get_results (priv->engine, device_id, &error);
1055 if (result == NULL) {
1056 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +00001057 return;
1058 }
Richard Hughese0bd53e2017-09-17 08:29:02 +01001059 val = fwupd_device_to_variant (result);
1060 g_dbus_method_invocation_return_value (invocation,
1061 g_variant_new_tuple (&val, 1));
Richard Hughes0e883ee2015-03-18 17:22:33 +00001062 return;
1063 }
Richard Hughesba73c762017-09-15 14:31:17 +01001064 if (g_strcmp0 (method_name, "UpdateMetadata") == 0) {
Richard Hughes1b50d962017-06-02 12:23:00 +01001065 GDBusMessage *message;
1066 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +01001067 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +01001068 gint fd_data;
1069 gint fd_sig;
1070
Richard Hughes9945edb2017-06-19 10:03:55 +01001071 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
1072 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +01001073
Richard Hughes5935ebd2017-06-16 15:40:31 +01001074 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +01001075 message = g_dbus_method_invocation_get_message (invocation);
1076 fd_list = g_dbus_message_get_unix_fd_list (message);
1077 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
1078 g_set_error (&error,
1079 FWUPD_ERROR,
1080 FWUPD_ERROR_INTERNAL,
1081 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001082 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001083 return;
1084 }
1085 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
1086 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001087 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001088 return;
1089 }
1090 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
1091 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001092 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001093 return;
1094 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001095
1096 /* store new metadata (will close the fds when done) */
1097 if (!fu_engine_update_metadata (priv->engine, remote_id,
1098 fd_data, fd_sig, &error)) {
Richard Hughesf3d46c62017-11-28 14:01:30 +00001099 g_prefix_error (&error, "Failed to update metadata for %s: ", remote_id);
Richard Hughes9945edb2017-06-19 10:03:55 +01001100 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +01001101 return;
1102 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001103 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +01001104 return;
1105 }
Richard Hughes9a410ce2016-02-28 15:58:54 +00001106 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001107 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001108 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +00001109 g_autoptr(PolkitSubject) subject = NULL;
1110
Richard Hughes9945edb2017-06-19 10:03:55 +01001111 g_variant_get (parameters, "(&s)", &device_id);
1112 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001113 if (!fu_main_device_id_valid (device_id, &error)) {
1114 g_dbus_method_invocation_return_gerror (invocation, error);
1115 return;
1116 }
Richard Hughesfe5cc902016-06-29 10:00:00 +01001117
Richard Hughes9a410ce2016-02-28 15:58:54 +00001118 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001119 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes9945edb2017-06-19 10:03:55 +01001120 helper = g_new0 (FuMainAuthHelper, 1);
1121 helper->priv = priv;
1122 helper->invocation = g_object_ref (invocation);
1123 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +00001124 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +01001125 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +00001126 "org.freedesktop.fwupd.device-unlock",
1127 NULL,
1128 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1129 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +01001130 fu_main_authorize_unlock_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001131 g_steal_pointer (&helper));
Richard Hughes9a410ce2016-02-28 15:58:54 +00001132 return;
1133 }
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001134 if (g_strcmp0 (method_name, "Activate") == 0) {
1135 const gchar *device_id = NULL;
1136 g_autoptr(FuMainAuthHelper) helper = NULL;
1137 g_autoptr(PolkitSubject) subject = NULL;
1138
1139 g_variant_get (parameters, "(&s)", &device_id);
1140 g_debug ("Called %s(%s)", method_name, device_id);
1141 if (!fu_main_device_id_valid (device_id, &error)) {
1142 g_dbus_method_invocation_return_gerror (invocation, error);
1143 return;
1144 }
1145
1146 /* authenticate */
1147 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
1148 helper = g_new0 (FuMainAuthHelper, 1);
1149 helper->priv = priv;
1150 helper->invocation = g_object_ref (invocation);
1151 helper->device_id = g_strdup (device_id);
1152 subject = polkit_system_bus_name_new (sender);
1153 polkit_authority_check_authorization (priv->authority, subject,
1154 "org.freedesktop.fwupd.device-activate",
1155 NULL,
1156 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1157 NULL,
1158 fu_main_authorize_activate_cb,
1159 g_steal_pointer (&helper));
1160 return;
1161 }
Mario Limonciellobfcf75b2019-04-17 15:05:39 +01001162 if (g_strcmp0 (method_name, "ModifyConfig") == 0) {
1163 g_autofree gchar *key = NULL;
1164 g_autofree gchar *value = NULL;
1165 g_autoptr(FuMainAuthHelper) helper = NULL;
1166 g_autoptr(PolkitSubject) subject = NULL;
1167
1168 g_variant_get (parameters, "(ss)", &key, &value);
1169 g_debug ("Called %s(%s=%s)", method_name, key, value);
1170
1171 /* authenticate */
1172 helper = g_new0 (FuMainAuthHelper, 1);
1173 helper->priv = priv;
1174 helper->key = g_steal_pointer (&key);
1175 helper->value = g_steal_pointer (&value);
1176 helper->invocation = g_object_ref (invocation);
1177 subject = polkit_system_bus_name_new (sender);
1178 polkit_authority_check_authorization (priv->authority, subject,
1179 "org.freedesktop.fwupd.modify-config",
1180 NULL,
1181 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1182 NULL,
1183 fu_main_modify_config_cb,
1184 g_steal_pointer (&helper));
1185 return;
1186 }
Richard Hughesa6bd5582017-09-07 14:32:22 +01001187 if (g_strcmp0 (method_name, "ModifyRemote") == 0) {
Richard Hughesa6bd5582017-09-07 14:32:22 +01001188 const gchar *remote_id = NULL;
1189 const gchar *key = NULL;
1190 const gchar *value = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001191 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughesa6bd5582017-09-07 14:32:22 +01001192 g_autoptr(PolkitSubject) subject = NULL;
1193
1194 /* check the id exists */
1195 g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value);
1196 g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value);
1197
1198 /* create helper object */
1199 helper = g_new0 (FuMainAuthHelper, 1);
1200 helper->invocation = g_object_ref (invocation);
1201 helper->remote_id = g_strdup (remote_id);
1202 helper->key = g_strdup (key);
1203 helper->value = g_strdup (value);
1204 helper->priv = priv;
1205
1206 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001207 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughesa6bd5582017-09-07 14:32:22 +01001208 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -05001209 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughesa6bd5582017-09-07 14:32:22 +01001210 "org.freedesktop.fwupd.modify-remote",
1211 NULL,
1212 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1213 NULL,
1214 fu_main_authorize_modify_remote_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001215 g_steal_pointer (&helper));
Richard Hughesa6bd5582017-09-07 14:32:22 +01001216 return;
1217 }
Richard Hughes29c220d2016-12-14 17:09:54 +00001218 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001219 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001220 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +00001221 g_autoptr(PolkitSubject) subject = NULL;
1222
1223 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +01001224 g_variant_get (parameters, "(&s)", &device_id);
1225 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001226 if (!fu_main_device_id_valid (device_id, &error)) {
1227 g_dbus_method_invocation_return_gerror (invocation, error);
1228 return;
1229 }
Richard Hughes29c220d2016-12-14 17:09:54 +00001230
Richard Hughes9945edb2017-06-19 10:03:55 +01001231 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +00001232 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +00001233 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +01001234 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +00001235 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +00001236
1237 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001238 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes29c220d2016-12-14 17:09:54 +00001239 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -05001240 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes29c220d2016-12-14 17:09:54 +00001241 "org.freedesktop.fwupd.verify-update",
1242 NULL,
1243 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1244 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +01001245 fu_main_authorize_verify_update_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001246 g_steal_pointer (&helper));
Richard Hughes29c220d2016-12-14 17:09:54 +00001247 return;
1248 }
Richard Hughesa043c2e2015-06-29 08:43:18 +01001249 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001250 const gchar *device_id = NULL;
1251 g_variant_get (parameters, "(&s)", &device_id);
1252 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001253 if (!fu_main_device_id_valid (device_id, &error)) {
1254 g_dbus_method_invocation_return_gerror (invocation, error);
1255 return;
1256 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001257 if (!fu_engine_verify (priv->engine, device_id, &error)) {
1258 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001259 return;
1260 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001261 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001262 return;
1263 }
Richard Hughes63a407a2015-07-22 08:54:14 +01001264 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001265 GVariant *prop_value;
Richard Hughes9945edb2017-06-19 10:03:55 +01001266 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +00001267 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001268 gint32 fd_handle = 0;
1269 gint fd;
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001270 guint64 archive_size_max;
Richard Hughes9945edb2017-06-19 10:03:55 +01001271 GDBusMessage *message;
1272 GUnixFDList *fd_list;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001273 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001274 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001275
1276 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +01001277 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
1278 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughesb6f79552017-11-11 07:58:17 +00001279 if (!fu_main_device_id_valid (device_id, &error)) {
1280 g_dbus_method_invocation_return_gerror (invocation, error);
1281 return;
1282 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001283
Richard Hughes9945edb2017-06-19 10:03:55 +01001284 /* create helper object */
1285 helper = g_new0 (FuMainAuthHelper, 1);
1286 helper->invocation = g_object_ref (invocation);
1287 helper->device_id = g_strdup (device_id);
1288 helper->priv = priv;
1289
1290 /* get flags */
1291 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001292 g_debug ("got option %s", prop_key);
1293 if (g_strcmp0 (prop_key, "offline") == 0 &&
1294 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001295 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +00001296 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
1297 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001298 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +00001299 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
1300 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001301 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -05001302 if (g_strcmp0 (prop_key, "force") == 0 &&
1303 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001304 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes76e0f942018-05-14 16:24:00 +01001305 if (g_strcmp0 (prop_key, "no-history") == 0 &&
1306 g_variant_get_boolean (prop_value) == TRUE)
1307 helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY;
Richard Hughes1ffde6c2015-03-02 22:44:48 +00001308 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +00001309 }
1310
Richard Hughes9945edb2017-06-19 10:03:55 +01001311
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001312 /* get the fd */
1313 message = g_dbus_method_invocation_get_message (invocation);
1314 fd_list = g_dbus_message_get_unix_fd_list (message);
1315 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001316 g_set_error (&error,
1317 FWUPD_ERROR,
1318 FWUPD_ERROR_INTERNAL,
1319 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001320 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001321 return;
1322 }
Richard Hughes7419e962016-11-22 19:48:06 +00001323 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001324 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001325 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001326 return;
1327 }
1328
Richard Hughes9945edb2017-06-19 10:03:55 +01001329 /* parse the cab file before authenticating so we can work out
1330 * what action ID to use, for instance, if this is trusted --
1331 * this will also close the fd when done */
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001332 archive_size_max = fu_engine_get_archive_size_max (priv->engine);
1333 helper->blob_cab = fu_common_get_contents_fd (fd, archive_size_max, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001334 if (helper->blob_cab == NULL) {
1335 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +01001336 return;
1337 }
Richard Hughes4ad41f02018-05-08 14:35:36 +01001338
1339 /* install all the things in the store */
1340 helper->subject = polkit_system_bus_name_new (sender);
1341 if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001342 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +00001343 return;
1344 }
1345
Richard Hughes4ad41f02018-05-08 14:35:36 +01001346 /* async return */
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001347 return;
1348 }
Richard Hughes07f963a2017-09-15 14:28:47 +01001349 if (g_strcmp0 (method_name, "GetDetails") == 0) {
Richard Hughes7289a6b2016-05-29 09:27:47 +01001350 GDBusMessage *message;
1351 GUnixFDList *fd_list;
1352 gint32 fd_handle = 0;
1353 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +01001354 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +01001355
1356 /* get parameters */
1357 g_variant_get (parameters, "(h)", &fd_handle);
1358 g_debug ("Called %s(%i)", method_name, fd_handle);
1359
1360 /* get the fd */
1361 message = g_dbus_method_invocation_get_message (invocation);
1362 fd_list = g_dbus_message_get_unix_fd_list (message);
1363 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001364 g_set_error (&error,
1365 FWUPD_ERROR,
1366 FWUPD_ERROR_INTERNAL,
1367 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001368 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001369 return;
1370 }
Richard Hughes7419e962016-11-22 19:48:06 +00001371 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001372 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001373 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001374 return;
1375 }
1376
Richard Hughes9945edb2017-06-19 10:03:55 +01001377 /* get details about the file (will close the fd when done) */
Richard Hughes07f963a2017-09-15 14:28:47 +01001378 results = fu_engine_get_details (priv->engine, fd, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001379 if (results == NULL) {
1380 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001381 return;
1382 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001383 val = fu_main_result_array_to_variant (results);
1384 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001385 return;
1386 }
Richard Hughes060af612016-08-17 17:32:34 +01001387 g_set_error (&error,
1388 G_DBUS_ERROR,
1389 G_DBUS_ERROR_UNKNOWN_METHOD,
1390 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +01001391 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001392}
1393
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001394static GVariant *
1395fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
1396 const gchar *object_path, const gchar *interface_name,
1397 const gchar *property_name, GError **error,
1398 gpointer user_data)
1399{
Richard Hughes773ce982015-03-09 22:40:57 +00001400 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1401
Richard Hughes75b965d2018-11-15 13:51:21 +00001402 /* activity */
1403 fu_engine_idle_reset (priv->engine);
1404
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001405 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
Richard Hughesfe4b3ea2020-03-30 10:53:20 +01001406 return g_variant_new_string (SOURCE_VERSION);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001407
Richard Hughesf425d292019-01-18 17:57:39 +00001408 if (g_strcmp0 (property_name, "Tainted") == 0)
1409 return g_variant_new_boolean (fu_engine_get_tainted (priv->engine));
1410
Richard Hughes773ce982015-03-09 22:40:57 +00001411 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +01001412 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +00001413
Mario Limonciello20cc9ee2019-09-05 07:27:26 -05001414 if (g_strcmp0 (property_name, "HostProduct") == 0)
1415 return g_variant_new_string (fu_engine_get_host_product (priv->engine));
1416
Richard Hughes0917fb62019-09-21 12:55:37 +01001417 if (g_strcmp0 (property_name, "HostMachineId") == 0)
1418 return g_variant_new_string (fu_engine_get_host_machine_id (priv->engine));
1419
Richard Hughes196c6c62020-05-11 19:42:47 +01001420 if (g_strcmp0 (property_name, "HostSecurityId") == 0)
1421 return g_variant_new_string (fu_engine_get_host_security_id (priv->engine));
1422
Mario Limoncielloeb4c7642019-11-11 10:31:29 -06001423 if (g_strcmp0 (property_name, "Interactive") == 0)
1424 return g_variant_new_boolean (isatty (fileno (stdout)) != 0);
1425
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001426 /* return an error */
1427 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +00001428 G_DBUS_ERROR,
1429 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001430 "failed to get daemon property %s",
1431 property_name);
1432 return NULL;
1433}
1434
Richard Hughesfd468842015-04-22 16:44:08 +01001435static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001436fu_main_on_bus_acquired_cb (GDBusConnection *connection,
1437 const gchar *name,
1438 gpointer user_data)
1439{
1440 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1441 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +01001442 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001443 static const GDBusInterfaceVTable interface_vtable = {
1444 fu_main_daemon_method_call,
1445 fu_main_daemon_get_property,
1446 NULL
1447 };
1448
1449 priv->connection = g_object_ref (connection);
1450 registration_id = g_dbus_connection_register_object (connection,
1451 FWUPD_DBUS_PATH,
1452 priv->introspection_daemon->interfaces[0],
1453 &interface_vtable,
1454 priv, /* user_data */
1455 NULL, /* user_data_free_func */
1456 NULL); /* GError** */
1457 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +00001458
1459 /* connect to D-Bus directly */
1460 priv->proxy_uid =
1461 g_dbus_proxy_new_sync (priv->connection,
1462 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1463 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1464 NULL,
1465 "org.freedesktop.DBus",
1466 "/org/freedesktop/DBus",
1467 "org.freedesktop.DBus",
1468 NULL,
1469 &error);
1470 if (priv->proxy_uid == NULL) {
1471 g_warning ("cannot connect to DBus: %s", error->message);
1472 return;
1473 }
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001474}
1475
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001476static void
1477fu_main_on_name_acquired_cb (GDBusConnection *connection,
1478 const gchar *name,
1479 gpointer user_data)
1480{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001481 g_debug ("FuMain: acquired name: %s", name);
1482}
1483
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001484static void
1485fu_main_on_name_lost_cb (GDBusConnection *connection,
1486 const gchar *name,
1487 gpointer user_data)
1488{
1489 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1490 g_debug ("FuMain: lost name: %s", name);
1491 g_main_loop_quit (priv->loop);
1492}
1493
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001494static gboolean
1495fu_main_timed_exit_cb (gpointer user_data)
1496{
1497 GMainLoop *loop = (GMainLoop *) user_data;
1498 g_main_loop_quit (loop);
1499 return G_SOURCE_REMOVE;
1500}
1501
Richard Hughesf3dc1622019-03-27 12:48:39 +00001502static void
1503fu_main_argv_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file,
1504 GFileMonitorEvent event_type, gpointer user_data)
1505{
1506 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1507
1508 /* can do straight away? */
1509 if (priv->update_in_progress) {
1510 g_warning ("binary changed during a firmware update, ignoring");
1511 return;
1512 }
1513 g_debug ("binary changed, shutting down");
1514 g_main_loop_quit (priv->loop);
1515}
1516
Richard Hughes603e4f62019-12-11 13:44:09 +00001517#if GLIB_CHECK_VERSION(2,63,3)
1518static void
1519fu_main_memory_monitor_warning_cb (GMemoryMonitor *memory_monitor,
1520 GMemoryMonitorWarningLevel level,
1521 FuMainPrivate *priv)
1522{
1523 /* can do straight away? */
1524 if (priv->update_in_progress) {
1525 g_warning ("OOM during a firmware update, ignoring");
1526 priv->pending_sigterm = TRUE;
1527 return;
1528 }
1529 g_debug ("OOM event, shutting down");
1530 g_main_loop_quit (priv->loop);
1531}
1532#endif
1533
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001534static GDBusNodeInfo *
1535fu_main_load_introspection (const gchar *filename, GError **error)
1536{
Richard Hughes46832432015-09-11 13:43:15 +01001537 g_autoptr(GBytes) data = NULL;
1538 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001539
1540 /* lookup data */
1541 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
1542 data = g_resource_lookup_data (fu_get_resource (),
1543 path,
1544 G_RESOURCE_LOOKUP_FLAGS_NONE,
1545 error);
1546 if (data == NULL)
1547 return NULL;
1548
1549 /* build introspection from XML */
1550 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
1551}
1552
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001553static void
1554fu_main_private_free (FuMainPrivate *priv)
1555{
1556 if (priv->loop != NULL)
1557 g_main_loop_unref (priv->loop);
1558 if (priv->owner_id > 0)
1559 g_bus_unown_name (priv->owner_id);
1560 if (priv->proxy_uid != NULL)
1561 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +01001562 if (priv->engine != NULL)
1563 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001564 if (priv->connection != NULL)
1565 g_object_unref (priv->connection);
1566 if (priv->authority != NULL)
1567 g_object_unref (priv->authority);
Richard Hughesf3dc1622019-03-27 12:48:39 +00001568 if (priv->argv0_monitor != NULL)
1569 g_object_unref (priv->argv0_monitor);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001570 if (priv->introspection_daemon != NULL)
1571 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughes603e4f62019-12-11 13:44:09 +00001572#if GLIB_CHECK_VERSION(2,63,3)
1573 if (priv->memory_monitor != NULL)
1574 g_object_unref (priv->memory_monitor);
1575#endif
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001576 g_free (priv);
1577}
1578
Mario Limoncielloa98df552018-04-16 12:15:51 -05001579#pragma clang diagnostic push
1580#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001581G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -05001582#pragma clang diagnostic pop
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001583
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001584int
1585main (int argc, char *argv[])
1586{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001587 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001588 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001589 const GOptionEntry options[] = {
1590 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
1591 /* TRANSLATORS: exit after we've started up, used for user profiling */
1592 _("Exit after a small delay"), NULL },
1593 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
1594 /* TRANSLATORS: exit straight away, used for automatic profiling */
1595 _("Exit after the engine has loaded"), NULL },
1596 { NULL}
1597 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001598 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001599 g_autoptr(GError) error = NULL;
Richard Hughesf3dc1622019-03-27 12:48:39 +00001600 g_autoptr(GFile) argv0_file = g_file_new_for_path (argv[0]);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001601 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001602
1603 setlocale (LC_ALL, "");
1604
Richard Hughes668ee212019-11-22 09:17:46 +00001605 bindtextdomain (GETTEXT_PACKAGE, FWUPD_LOCALEDIR);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001606 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1607 textdomain (GETTEXT_PACKAGE);
1608
1609 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +01001610 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001611 context = g_option_context_new (NULL);
1612 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001613 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +00001614 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001615 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001616 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1617 g_printerr ("Failed to parse command line: %s\n", error->message);
1618 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001619 }
1620
1621 /* create new objects */
1622 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001623 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001624
Richard Hughes9945edb2017-06-19 10:03:55 +01001625 /* load engine */
Richard Hughes5b5f6552018-05-18 10:22:39 +01001626 priv->engine = fu_engine_new (FU_APP_FLAGS_NONE);
Richard Hughes9945edb2017-06-19 10:03:55 +01001627 g_signal_connect (priv->engine, "changed",
1628 G_CALLBACK (fu_main_engine_changed_cb),
1629 priv);
1630 g_signal_connect (priv->engine, "device-added",
1631 G_CALLBACK (fu_main_engine_device_added_cb),
1632 priv);
1633 g_signal_connect (priv->engine, "device-removed",
1634 G_CALLBACK (fu_main_engine_device_removed_cb),
1635 priv);
1636 g_signal_connect (priv->engine, "device-changed",
1637 G_CALLBACK (fu_main_engine_device_changed_cb),
1638 priv);
1639 g_signal_connect (priv->engine, "status-changed",
1640 G_CALLBACK (fu_main_engine_status_changed_cb),
1641 priv);
1642 g_signal_connect (priv->engine, "percentage-changed",
1643 G_CALLBACK (fu_main_engine_percentage_changed_cb),
1644 priv);
Richard Hughesc8cc77c2019-03-07 11:57:24 +00001645 if (!fu_engine_load (priv->engine, FU_ENGINE_LOAD_FLAG_NONE, &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001646 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001647 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +01001648 }
1649
Mario Limonciello6754f5a2018-10-11 10:50:03 -05001650 g_unix_signal_add_full (G_PRIORITY_DEFAULT,
1651 SIGTERM, fu_main_sigterm_cb,
1652 priv, NULL);
1653
Richard Hughesf3dc1622019-03-27 12:48:39 +00001654 /* restart the daemon if the binary gets replaced */
1655 priv->argv0_monitor = g_file_monitor_file (argv0_file, G_FILE_MONITOR_NONE,
1656 NULL, &error);
1657 g_signal_connect (priv->argv0_monitor, "changed",
1658 G_CALLBACK (fu_main_argv_changed_cb), priv);
1659
Richard Hughes603e4f62019-12-11 13:44:09 +00001660#if GLIB_CHECK_VERSION(2,63,3)
1661 /* shut down on low memory event as we can just rescan hardware */
1662 priv->memory_monitor = g_memory_monitor_dup_default ();
1663 g_signal_connect (G_OBJECT (priv->memory_monitor), "low-memory-warning",
1664 G_CALLBACK (fu_main_memory_monitor_warning_cb), priv);
1665#endif
1666
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001667 /* load introspection from file */
1668 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1669 &error);
1670 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001671 g_printerr ("Failed to load introspection: %s\n", error->message);
1672 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001673 }
1674
Richard Hughesf508e762015-02-27 12:49:36 +00001675 /* get authority */
1676 priv->authority = polkit_authority_get_sync (NULL, &error);
1677 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001678 g_printerr ("Failed to load authority: %s\n", error->message);
1679 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +00001680 }
1681
Richard Hughesebae3962018-09-09 13:40:49 +01001682 /* own the object */
1683 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1684 FWUPD_DBUS_SERVICE,
1685 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1686 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1687 fu_main_on_bus_acquired_cb,
1688 fu_main_on_name_acquired_cb,
1689 fu_main_on_name_lost_cb,
1690 priv, NULL);
1691
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001692 /* Only timeout and close the mainloop if we have specified it
1693 * on the command line */
1694 if (immediate_exit)
1695 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1696 else if (timed_exit)
1697 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1698
Mario Limonciello46bb4e92019-01-07 09:44:31 -06001699 g_debug ("Started with locale %s", g_getenv ("LANG"));
1700
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001701 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +01001702 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001703 g_main_loop_run (priv->loop);
1704
1705 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001706 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001707}