blob: bc7e8cf7ee6fb354a3cd7a7a03d5e0b9f81409f9 [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 Hughesf58ac732020-05-12 15:23:44 +010033#include "fu-security-attrs-private.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000034
Philip Withnallbc339aa2016-11-22 16:13:22 +000035#ifndef HAVE_POLKIT_0_114
Mario Limoncielloa98df552018-04-16 12:15:51 -050036#pragma clang diagnostic push
37#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes60f48c22015-10-08 20:25:51 +010038G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
39G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
Mario Limoncielloa98df552018-04-16 12:15:51 -050040#pragma clang diagnostic pop
Richard Hughes60f48c22015-10-08 20:25:51 +010041#endif
42
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000043typedef struct {
44 GDBusConnection *connection;
45 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000046 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000047 GMainLoop *loop;
Richard Hughesf3dc1622019-03-27 12:48:39 +000048 GFileMonitor *argv0_monitor;
Richard Hughes603e4f62019-12-11 13:44:09 +000049#if GLIB_CHECK_VERSION(2,63,3)
50 GMemoryMonitor *memory_monitor;
51#endif
Richard Hughesf508e762015-02-27 12:49:36 +000052 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000053 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010054 FuEngine *engine;
Mario Limonciello6754f5a2018-10-11 10:50:03 -050055 gboolean update_in_progress;
56 gboolean pending_sigterm;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000057} FuMainPrivate;
58
Mario Limonciello6754f5a2018-10-11 10:50:03 -050059static gboolean
60fu_main_sigterm_cb (gpointer user_data)
61{
62 FuMainPrivate *priv = (FuMainPrivate *) user_data;
63 if (!priv->update_in_progress) {
64 g_main_loop_quit (priv->loop);
65 return G_SOURCE_REMOVE;
66 }
67 g_warning ("Received SIGTERM during a firmware update, ignoring");
68 priv->pending_sigterm = TRUE;
69 return G_SOURCE_CONTINUE;
70}
71
Richard Hughesd7022b52015-03-11 19:47:06 +000072static void
Richard Hughes9945edb2017-06-19 10:03:55 +010073fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000074{
75 /* not yet connected */
76 if (priv->connection == NULL)
77 return;
78 g_dbus_connection_emit_signal (priv->connection,
79 NULL,
80 FWUPD_DBUS_PATH,
81 FWUPD_DBUS_INTERFACE,
82 "Changed",
83 NULL, NULL);
84}
85
Richard Hughes8ca33782016-04-28 15:04:31 +010086static void
Richard Hughes9945edb2017-06-19 10:03:55 +010087fu_main_engine_device_added_cb (FuEngine *engine,
88 FuDevice *device,
89 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010090{
91 GVariant *val;
92
93 /* not yet connected */
94 if (priv->connection == NULL)
95 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +010096 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +010097 g_dbus_connection_emit_signal (priv->connection,
98 NULL,
99 FWUPD_DBUS_PATH,
100 FWUPD_DBUS_INTERFACE,
101 "DeviceAdded",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100102 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100103}
104
Richard Hughes8ca33782016-04-28 15:04:31 +0100105static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100106fu_main_engine_device_removed_cb (FuEngine *engine,
107 FuDevice *device,
108 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100109{
110 GVariant *val;
111
112 /* not yet connected */
113 if (priv->connection == NULL)
114 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100115 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100116 g_dbus_connection_emit_signal (priv->connection,
117 NULL,
118 FWUPD_DBUS_PATH,
119 FWUPD_DBUS_INTERFACE,
120 "DeviceRemoved",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100121 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100122}
123
Richard Hughes8ca33782016-04-28 15:04:31 +0100124static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100125fu_main_engine_device_changed_cb (FuEngine *engine,
126 FuDevice *device,
127 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100128{
129 GVariant *val;
130
131 /* not yet connected */
132 if (priv->connection == NULL)
133 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100134 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100135 g_dbus_connection_emit_signal (priv->connection,
136 NULL,
137 FWUPD_DBUS_PATH,
138 FWUPD_DBUS_INTERFACE,
139 "DeviceChanged",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100140 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100141}
142
Richard Hughes773ce982015-03-09 22:40:57 +0000143static void
144fu_main_emit_property_changed (FuMainPrivate *priv,
145 const gchar *property_name,
146 GVariant *property_value)
147{
148 GVariantBuilder builder;
149 GVariantBuilder invalidated_builder;
150
151 /* not yet connected */
Richard Hughes34fcc022018-09-19 16:16:15 +0100152 if (priv->connection == NULL) {
153 g_variant_unref (g_variant_ref_sink (property_value));
Richard Hughes773ce982015-03-09 22:40:57 +0000154 return;
Richard Hughes34fcc022018-09-19 16:16:15 +0100155 }
Richard Hughes773ce982015-03-09 22:40:57 +0000156
157 /* build the dict */
158 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
Richard Hughes8356a832019-03-21 17:04:38 +0000159 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
Richard Hughes773ce982015-03-09 22:40:57 +0000160 g_variant_builder_add (&builder,
161 "{sv}",
162 property_name,
163 property_value);
164 g_dbus_connection_emit_signal (priv->connection,
165 NULL,
166 FWUPD_DBUS_PATH,
167 "org.freedesktop.DBus.Properties",
168 "PropertiesChanged",
169 g_variant_new ("(sa{sv}as)",
170 FWUPD_DBUS_INTERFACE,
171 &builder,
172 &invalidated_builder),
173 NULL);
174 g_variant_builder_clear (&builder);
175 g_variant_builder_clear (&invalidated_builder);
176}
177
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100178static void
179fu_main_set_status (FuMainPrivate *priv, FwupdStatus status)
180{
181 g_debug ("Emitting PropertyChanged('Status'='%s')",
182 fwupd_status_to_string (status));
183 fu_main_emit_property_changed (priv, "Status",
184 g_variant_new_uint32 (status));
185}
Richard Hughes773ce982015-03-09 22:40:57 +0000186
Richard Hughes9945edb2017-06-19 10:03:55 +0100187static void
188fu_main_engine_status_changed_cb (FuEngine *engine,
189 FwupdStatus status,
190 FuMainPrivate *priv)
191{
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100192 fu_main_set_status (priv, status);
Richard Hughes75b965d2018-11-15 13:51:21 +0000193
194 /* engine has gone idle */
195 if (status == FWUPD_STATUS_SHUTDOWN)
196 g_main_loop_quit (priv->loop);
Richard Hughes773ce982015-03-09 22:40:57 +0000197}
198
Richard Hughes876c0072016-08-17 14:51:03 +0100199static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100200fu_main_engine_percentage_changed_cb (FuEngine *engine,
201 guint percentage,
202 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100203{
Richard Hughes876c0072016-08-17 14:51:03 +0100204 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
205 fu_main_emit_property_changed (priv, "Percentage",
206 g_variant_new_uint32 (percentage));
207}
208
Mario Limoncielloe3016602018-09-06 11:20:59 -0500209static gboolean
210fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender,
211 FwupdDeviceFlags *flags, GError **error)
212{
213 uid_t calling_uid;
214 g_autoptr(GVariant) value = NULL;
215
216 g_return_val_if_fail (sender != NULL, FALSE);
217 g_return_val_if_fail (flags != NULL, FALSE);
218
219 value = g_dbus_proxy_call_sync (priv->proxy_uid,
220 "GetConnectionUnixUser",
221 g_variant_new ("(s)", sender),
222 G_DBUS_CALL_FLAGS_NONE,
223 2000,
224 NULL,
225 error);
226 if (value == NULL) {
227 g_prefix_error (error, "failed to read user id of caller: ");
228 return FALSE;
229 }
230 g_variant_get (value, "(u)", &calling_uid);
231 if (calling_uid == 0)
232 *flags |= FWUPD_DEVICE_FLAG_TRUSTED;
233
234 return TRUE;
235}
236
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000237static GVariant *
Mario Limoncielloe3016602018-09-06 11:20:59 -0500238fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender,
239 GPtrArray *devices, GError **error)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000240{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000241 GVariantBuilder builder;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500242 FwupdDeviceFlags flags = FWUPD_DEVICE_FLAG_NONE;
243
Richard Hughes9945edb2017-06-19 10:03:55 +0100244 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000245 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500246
247 if (!fu_main_get_device_flags_for_sender (priv, sender, &flags, error))
Richard Hughes83cce1b2018-09-10 16:42:30 +0100248 return NULL;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500249
Richard Hughesf192bf02016-07-22 08:26:43 +0100250 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100251 FuDevice *device = g_ptr_array_index (devices, i);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500252 GVariant *tmp = fwupd_device_to_variant_full (FWUPD_DEVICE (device),
253 flags);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000254 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000255 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100256 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000257}
258
Richard Hughes9945edb2017-06-19 10:03:55 +0100259static GVariant *
260fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100261{
Richard Hughes9945edb2017-06-19 10:03:55 +0100262 GVariantBuilder builder;
263 g_return_val_if_fail (results->len > 0, NULL);
264 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
265 for (guint i = 0; i < results->len; i++) {
266 FwupdRelease *rel = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100267 GVariant *tmp = fwupd_release_to_variant (rel);
Richard Hughes9945edb2017-06-19 10:03:55 +0100268 g_variant_builder_add_value (&builder, tmp);
269 }
270 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100271}
272
Richard Hughes9945edb2017-06-19 10:03:55 +0100273static GVariant *
274fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100275{
Richard Hughes9945edb2017-06-19 10:03:55 +0100276 GVariantBuilder builder;
277 g_return_val_if_fail (remotes->len > 0, NULL);
278 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
279 for (guint i = 0; i < remotes->len; i++) {
280 FwupdRemote *remote = g_ptr_array_index (remotes, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100281 GVariant *tmp = fwupd_remote_to_variant (remote);
Richard Hughes9945edb2017-06-19 10:03:55 +0100282 g_variant_builder_add_value (&builder, tmp);
283 }
284 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100285}
286
Richard Hughes9945edb2017-06-19 10:03:55 +0100287static GVariant *
288fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000289{
Richard Hughes9945edb2017-06-19 10:03:55 +0100290 GVariantBuilder builder;
291 g_return_val_if_fail (results->len > 0, NULL);
292 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
293 for (guint i = 0; i < results->len; i++) {
Richard Hughes93b15762017-09-15 11:05:23 +0100294 FwupdDevice *result = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100295 GVariant *tmp = fwupd_device_to_variant (result);
Richard Hughes9945edb2017-06-19 10:03:55 +0100296 g_variant_builder_add_value (&builder, tmp);
297 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100298 return g_variant_new ("(aa{sv})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000299}
300
Richard Hughesf508e762015-02-27 12:49:36 +0000301typedef struct {
302 GDBusMethodInvocation *invocation;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100303 PolkitSubject *subject;
304 GPtrArray *install_tasks;
305 GPtrArray *action_ids;
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000306 GPtrArray *checksums;
Richard Hughes3d607622019-03-07 16:59:27 +0000307 guint64 flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100308 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000309 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100310 gchar *device_id;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100311 gchar *remote_id;
312 gchar *key;
313 gchar *value;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100314 XbSilo *silo;
Richard Hughesf508e762015-02-27 12:49:36 +0000315} FuMainAuthHelper;
316
Richard Hughesf508e762015-02-27 12:49:36 +0000317static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100318fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000319{
Richard Hughes4ced4662016-08-26 11:02:31 +0100320 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100321 g_bytes_unref (helper->blob_cab);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100322 if (helper->subject != NULL)
323 g_object_unref (helper->subject);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100324 if (helper->silo != NULL)
325 g_object_unref (helper->silo);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100326 if (helper->install_tasks != NULL)
327 g_ptr_array_unref (helper->install_tasks);
328 if (helper->action_ids != NULL)
329 g_ptr_array_unref (helper->action_ids);
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000330 if (helper->checksums != NULL)
331 g_ptr_array_unref (helper->checksums);
Richard Hughes9945edb2017-06-19 10:03:55 +0100332 g_free (helper->device_id);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100333 g_free (helper->remote_id);
334 g_free (helper->key);
335 g_free (helper->value);
Richard Hughes67ec8982015-03-03 11:39:27 +0000336 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000337 g_free (helper);
338}
339
Mario Limoncielloa98df552018-04-16 12:15:51 -0500340#pragma clang diagnostic push
341#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes9945edb2017-06-19 10:03:55 +0100342G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -0500343#pragma clang diagnostic pop
Richard Hughes9945edb2017-06-19 10:03:55 +0100344
345/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000346static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100347fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000348{
Richard Hughes9945edb2017-06-19 10:03:55 +0100349 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000350 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100351 g_autofree gchar *message = g_strdup ((*error)->message);
352 g_clear_error (error);
353 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100354 FWUPD_ERROR,
355 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100356 "Could not check for auth: %s", message);
357 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000358 }
359
360 /* did not auth */
361 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100362 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100363 FWUPD_ERROR,
364 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100365 "Failed to obtain auth");
366 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000367 }
368
369 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100370 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100371}
372
Richard Hughesdf7950b2016-01-31 10:18:40 +0000373static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100374fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100375{
Richard Hughes9945edb2017-06-19 10:03:55 +0100376 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
377 g_autoptr(GError) error = NULL;
378 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100379
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100380
Richard Hughes9945edb2017-06-19 10:03:55 +0100381 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100382 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100383 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
384 res, &error);
385 if (!fu_main_authorization_is_valid (auth, &error)) {
386 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100387 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100388 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100389
390 /* authenticated */
391 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
392 g_dbus_method_invocation_return_gerror (helper->invocation, error);
393 return;
394 }
395
396 /* success */
397 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100398}
399
400static void
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000401fu_main_authorize_set_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data)
402{
403 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
404 g_autoptr(GError) error = NULL;
405 g_autoptr(PolkitAuthorizationResult) auth = NULL;
406
407 /* get result */
408 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
409 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
410 res, &error);
411 if (!fu_main_authorization_is_valid (auth, &error)) {
412 g_dbus_method_invocation_return_gerror (helper->invocation, error);
413 return;
414 }
415
416 /* success */
417 for (guint i = 0; i < helper->checksums->len; i++) {
418 const gchar *csum = g_ptr_array_index (helper->checksums, i);
419 fu_engine_add_approved_firmware (helper->priv->engine, csum);
420 }
421 g_dbus_method_invocation_return_value (helper->invocation, NULL);
422}
423
424static void
Richard Hughes3d607622019-03-07 16:59:27 +0000425fu_main_authorize_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data)
426{
427 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
428 g_autofree gchar *sig = NULL;
429 g_autoptr(GError) error = NULL;
430 g_autoptr(PolkitAuthorizationResult) auth = NULL;
431
432 /* get result */
433 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
434 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
435 res, &error);
436 if (!fu_main_authorization_is_valid (auth, &error)) {
437 g_dbus_method_invocation_return_gerror (helper->invocation, error);
438 return;
439 }
440
441 /* authenticated */
442 sig = fu_engine_self_sign (helper->priv->engine, helper->value, helper->flags, &error);
443 if (sig == NULL) {
444 g_dbus_method_invocation_return_gerror (helper->invocation, error);
445 return;
446 }
447
448 /* success */
449 g_dbus_method_invocation_return_value (helper->invocation, g_variant_new ("(s)", sig));
450}
451
452static void
Mario Limonciellobfcf75b2019-04-17 15:05:39 +0100453fu_main_modify_config_cb (GObject *source, GAsyncResult *res, gpointer user_data)
454{
455 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
456 g_autoptr(GError) error = NULL;
457 g_autoptr(PolkitAuthorizationResult) auth = NULL;
458
459 /* get result */
460 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
461 res, &error);
462 if (!fu_main_authorization_is_valid (auth, &error)) {
463 g_dbus_method_invocation_return_gerror (helper->invocation, error);
464 return;
465 }
466
467 if (!fu_engine_modify_config (helper->priv->engine, helper->key, helper->value, &error)) {
468 g_dbus_method_invocation_return_gerror (helper->invocation, error);
469 return;
470 }
471
472 /* success */
473 g_dbus_method_invocation_return_value (helper->invocation, NULL);
474}
475
476static void
Mario Limonciello96a0dd52019-02-25 13:50:03 -0600477fu_main_authorize_activate_cb (GObject *source, GAsyncResult *res, gpointer user_data)
478{
479 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
480 g_autoptr(GError) error = NULL;
481 g_autoptr(PolkitAuthorizationResult) auth = NULL;
482
483 /* get result */
484 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
485 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
486 res, &error);
487 if (!fu_main_authorization_is_valid (auth, &error)) {
488 g_dbus_method_invocation_return_gerror (helper->invocation, error);
489 return;
490 }
491
492 /* authenticated */
493 if (!fu_engine_activate (helper->priv->engine, helper->device_id, &error)) {
494 g_dbus_method_invocation_return_gerror (helper->invocation, error);
495 return;
496 }
497
498 /* success */
499 g_dbus_method_invocation_return_value (helper->invocation, NULL);
500}
501
502static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100503fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000504{
Richard Hughes9945edb2017-06-19 10:03:55 +0100505 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
506 g_autoptr(GError) error = NULL;
507 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000508
Richard Hughes9945edb2017-06-19 10:03:55 +0100509 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100510 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100511 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
512 res, &error);
513 if (!fu_main_authorization_is_valid (auth, &error)) {
514 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000515 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100516 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000517
Richard Hughes9945edb2017-06-19 10:03:55 +0100518 /* authenticated */
519 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
520 g_dbus_method_invocation_return_gerror (helper->invocation, error);
521 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000522 }
523
524 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100525 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100526}
527
Richard Hughes9945edb2017-06-19 10:03:55 +0100528static void
Richard Hughesa6bd5582017-09-07 14:32:22 +0100529fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data)
530{
531 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
532 g_autoptr(GError) error = NULL;
533 g_autoptr(PolkitAuthorizationResult) auth = NULL;
534
535 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100536 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughesa6bd5582017-09-07 14:32:22 +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;
542 }
543
544 /* authenticated */
545 if (!fu_engine_modify_remote (helper->priv->engine,
546 helper->remote_id,
547 helper->key,
548 helper->value,
549 &error)) {
550 g_dbus_method_invocation_return_gerror (helper->invocation, error);
551 return;
552 }
553
554 /* success */
555 g_dbus_method_invocation_return_value (helper->invocation, NULL);
556}
557
Richard Hughes4ad41f02018-05-08 14:35:36 +0100558static void fu_main_authorize_install_queue (FuMainAuthHelper *helper);
559
Richard Hughesa6bd5582017-09-07 14:32:22 +0100560static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100561fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000562{
Richard Hughes9945edb2017-06-19 10:03:55 +0100563 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100564 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100565 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000566
Richard Hughes9945edb2017-06-19 10:03:55 +0100567 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100568 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100569 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
570 res, &error);
571 if (!fu_main_authorization_is_valid (auth, &error)) {
572 g_dbus_method_invocation_return_gerror (helper->invocation, error);
573 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000574 }
575
Richard Hughes4ad41f02018-05-08 14:35:36 +0100576 /* do the next authentication action ID */
577 fu_main_authorize_install_queue (g_steal_pointer (&helper));
578}
579
580static void
581fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref)
582{
583 FuMainPrivate *priv = helper_ref->priv;
584 g_autoptr(FuMainAuthHelper) helper = helper_ref;
585 g_autoptr(GError) error = NULL;
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500586 gboolean ret;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100587
588 /* still more things to to authenticate */
589 if (helper->action_ids->len > 0) {
590 g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0));
591 g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject);
592 g_ptr_array_remove_index (helper->action_ids, 0);
593 polkit_authority_check_authorization (priv->authority, subject,
594 action_id, NULL,
595 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
596 NULL,
597 fu_main_authorize_install_cb,
598 g_steal_pointer (&helper));
Richard Hughes9945edb2017-06-19 10:03:55 +0100599 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100600 }
601
Richard Hughes4ad41f02018-05-08 14:35:36 +0100602 /* all authenticated, so install all the things */
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500603 priv->update_in_progress = TRUE;
604 ret = fu_engine_install_tasks (helper->priv->engine,
605 helper->install_tasks,
606 helper->blob_cab,
607 helper->flags,
608 &error);
609 priv->update_in_progress = FALSE;
610 if (priv->pending_sigterm)
611 g_main_loop_quit (priv->loop);
612 if (!ret) {
Richard Hughesdbd8c762018-06-15 20:31:40 +0100613 g_dbus_method_invocation_return_gerror (helper->invocation, error);
614 return;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100615 }
616
Richard Hughes654f6b82016-04-25 12:29:48 +0100617 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100618 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100619}
620
Richard Hughes4ad41f02018-05-08 14:35:36 +0100621#if !GLIB_CHECK_VERSION(2,54,0)
622static gboolean
623g_ptr_array_find (GPtrArray *haystack, gconstpointer needle, guint *index_)
624{
625 for (guint i = 0; i < haystack->len; i++) {
626 gconstpointer *tmp = g_ptr_array_index (haystack, i);
627 if (tmp == needle) {
628 if (index_ != NULL) {
629 *index_ = i;
630 return TRUE;
631 }
632 }
633 }
634 return FALSE;
635}
636#endif
637
Richard Hughes9f86ade2018-05-10 21:11:22 +0100638static gint
639fu_main_install_task_sort_cb (gconstpointer a, gconstpointer b)
640{
641 FuInstallTask *task_a = *((FuInstallTask **) a);
642 FuInstallTask *task_b = *((FuInstallTask **) b);
Richard Hughesc02cb832018-05-20 10:31:04 +0100643 return fu_install_task_compare (task_a, task_b);
Richard Hughes9f86ade2018-05-10 21:11:22 +0100644}
645
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500646static GPtrArray *
647fu_main_get_device_family (FuMainAuthHelper *helper, GError **error)
648{
649 FuDevice *parent;
650 GPtrArray *children;
651 g_autoptr(FuDevice) device = NULL;
652 g_autoptr(GPtrArray) devices_possible = NULL;
653
654 /* get the device */
655 device = fu_engine_get_device (helper->priv->engine, helper->device_id, error);
656 if (device == NULL)
657 return NULL;
658
659 /* device itself */
660 devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
661 g_ptr_array_add (devices_possible, g_object_ref (device));
662
663 /* add device children */
664 children = fu_device_get_children (device);
665 for (guint i = 0; i < children->len; i++) {
666 FuDevice *child = g_ptr_array_index (children, i);
667 g_ptr_array_add (devices_possible, g_object_ref (child));
668 }
669
670 /* add parent and siblings, not including the device itself */
671 parent = fu_device_get_parent (device);
672 if (parent != NULL) {
673 GPtrArray *siblings = fu_device_get_children (parent);
674 g_ptr_array_add (devices_possible, g_object_ref (parent));
675 for (guint i = 0; i < siblings->len; i++) {
676 FuDevice *sibling = g_ptr_array_index (siblings, i);
677 if (sibling == device)
678 continue;
679 g_ptr_array_add (devices_possible, g_object_ref (sibling));
680 }
681 }
682
683 /* success */
684 return g_steal_pointer (&devices_possible);
685}
686
Richard Hughes4ad41f02018-05-08 14:35:36 +0100687static gboolean
688fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error)
689{
690 FuMainPrivate *priv = helper_ref->priv;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100691 g_autoptr(FuMainAuthHelper) helper = helper_ref;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100692 g_autoptr(GPtrArray) components = NULL;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100693 g_autoptr(GPtrArray) devices_possible = NULL;
694 g_autoptr(GPtrArray) errors = NULL;
695
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500696 /* get a list of devices that in some way match the device_id */
Richard Hughes4ad41f02018-05-08 14:35:36 +0100697 if (g_strcmp0 (helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) {
698 devices_possible = fu_engine_get_devices (priv->engine, error);
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500699 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100700 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100701 } else {
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500702 devices_possible = fu_main_get_device_family (helper, error);
703 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100704 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100705 }
706
Richard Hughes481aa2a2018-09-18 20:51:46 +0100707 /* parse silo */
708 helper->silo = fu_engine_get_silo_from_blob (priv->engine,
709 helper->blob_cab,
710 error);
711 if (helper->silo == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100712 return FALSE;
713
Richard Hughes481aa2a2018-09-18 20:51:46 +0100714 /* for each component in the silo */
Mario Limonciello51ddf182019-01-26 00:31:58 -0600715 components = xb_silo_query (helper->silo, "components/component", 0, error);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100716 if (components == NULL)
717 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100718 helper->action_ids = g_ptr_array_new_with_free_func (g_free);
719 helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
720 errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100721 for (guint i = 0; i < components->len; i++) {
722 XbNode *component = g_ptr_array_index (components, i);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100723
724 /* do any devices pass the requirements */
725 for (guint j = 0; j < devices_possible->len; j++) {
726 FuDevice *device = g_ptr_array_index (devices_possible, j);
727 const gchar *action_id;
728 g_autoptr(FuInstallTask) task = NULL;
729 g_autoptr(GError) error_local = NULL;
730
731 /* is this component valid for the device */
Richard Hughes481aa2a2018-09-18 20:51:46 +0100732 task = fu_install_task_new (device, component);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100733 if (!fu_engine_check_requirements (priv->engine,
Richard Hughes1d1f5cf2018-05-19 23:06:03 +0100734 task,
Mario Limonciello537da0e2020-03-09 15:38:17 -0500735 helper->flags | FWUPD_INSTALL_FLAG_FORCE,
736 &error_local)) {
737 g_debug ("first pass requirement on %s:%s failed: %s",
738 fu_device_get_id (device),
739 xb_node_query_text (component, "id", NULL),
740 error_local->message);
741 g_ptr_array_add (errors, g_steal_pointer (&error_local));
742 continue;
743 }
744
745 /* make a second pass using possibly updated version format now */
746 fu_engine_md_refresh_device_from_component (priv->engine, device, component);
747 if (!fu_engine_check_requirements (priv->engine,
748 task,
Richard Hughes1d1f5cf2018-05-19 23:06:03 +0100749 helper->flags,
Richard Hughes4ad41f02018-05-08 14:35:36 +0100750 &error_local)) {
Mario Limonciello537da0e2020-03-09 15:38:17 -0500751 g_debug ("second pass requirement on %s:%s failed: %s",
Richard Hughes4ad41f02018-05-08 14:35:36 +0100752 fu_device_get_id (device),
Richard Hughes481aa2a2018-09-18 20:51:46 +0100753 xb_node_query_text (component, "id", NULL),
Richard Hughes4ad41f02018-05-08 14:35:36 +0100754 error_local->message);
755 g_ptr_array_add (errors, g_steal_pointer (&error_local));
756 continue;
757 }
758
Mario Limonciello7a3df4b2019-01-31 10:27:22 -0600759 /* if component should have an update message from CAB */
760 fu_device_incorporate_from_component (device, component);
761
Richard Hughes4ad41f02018-05-08 14:35:36 +0100762 /* get the action IDs for the valid device */
763 action_id = fu_install_task_get_action_id (task);
764 if (!g_ptr_array_find (helper->action_ids, action_id, NULL))
765 g_ptr_array_add (helper->action_ids, g_strdup (action_id));
766 g_ptr_array_add (helper->install_tasks, g_steal_pointer (&task));
767 }
768 }
769
Richard Hughes9f86ade2018-05-10 21:11:22 +0100770 /* order the install tasks by the device priority */
771 g_ptr_array_sort (helper->install_tasks, fu_main_install_task_sort_cb);
772
Richard Hughes4ad41f02018-05-08 14:35:36 +0100773 /* nothing suitable */
774 if (helper->install_tasks->len == 0) {
Richard Hughese82eef32018-05-20 10:41:26 +0100775 GError *error_tmp = fu_common_error_array_get_best (errors);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100776 g_propagate_error (error, error_tmp);
777 return FALSE;
778 }
779
780 /* authenticate all things in the action_ids */
781 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
782 fu_main_authorize_install_queue (g_steal_pointer (&helper));
783 return TRUE;
784}
785
Richard Hughesb6f79552017-11-11 07:58:17 +0000786static gboolean
787fu_main_device_id_valid (const gchar *device_id, GError **error)
788{
789 if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0)
790 return TRUE;
791 if (device_id != NULL && strlen (device_id) >= 4)
792 return TRUE;
793 g_set_error (error,
794 FWUPD_ERROR,
795 FWUPD_ERROR_INTERNAL,
796 "invalid device ID: %s",
797 device_id);
798 return FALSE;
799}
800
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000801static void
802fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
803 const gchar *object_path, const gchar *interface_name,
804 const gchar *method_name, GVariant *parameters,
805 GDBusMethodInvocation *invocation, gpointer user_data)
806{
807 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100808 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100809 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000810
Richard Hughes75b965d2018-11-15 13:51:21 +0000811 /* activity */
812 fu_engine_idle_reset (priv->engine);
813
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000814 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100815 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000816 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100817 devices = fu_engine_get_devices (priv->engine, &error);
818 if (devices == NULL) {
819 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100820 return;
821 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500822 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
823 if (val == NULL) {
824 g_dbus_method_invocation_return_gerror (invocation, error);
825 return;
826 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100827 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100828 return;
829 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100830 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100831 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100832 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100833 g_variant_get (parameters, "(&s)", &device_id);
834 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000835 if (!fu_main_device_id_valid (device_id, &error)) {
836 g_dbus_method_invocation_return_gerror (invocation, error);
837 return;
838 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100839 releases = fu_engine_get_releases (priv->engine, device_id, &error);
840 if (releases == NULL) {
841 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100842 return;
843 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100844 val = fu_main_release_array_to_variant (releases);
845 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100846 return;
847 }
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000848 if (g_strcmp0 (method_name, "GetApprovedFirmware") == 0) {
849 GVariantBuilder builder;
850 GPtrArray *checksums = fu_engine_get_approved_firmware (priv->engine);
851 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
852 for (guint i = 0; i < checksums->len; i++) {
853 const gchar *checksum = g_ptr_array_index (checksums, i);
854 g_variant_builder_add_value (&builder, g_variant_new_string (checksum));
855 }
856 val = g_variant_builder_end (&builder);
857 g_dbus_method_invocation_return_value (invocation,
858 g_variant_new_tuple (&val, 1));
859 return;
860 }
Richard Hughes6ecc4ca2020-05-20 18:42:46 +0100861 if (g_strcmp0 (method_name, "GetReportMetadata") == 0) {
862 GHashTableIter iter;
863 GVariantBuilder builder;
864 const gchar *key;
865 const gchar *value;
866 g_autoptr(GHashTable) metadata = NULL;
867
868 metadata = fu_engine_get_report_metadata (priv->engine, &error);
869 if (metadata == NULL) {
870 g_dbus_method_invocation_return_gerror (invocation, error);
871 return;
872 }
873 g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
874 g_hash_table_iter_init (&iter, metadata);
875 while (g_hash_table_iter_next (&iter,
876 (gpointer *) &key,
877 (gpointer *) &value)) {
878 g_variant_builder_add_value (&builder,
879 g_variant_new ("{ss}", key, value));
880 }
881 val = g_variant_builder_end (&builder);
882 g_dbus_method_invocation_return_value (invocation,
883 g_variant_new_tuple (&val, 1));
884 return;
885 }
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000886 if (g_strcmp0 (method_name, "SetApprovedFirmware") == 0) {
887 g_autofree gchar *checksums_str = NULL;
888 g_auto(GStrv) checksums = NULL;
889 g_autoptr(FuMainAuthHelper) helper = NULL;
890 g_autoptr(PolkitSubject) subject = NULL;
891
892 g_variant_get (parameters, "(^as)", &checksums);
893 checksums_str = g_strjoinv (",", checksums);
894 g_debug ("Called %s(%s)", method_name, checksums_str);
895
896 /* authenticate */
897 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
898 helper = g_new0 (FuMainAuthHelper, 1);
899 helper->priv = priv;
900 helper->invocation = g_object_ref (invocation);
901 helper->checksums = g_ptr_array_new_with_free_func (g_free);
902 for (guint i = 0; checksums[i] != NULL; i++)
903 g_ptr_array_add (helper->checksums, g_strdup (checksums[i]));
904 subject = polkit_system_bus_name_new (sender);
905 polkit_authority_check_authorization (priv->authority, subject,
906 "org.freedesktop.fwupd.set-approved-firmware",
907 NULL,
908 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
909 NULL,
910 fu_main_authorize_set_approved_firmware_cb,
911 g_steal_pointer (&helper));
912 return;
913 }
Richard Hughes3d607622019-03-07 16:59:27 +0000914 if (g_strcmp0 (method_name, "SelfSign") == 0) {
915 GVariant *prop_value;
916 gchar *prop_key;
917 g_autofree gchar *value = NULL;
918 g_autoptr(FuMainAuthHelper) helper = NULL;
919 g_autoptr(PolkitSubject) subject = NULL;
920 g_autoptr(GVariantIter) iter = NULL;
921
922 g_variant_get (parameters, "(sa{sv})", &value, &iter);
923 g_debug ("Called %s(%s)", method_name, value);
924
925 /* get flags */
926 helper = g_new0 (FuMainAuthHelper, 1);
927 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
928 g_debug ("got option %s", prop_key);
929 if (g_strcmp0 (prop_key, "add-timestamp") == 0 &&
930 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughesd5aab652020-02-25 12:47:50 +0000931 helper->flags |= JCAT_SIGN_FLAG_ADD_TIMESTAMP;
Richard Hughes3d607622019-03-07 16:59:27 +0000932 if (g_strcmp0 (prop_key, "add-cert") == 0 &&
933 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughesd5aab652020-02-25 12:47:50 +0000934 helper->flags |= JCAT_SIGN_FLAG_ADD_CERT;
Richard Hughes3d607622019-03-07 16:59:27 +0000935 g_variant_unref (prop_value);
936 }
937
938 /* authenticate */
939 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
940 helper->priv = priv;
941 helper->value = g_steal_pointer (&value);
942 helper->invocation = g_object_ref (invocation);
943 subject = polkit_system_bus_name_new (sender);
944 polkit_authority_check_authorization (priv->authority, subject,
945 "org.freedesktop.fwupd.self-sign",
946 NULL,
947 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
948 NULL,
949 fu_main_authorize_self_sign_cb,
950 g_steal_pointer (&helper));
951 return;
952 }
Richard Hughes97284b12017-09-13 17:07:58 +0100953 if (g_strcmp0 (method_name, "GetDowngrades") == 0) {
954 const gchar *device_id;
955 g_autoptr(GPtrArray) releases = NULL;
956 g_variant_get (parameters, "(&s)", &device_id);
957 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000958 if (!fu_main_device_id_valid (device_id, &error)) {
959 g_dbus_method_invocation_return_gerror (invocation, error);
960 return;
961 }
Richard Hughes97284b12017-09-13 17:07:58 +0100962 releases = fu_engine_get_downgrades (priv->engine, device_id, &error);
963 if (releases == NULL) {
964 g_dbus_method_invocation_return_gerror (invocation, error);
965 return;
966 }
967 val = fu_main_release_array_to_variant (releases);
968 g_dbus_method_invocation_return_value (invocation, val);
969 return;
970 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100971 if (g_strcmp0 (method_name, "GetUpgrades") == 0) {
972 const gchar *device_id;
973 g_autoptr(GPtrArray) releases = NULL;
974 g_variant_get (parameters, "(&s)", &device_id);
975 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000976 if (!fu_main_device_id_valid (device_id, &error)) {
977 g_dbus_method_invocation_return_gerror (invocation, error);
978 return;
979 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100980 releases = fu_engine_get_upgrades (priv->engine, device_id, &error);
981 if (releases == NULL) {
982 g_dbus_method_invocation_return_gerror (invocation, error);
983 return;
984 }
985 val = fu_main_release_array_to_variant (releases);
986 g_dbus_method_invocation_return_value (invocation, val);
987 return;
988 }
Richard Hughes4c369702017-06-16 15:31:38 +0100989 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100990 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100991 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100992 remotes = fu_engine_get_remotes (priv->engine, &error);
993 if (remotes == NULL) {
994 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100995 return;
996 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100997 val = fu_main_remote_array_to_variant (remotes);
998 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100999 return;
1000 }
Richard Hughes476363a2018-01-11 10:08:58 +00001001 if (g_strcmp0 (method_name, "GetHistory") == 0) {
1002 g_autoptr(GPtrArray) devices = NULL;
1003 g_debug ("Called %s()", method_name);
1004 devices = fu_engine_get_history (priv->engine, &error);
1005 if (devices == NULL) {
1006 g_dbus_method_invocation_return_gerror (invocation, error);
1007 return;
1008 }
Mario Limoncielloe3016602018-09-06 11:20:59 -05001009 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
1010 if (val == NULL) {
1011 g_dbus_method_invocation_return_gerror (invocation, error);
1012 return;
1013 }
Richard Hughes476363a2018-01-11 10:08:58 +00001014 g_dbus_method_invocation_return_value (invocation, val);
1015 return;
1016 }
Richard Hughes196c6c62020-05-11 19:42:47 +01001017 if (g_strcmp0 (method_name, "GetHostSecurityAttrs") == 0) {
Richard Hughesf58ac732020-05-12 15:23:44 +01001018 g_autoptr(FuSecurityAttrs) attrs = NULL;
Richard Hughes196c6c62020-05-11 19:42:47 +01001019 g_debug ("Called %s()", method_name);
Richard Hughes56e7ae52020-05-17 21:00:23 +01001020 attrs = fu_engine_get_host_security_attrs (priv->engine);
Richard Hughesf58ac732020-05-12 15:23:44 +01001021 val = fu_security_attrs_to_variant (attrs);
Richard Hughes196c6c62020-05-11 19:42:47 +01001022 g_dbus_method_invocation_return_value (invocation, val);
1023 return;
1024 }
Richard Hughes0e883ee2015-03-18 17:22:33 +00001025 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001026 const gchar *device_id;
1027 g_variant_get (parameters, "(&s)", &device_id);
1028 g_debug ("Called %s(%s)", method_name, device_id);
1029 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
1030 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +00001031 return;
1032 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001033 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +00001034 return;
1035 }
Richard Hughes6b222952018-01-11 10:20:48 +00001036 if (g_strcmp0 (method_name, "ModifyDevice") == 0) {
1037 const gchar *device_id;
1038 const gchar *key = NULL;
1039 const gchar *value = NULL;
1040
1041 /* check the id exists */
1042 g_variant_get (parameters, "(&s&s&s)", &device_id, &key, &value);
1043 g_debug ("Called %s(%s,%s=%s)", method_name, device_id, key, value);
1044 if (!fu_engine_modify_device (priv->engine, device_id, key, value, &error)) {
1045 g_dbus_method_invocation_return_gerror (invocation, error);
1046 return;
1047 }
1048 g_dbus_method_invocation_return_value (invocation, NULL);
1049 return;
1050 }
Richard Hughes0e883ee2015-03-18 17:22:33 +00001051 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001052 const gchar *device_id = NULL;
Richard Hughes93b15762017-09-15 11:05:23 +01001053 g_autoptr(FwupdDevice) result = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +01001054 g_variant_get (parameters, "(&s)", &device_id);
1055 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001056 if (!fu_main_device_id_valid (device_id, &error)) {
1057 g_dbus_method_invocation_return_gerror (invocation, error);
1058 return;
1059 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001060 result = fu_engine_get_results (priv->engine, device_id, &error);
1061 if (result == NULL) {
1062 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +00001063 return;
1064 }
Richard Hughese0bd53e2017-09-17 08:29:02 +01001065 val = fwupd_device_to_variant (result);
1066 g_dbus_method_invocation_return_value (invocation,
1067 g_variant_new_tuple (&val, 1));
Richard Hughes0e883ee2015-03-18 17:22:33 +00001068 return;
1069 }
Richard Hughesba73c762017-09-15 14:31:17 +01001070 if (g_strcmp0 (method_name, "UpdateMetadata") == 0) {
Richard Hughes1b50d962017-06-02 12:23:00 +01001071 GDBusMessage *message;
1072 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +01001073 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +01001074 gint fd_data;
1075 gint fd_sig;
1076
Richard Hughes9945edb2017-06-19 10:03:55 +01001077 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
1078 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +01001079
Richard Hughes5935ebd2017-06-16 15:40:31 +01001080 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +01001081 message = g_dbus_method_invocation_get_message (invocation);
1082 fd_list = g_dbus_message_get_unix_fd_list (message);
1083 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
1084 g_set_error (&error,
1085 FWUPD_ERROR,
1086 FWUPD_ERROR_INTERNAL,
1087 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001088 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001089 return;
1090 }
1091 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
1092 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001093 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001094 return;
1095 }
1096 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
1097 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001098 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001099 return;
1100 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001101
1102 /* store new metadata (will close the fds when done) */
1103 if (!fu_engine_update_metadata (priv->engine, remote_id,
1104 fd_data, fd_sig, &error)) {
Richard Hughesf3d46c62017-11-28 14:01:30 +00001105 g_prefix_error (&error, "Failed to update metadata for %s: ", remote_id);
Richard Hughes9945edb2017-06-19 10:03:55 +01001106 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +01001107 return;
1108 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001109 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +01001110 return;
1111 }
Richard Hughes9a410ce2016-02-28 15:58:54 +00001112 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001113 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001114 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +00001115 g_autoptr(PolkitSubject) subject = NULL;
1116
Richard Hughes9945edb2017-06-19 10:03:55 +01001117 g_variant_get (parameters, "(&s)", &device_id);
1118 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001119 if (!fu_main_device_id_valid (device_id, &error)) {
1120 g_dbus_method_invocation_return_gerror (invocation, error);
1121 return;
1122 }
Richard Hughesfe5cc902016-06-29 10:00:00 +01001123
Richard Hughes9a410ce2016-02-28 15:58:54 +00001124 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001125 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes9945edb2017-06-19 10:03:55 +01001126 helper = g_new0 (FuMainAuthHelper, 1);
1127 helper->priv = priv;
1128 helper->invocation = g_object_ref (invocation);
1129 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +00001130 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +01001131 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +00001132 "org.freedesktop.fwupd.device-unlock",
1133 NULL,
1134 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1135 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +01001136 fu_main_authorize_unlock_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001137 g_steal_pointer (&helper));
Richard Hughes9a410ce2016-02-28 15:58:54 +00001138 return;
1139 }
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001140 if (g_strcmp0 (method_name, "Activate") == 0) {
1141 const gchar *device_id = NULL;
1142 g_autoptr(FuMainAuthHelper) helper = NULL;
1143 g_autoptr(PolkitSubject) subject = NULL;
1144
1145 g_variant_get (parameters, "(&s)", &device_id);
1146 g_debug ("Called %s(%s)", method_name, device_id);
1147 if (!fu_main_device_id_valid (device_id, &error)) {
1148 g_dbus_method_invocation_return_gerror (invocation, error);
1149 return;
1150 }
1151
1152 /* authenticate */
1153 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
1154 helper = g_new0 (FuMainAuthHelper, 1);
1155 helper->priv = priv;
1156 helper->invocation = g_object_ref (invocation);
1157 helper->device_id = g_strdup (device_id);
1158 subject = polkit_system_bus_name_new (sender);
1159 polkit_authority_check_authorization (priv->authority, subject,
1160 "org.freedesktop.fwupd.device-activate",
1161 NULL,
1162 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1163 NULL,
1164 fu_main_authorize_activate_cb,
1165 g_steal_pointer (&helper));
1166 return;
1167 }
Mario Limonciellobfcf75b2019-04-17 15:05:39 +01001168 if (g_strcmp0 (method_name, "ModifyConfig") == 0) {
1169 g_autofree gchar *key = NULL;
1170 g_autofree gchar *value = NULL;
1171 g_autoptr(FuMainAuthHelper) helper = NULL;
1172 g_autoptr(PolkitSubject) subject = NULL;
1173
1174 g_variant_get (parameters, "(ss)", &key, &value);
1175 g_debug ("Called %s(%s=%s)", method_name, key, value);
1176
1177 /* authenticate */
1178 helper = g_new0 (FuMainAuthHelper, 1);
1179 helper->priv = priv;
1180 helper->key = g_steal_pointer (&key);
1181 helper->value = g_steal_pointer (&value);
1182 helper->invocation = g_object_ref (invocation);
1183 subject = polkit_system_bus_name_new (sender);
1184 polkit_authority_check_authorization (priv->authority, subject,
1185 "org.freedesktop.fwupd.modify-config",
1186 NULL,
1187 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1188 NULL,
1189 fu_main_modify_config_cb,
1190 g_steal_pointer (&helper));
1191 return;
1192 }
Richard Hughesa6bd5582017-09-07 14:32:22 +01001193 if (g_strcmp0 (method_name, "ModifyRemote") == 0) {
Richard Hughesa6bd5582017-09-07 14:32:22 +01001194 const gchar *remote_id = NULL;
1195 const gchar *key = NULL;
1196 const gchar *value = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001197 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughesa6bd5582017-09-07 14:32:22 +01001198 g_autoptr(PolkitSubject) subject = NULL;
1199
1200 /* check the id exists */
1201 g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value);
1202 g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value);
1203
1204 /* create helper object */
1205 helper = g_new0 (FuMainAuthHelper, 1);
1206 helper->invocation = g_object_ref (invocation);
1207 helper->remote_id = g_strdup (remote_id);
1208 helper->key = g_strdup (key);
1209 helper->value = g_strdup (value);
1210 helper->priv = priv;
1211
1212 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001213 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughesa6bd5582017-09-07 14:32:22 +01001214 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -05001215 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughesa6bd5582017-09-07 14:32:22 +01001216 "org.freedesktop.fwupd.modify-remote",
1217 NULL,
1218 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1219 NULL,
1220 fu_main_authorize_modify_remote_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001221 g_steal_pointer (&helper));
Richard Hughesa6bd5582017-09-07 14:32:22 +01001222 return;
1223 }
Richard Hughes29c220d2016-12-14 17:09:54 +00001224 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001225 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001226 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +00001227 g_autoptr(PolkitSubject) subject = NULL;
1228
1229 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +01001230 g_variant_get (parameters, "(&s)", &device_id);
1231 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001232 if (!fu_main_device_id_valid (device_id, &error)) {
1233 g_dbus_method_invocation_return_gerror (invocation, error);
1234 return;
1235 }
Richard Hughes29c220d2016-12-14 17:09:54 +00001236
Richard Hughes9945edb2017-06-19 10:03:55 +01001237 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +00001238 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +00001239 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +01001240 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +00001241 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +00001242
1243 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001244 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes29c220d2016-12-14 17:09:54 +00001245 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -05001246 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes29c220d2016-12-14 17:09:54 +00001247 "org.freedesktop.fwupd.verify-update",
1248 NULL,
1249 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1250 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +01001251 fu_main_authorize_verify_update_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001252 g_steal_pointer (&helper));
Richard Hughes29c220d2016-12-14 17:09:54 +00001253 return;
1254 }
Richard Hughesa043c2e2015-06-29 08:43:18 +01001255 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001256 const gchar *device_id = NULL;
1257 g_variant_get (parameters, "(&s)", &device_id);
1258 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001259 if (!fu_main_device_id_valid (device_id, &error)) {
1260 g_dbus_method_invocation_return_gerror (invocation, error);
1261 return;
1262 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001263 if (!fu_engine_verify (priv->engine, device_id, &error)) {
1264 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001265 return;
1266 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001267 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001268 return;
1269 }
Richard Hughes63a407a2015-07-22 08:54:14 +01001270 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001271 GVariant *prop_value;
Richard Hughes9945edb2017-06-19 10:03:55 +01001272 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +00001273 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001274 gint32 fd_handle = 0;
1275 gint fd;
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001276 guint64 archive_size_max;
Richard Hughes9945edb2017-06-19 10:03:55 +01001277 GDBusMessage *message;
1278 GUnixFDList *fd_list;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001279 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001280 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001281
1282 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +01001283 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
1284 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughesb6f79552017-11-11 07:58:17 +00001285 if (!fu_main_device_id_valid (device_id, &error)) {
1286 g_dbus_method_invocation_return_gerror (invocation, error);
1287 return;
1288 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001289
Richard Hughes9945edb2017-06-19 10:03:55 +01001290 /* create helper object */
1291 helper = g_new0 (FuMainAuthHelper, 1);
1292 helper->invocation = g_object_ref (invocation);
1293 helper->device_id = g_strdup (device_id);
1294 helper->priv = priv;
1295
1296 /* get flags */
1297 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001298 g_debug ("got option %s", prop_key);
1299 if (g_strcmp0 (prop_key, "offline") == 0 &&
1300 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001301 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +00001302 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
1303 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001304 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +00001305 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
1306 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001307 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -05001308 if (g_strcmp0 (prop_key, "force") == 0 &&
1309 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001310 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes76e0f942018-05-14 16:24:00 +01001311 if (g_strcmp0 (prop_key, "no-history") == 0 &&
1312 g_variant_get_boolean (prop_value) == TRUE)
1313 helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY;
Richard Hughes1ffde6c2015-03-02 22:44:48 +00001314 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +00001315 }
1316
Richard Hughes9945edb2017-06-19 10:03:55 +01001317
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001318 /* get the fd */
1319 message = g_dbus_method_invocation_get_message (invocation);
1320 fd_list = g_dbus_message_get_unix_fd_list (message);
1321 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001322 g_set_error (&error,
1323 FWUPD_ERROR,
1324 FWUPD_ERROR_INTERNAL,
1325 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001326 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001327 return;
1328 }
Richard Hughes7419e962016-11-22 19:48:06 +00001329 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001330 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001331 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001332 return;
1333 }
1334
Richard Hughes9945edb2017-06-19 10:03:55 +01001335 /* parse the cab file before authenticating so we can work out
1336 * what action ID to use, for instance, if this is trusted --
1337 * this will also close the fd when done */
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001338 archive_size_max = fu_engine_get_archive_size_max (priv->engine);
1339 helper->blob_cab = fu_common_get_contents_fd (fd, archive_size_max, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001340 if (helper->blob_cab == NULL) {
1341 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +01001342 return;
1343 }
Richard Hughes4ad41f02018-05-08 14:35:36 +01001344
1345 /* install all the things in the store */
1346 helper->subject = polkit_system_bus_name_new (sender);
1347 if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001348 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +00001349 return;
1350 }
1351
Richard Hughes4ad41f02018-05-08 14:35:36 +01001352 /* async return */
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001353 return;
1354 }
Richard Hughes07f963a2017-09-15 14:28:47 +01001355 if (g_strcmp0 (method_name, "GetDetails") == 0) {
Richard Hughes7289a6b2016-05-29 09:27:47 +01001356 GDBusMessage *message;
1357 GUnixFDList *fd_list;
1358 gint32 fd_handle = 0;
1359 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +01001360 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +01001361
1362 /* get parameters */
1363 g_variant_get (parameters, "(h)", &fd_handle);
1364 g_debug ("Called %s(%i)", method_name, fd_handle);
1365
1366 /* get the fd */
1367 message = g_dbus_method_invocation_get_message (invocation);
1368 fd_list = g_dbus_message_get_unix_fd_list (message);
1369 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001370 g_set_error (&error,
1371 FWUPD_ERROR,
1372 FWUPD_ERROR_INTERNAL,
1373 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001374 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001375 return;
1376 }
Richard Hughes7419e962016-11-22 19:48:06 +00001377 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001378 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001379 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001380 return;
1381 }
1382
Richard Hughes9945edb2017-06-19 10:03:55 +01001383 /* get details about the file (will close the fd when done) */
Richard Hughes07f963a2017-09-15 14:28:47 +01001384 results = fu_engine_get_details (priv->engine, fd, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001385 if (results == NULL) {
1386 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001387 return;
1388 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001389 val = fu_main_result_array_to_variant (results);
1390 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001391 return;
1392 }
Richard Hughes060af612016-08-17 17:32:34 +01001393 g_set_error (&error,
1394 G_DBUS_ERROR,
1395 G_DBUS_ERROR_UNKNOWN_METHOD,
1396 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +01001397 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001398}
1399
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001400static GVariant *
1401fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
1402 const gchar *object_path, const gchar *interface_name,
1403 const gchar *property_name, GError **error,
1404 gpointer user_data)
1405{
Richard Hughes773ce982015-03-09 22:40:57 +00001406 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1407
Richard Hughes75b965d2018-11-15 13:51:21 +00001408 /* activity */
1409 fu_engine_idle_reset (priv->engine);
1410
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001411 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
Richard Hughesfe4b3ea2020-03-30 10:53:20 +01001412 return g_variant_new_string (SOURCE_VERSION);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001413
Richard Hughesf425d292019-01-18 17:57:39 +00001414 if (g_strcmp0 (property_name, "Tainted") == 0)
1415 return g_variant_new_boolean (fu_engine_get_tainted (priv->engine));
1416
Richard Hughes773ce982015-03-09 22:40:57 +00001417 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +01001418 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +00001419
Mario Limonciello20cc9ee2019-09-05 07:27:26 -05001420 if (g_strcmp0 (property_name, "HostProduct") == 0)
1421 return g_variant_new_string (fu_engine_get_host_product (priv->engine));
1422
Richard Hughes0917fb62019-09-21 12:55:37 +01001423 if (g_strcmp0 (property_name, "HostMachineId") == 0)
1424 return g_variant_new_string (fu_engine_get_host_machine_id (priv->engine));
1425
Richard Hughes196c6c62020-05-11 19:42:47 +01001426 if (g_strcmp0 (property_name, "HostSecurityId") == 0)
1427 return g_variant_new_string (fu_engine_get_host_security_id (priv->engine));
1428
Mario Limoncielloeb4c7642019-11-11 10:31:29 -06001429 if (g_strcmp0 (property_name, "Interactive") == 0)
1430 return g_variant_new_boolean (isatty (fileno (stdout)) != 0);
1431
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001432 /* return an error */
1433 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +00001434 G_DBUS_ERROR,
1435 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001436 "failed to get daemon property %s",
1437 property_name);
1438 return NULL;
1439}
1440
Richard Hughesfd468842015-04-22 16:44:08 +01001441static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001442fu_main_on_bus_acquired_cb (GDBusConnection *connection,
1443 const gchar *name,
1444 gpointer user_data)
1445{
1446 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1447 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +01001448 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001449 static const GDBusInterfaceVTable interface_vtable = {
1450 fu_main_daemon_method_call,
1451 fu_main_daemon_get_property,
1452 NULL
1453 };
1454
1455 priv->connection = g_object_ref (connection);
1456 registration_id = g_dbus_connection_register_object (connection,
1457 FWUPD_DBUS_PATH,
1458 priv->introspection_daemon->interfaces[0],
1459 &interface_vtable,
1460 priv, /* user_data */
1461 NULL, /* user_data_free_func */
1462 NULL); /* GError** */
1463 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +00001464
1465 /* connect to D-Bus directly */
1466 priv->proxy_uid =
1467 g_dbus_proxy_new_sync (priv->connection,
1468 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1469 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1470 NULL,
1471 "org.freedesktop.DBus",
1472 "/org/freedesktop/DBus",
1473 "org.freedesktop.DBus",
1474 NULL,
1475 &error);
1476 if (priv->proxy_uid == NULL) {
1477 g_warning ("cannot connect to DBus: %s", error->message);
1478 return;
1479 }
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001480}
1481
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001482static void
1483fu_main_on_name_acquired_cb (GDBusConnection *connection,
1484 const gchar *name,
1485 gpointer user_data)
1486{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001487 g_debug ("FuMain: acquired name: %s", name);
1488}
1489
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001490static void
1491fu_main_on_name_lost_cb (GDBusConnection *connection,
1492 const gchar *name,
1493 gpointer user_data)
1494{
1495 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1496 g_debug ("FuMain: lost name: %s", name);
1497 g_main_loop_quit (priv->loop);
1498}
1499
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001500static gboolean
1501fu_main_timed_exit_cb (gpointer user_data)
1502{
1503 GMainLoop *loop = (GMainLoop *) user_data;
1504 g_main_loop_quit (loop);
1505 return G_SOURCE_REMOVE;
1506}
1507
Richard Hughesf3dc1622019-03-27 12:48:39 +00001508static void
1509fu_main_argv_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file,
1510 GFileMonitorEvent event_type, gpointer user_data)
1511{
1512 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1513
1514 /* can do straight away? */
1515 if (priv->update_in_progress) {
1516 g_warning ("binary changed during a firmware update, ignoring");
1517 return;
1518 }
1519 g_debug ("binary changed, shutting down");
1520 g_main_loop_quit (priv->loop);
1521}
1522
Richard Hughes603e4f62019-12-11 13:44:09 +00001523#if GLIB_CHECK_VERSION(2,63,3)
1524static void
1525fu_main_memory_monitor_warning_cb (GMemoryMonitor *memory_monitor,
1526 GMemoryMonitorWarningLevel level,
1527 FuMainPrivate *priv)
1528{
1529 /* can do straight away? */
1530 if (priv->update_in_progress) {
1531 g_warning ("OOM during a firmware update, ignoring");
1532 priv->pending_sigterm = TRUE;
1533 return;
1534 }
1535 g_debug ("OOM event, shutting down");
1536 g_main_loop_quit (priv->loop);
1537}
1538#endif
1539
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001540static GDBusNodeInfo *
1541fu_main_load_introspection (const gchar *filename, GError **error)
1542{
Richard Hughes46832432015-09-11 13:43:15 +01001543 g_autoptr(GBytes) data = NULL;
1544 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001545
1546 /* lookup data */
1547 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
1548 data = g_resource_lookup_data (fu_get_resource (),
1549 path,
1550 G_RESOURCE_LOOKUP_FLAGS_NONE,
1551 error);
1552 if (data == NULL)
1553 return NULL;
1554
1555 /* build introspection from XML */
1556 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
1557}
1558
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001559static void
1560fu_main_private_free (FuMainPrivate *priv)
1561{
1562 if (priv->loop != NULL)
1563 g_main_loop_unref (priv->loop);
1564 if (priv->owner_id > 0)
1565 g_bus_unown_name (priv->owner_id);
1566 if (priv->proxy_uid != NULL)
1567 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +01001568 if (priv->engine != NULL)
1569 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001570 if (priv->connection != NULL)
1571 g_object_unref (priv->connection);
1572 if (priv->authority != NULL)
1573 g_object_unref (priv->authority);
Richard Hughesf3dc1622019-03-27 12:48:39 +00001574 if (priv->argv0_monitor != NULL)
1575 g_object_unref (priv->argv0_monitor);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001576 if (priv->introspection_daemon != NULL)
1577 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughes603e4f62019-12-11 13:44:09 +00001578#if GLIB_CHECK_VERSION(2,63,3)
1579 if (priv->memory_monitor != NULL)
1580 g_object_unref (priv->memory_monitor);
1581#endif
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001582 g_free (priv);
1583}
1584
Mario Limoncielloa98df552018-04-16 12:15:51 -05001585#pragma clang diagnostic push
1586#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001587G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -05001588#pragma clang diagnostic pop
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001589
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001590int
1591main (int argc, char *argv[])
1592{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001593 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001594 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001595 const GOptionEntry options[] = {
1596 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
1597 /* TRANSLATORS: exit after we've started up, used for user profiling */
1598 _("Exit after a small delay"), NULL },
1599 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
1600 /* TRANSLATORS: exit straight away, used for automatic profiling */
1601 _("Exit after the engine has loaded"), NULL },
1602 { NULL}
1603 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001604 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001605 g_autoptr(GError) error = NULL;
Richard Hughesf3dc1622019-03-27 12:48:39 +00001606 g_autoptr(GFile) argv0_file = g_file_new_for_path (argv[0]);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001607 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001608
1609 setlocale (LC_ALL, "");
1610
Richard Hughes668ee212019-11-22 09:17:46 +00001611 bindtextdomain (GETTEXT_PACKAGE, FWUPD_LOCALEDIR);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001612 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1613 textdomain (GETTEXT_PACKAGE);
1614
1615 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +01001616 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001617 context = g_option_context_new (NULL);
1618 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001619 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +00001620 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001621 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001622 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1623 g_printerr ("Failed to parse command line: %s\n", error->message);
1624 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001625 }
1626
1627 /* create new objects */
1628 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001629 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001630
Richard Hughes9945edb2017-06-19 10:03:55 +01001631 /* load engine */
Richard Hughes5b5f6552018-05-18 10:22:39 +01001632 priv->engine = fu_engine_new (FU_APP_FLAGS_NONE);
Richard Hughes9945edb2017-06-19 10:03:55 +01001633 g_signal_connect (priv->engine, "changed",
1634 G_CALLBACK (fu_main_engine_changed_cb),
1635 priv);
1636 g_signal_connect (priv->engine, "device-added",
1637 G_CALLBACK (fu_main_engine_device_added_cb),
1638 priv);
1639 g_signal_connect (priv->engine, "device-removed",
1640 G_CALLBACK (fu_main_engine_device_removed_cb),
1641 priv);
1642 g_signal_connect (priv->engine, "device-changed",
1643 G_CALLBACK (fu_main_engine_device_changed_cb),
1644 priv);
1645 g_signal_connect (priv->engine, "status-changed",
1646 G_CALLBACK (fu_main_engine_status_changed_cb),
1647 priv);
1648 g_signal_connect (priv->engine, "percentage-changed",
1649 G_CALLBACK (fu_main_engine_percentage_changed_cb),
1650 priv);
Richard Hughesc8cc77c2019-03-07 11:57:24 +00001651 if (!fu_engine_load (priv->engine, FU_ENGINE_LOAD_FLAG_NONE, &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001652 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001653 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +01001654 }
1655
Mario Limonciello6754f5a2018-10-11 10:50:03 -05001656 g_unix_signal_add_full (G_PRIORITY_DEFAULT,
1657 SIGTERM, fu_main_sigterm_cb,
1658 priv, NULL);
1659
Richard Hughesf3dc1622019-03-27 12:48:39 +00001660 /* restart the daemon if the binary gets replaced */
1661 priv->argv0_monitor = g_file_monitor_file (argv0_file, G_FILE_MONITOR_NONE,
1662 NULL, &error);
1663 g_signal_connect (priv->argv0_monitor, "changed",
1664 G_CALLBACK (fu_main_argv_changed_cb), priv);
1665
Richard Hughes603e4f62019-12-11 13:44:09 +00001666#if GLIB_CHECK_VERSION(2,63,3)
1667 /* shut down on low memory event as we can just rescan hardware */
1668 priv->memory_monitor = g_memory_monitor_dup_default ();
1669 g_signal_connect (G_OBJECT (priv->memory_monitor), "low-memory-warning",
1670 G_CALLBACK (fu_main_memory_monitor_warning_cb), priv);
1671#endif
1672
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001673 /* load introspection from file */
1674 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1675 &error);
1676 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001677 g_printerr ("Failed to load introspection: %s\n", error->message);
1678 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001679 }
1680
Richard Hughesf508e762015-02-27 12:49:36 +00001681 /* get authority */
1682 priv->authority = polkit_authority_get_sync (NULL, &error);
1683 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001684 g_printerr ("Failed to load authority: %s\n", error->message);
1685 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +00001686 }
1687
Richard Hughesebae3962018-09-09 13:40:49 +01001688 /* own the object */
1689 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1690 FWUPD_DBUS_SERVICE,
1691 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1692 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1693 fu_main_on_bus_acquired_cb,
1694 fu_main_on_name_acquired_cb,
1695 fu_main_on_name_lost_cb,
1696 priv, NULL);
1697
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001698 /* Only timeout and close the mainloop if we have specified it
1699 * on the command line */
1700 if (immediate_exit)
1701 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1702 else if (timed_exit)
1703 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1704
Mario Limonciello46bb4e92019-01-07 09:44:31 -06001705 g_debug ("Started with locale %s", g_getenv ("LANG"));
1706
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001707 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +01001708 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001709 g_main_loop_run (priv->loop);
1710
1711 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001712 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001713}