blob: 4a7e6cf8e80f6d56a55cfe085b48a1b2bebfca0c [file] [log] [blame]
Richard Hughes02c90d82018-08-09 12:13:03 +01001/*
Richard Hughesf29a6ee2017-06-02 19:50:37 +01002 * Copyright (C) 2015-2017 Richard Hughes <richard@hughsie.com>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00003 *
Mario Limonciello51308e62018-05-28 20:05:46 -05004 * SPDX-License-Identifier: LGPL-2.1+
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00005 */
6
Richard Hughesb08e7bc2018-09-11 10:51:13 +01007#define G_LOG_DOMAIN "FuMain"
8
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00009#include "config.h"
10
Richard Hughes481aa2a2018-09-18 20:51:46 +010011#include <xmlb.h>
Richard Hughes9945edb2017-06-19 10:03:55 +010012#include <fwupd.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000013#include <gio/gunixfdlist.h>
14#include <glib/gi18n.h>
Mario Limonciello6754f5a2018-10-11 10:50:03 -050015#include <glib-unix.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000016#include <locale.h>
Richard Hughesf508e762015-02-27 12:49:36 +000017#include <polkit/polkit.h>
Richard Hughes67ec8982015-03-03 11:39:27 +000018#include <stdlib.h>
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000019
Richard Hughes68982c62017-09-13 15:40:14 +010020#include "fwupd-device-private.h"
Richard Hughes1642b3b2017-06-05 17:40:08 +010021#include "fwupd-release-private.h"
Richard Hughes4c369702017-06-16 15:31:38 +010022#include "fwupd-remote-private.h"
Richard Hughesd6db6b42017-04-12 15:03:10 +010023#include "fwupd-resources.h"
Richard Hughes8e9762d2016-03-17 10:14:15 +000024
Richard Hughes943d2c92017-06-21 09:04:39 +010025#include "fu-common.h"
Richard Hughes8bbfdf42015-02-26 22:28:09 +000026#include "fu-debug.h"
Richard Hughes68982c62017-09-13 15:40:14 +010027#include "fu-device-private.h"
Richard Hughes9945edb2017-06-19 10:03:55 +010028#include "fu-engine.h"
Richard Hughes4ad41f02018-05-08 14:35:36 +010029#include "fu-install-task.h"
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000030
Philip Withnallbc339aa2016-11-22 16:13:22 +000031#ifndef HAVE_POLKIT_0_114
Mario Limoncielloa98df552018-04-16 12:15:51 -050032#pragma clang diagnostic push
33#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes60f48c22015-10-08 20:25:51 +010034G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
35G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
Mario Limoncielloa98df552018-04-16 12:15:51 -050036#pragma clang diagnostic pop
Richard Hughes60f48c22015-10-08 20:25:51 +010037#endif
38
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000039typedef struct {
40 GDBusConnection *connection;
41 GDBusNodeInfo *introspection_daemon;
Richard Hughes18423292015-03-09 17:10:50 +000042 GDBusProxy *proxy_uid;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000043 GMainLoop *loop;
Richard Hughesf3dc1622019-03-27 12:48:39 +000044 GFileMonitor *argv0_monitor;
Richard Hughesf508e762015-02-27 12:49:36 +000045 PolkitAuthority *authority;
Richard Hughesf0a799e2017-01-17 20:13:30 +000046 guint owner_id;
Richard Hughes9945edb2017-06-19 10:03:55 +010047 FuEngine *engine;
Mario Limonciello6754f5a2018-10-11 10:50:03 -050048 gboolean update_in_progress;
49 gboolean pending_sigterm;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +000050} FuMainPrivate;
51
Mario Limonciello6754f5a2018-10-11 10:50:03 -050052static gboolean
53fu_main_sigterm_cb (gpointer user_data)
54{
55 FuMainPrivate *priv = (FuMainPrivate *) user_data;
56 if (!priv->update_in_progress) {
57 g_main_loop_quit (priv->loop);
58 return G_SOURCE_REMOVE;
59 }
60 g_warning ("Received SIGTERM during a firmware update, ignoring");
61 priv->pending_sigterm = TRUE;
62 return G_SOURCE_CONTINUE;
63}
64
Richard Hughesd7022b52015-03-11 19:47:06 +000065static void
Richard Hughes9945edb2017-06-19 10:03:55 +010066fu_main_engine_changed_cb (FuEngine *engine, FuMainPrivate *priv)
Richard Hughesd7022b52015-03-11 19:47:06 +000067{
68 /* not yet connected */
69 if (priv->connection == NULL)
70 return;
71 g_dbus_connection_emit_signal (priv->connection,
72 NULL,
73 FWUPD_DBUS_PATH,
74 FWUPD_DBUS_INTERFACE,
75 "Changed",
76 NULL, NULL);
77}
78
Richard Hughes8ca33782016-04-28 15:04:31 +010079static void
Richard Hughes9945edb2017-06-19 10:03:55 +010080fu_main_engine_device_added_cb (FuEngine *engine,
81 FuDevice *device,
82 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +010083{
84 GVariant *val;
85
86 /* not yet connected */
87 if (priv->connection == NULL)
88 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +010089 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +010090 g_dbus_connection_emit_signal (priv->connection,
91 NULL,
92 FWUPD_DBUS_PATH,
93 FWUPD_DBUS_INTERFACE,
94 "DeviceAdded",
Richard Hughese0bd53e2017-09-17 08:29:02 +010095 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +010096}
97
Richard Hughes8ca33782016-04-28 15:04:31 +010098static void
Richard Hughes9945edb2017-06-19 10:03:55 +010099fu_main_engine_device_removed_cb (FuEngine *engine,
100 FuDevice *device,
101 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100102{
103 GVariant *val;
104
105 /* not yet connected */
106 if (priv->connection == NULL)
107 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100108 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100109 g_dbus_connection_emit_signal (priv->connection,
110 NULL,
111 FWUPD_DBUS_PATH,
112 FWUPD_DBUS_INTERFACE,
113 "DeviceRemoved",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100114 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100115}
116
Richard Hughes8ca33782016-04-28 15:04:31 +0100117static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100118fu_main_engine_device_changed_cb (FuEngine *engine,
119 FuDevice *device,
120 FuMainPrivate *priv)
Richard Hughes8ca33782016-04-28 15:04:31 +0100121{
122 GVariant *val;
123
124 /* not yet connected */
125 if (priv->connection == NULL)
126 return;
Richard Hughese0bd53e2017-09-17 08:29:02 +0100127 val = fwupd_device_to_variant (FWUPD_DEVICE (device));
Richard Hughes8ca33782016-04-28 15:04:31 +0100128 g_dbus_connection_emit_signal (priv->connection,
129 NULL,
130 FWUPD_DBUS_PATH,
131 FWUPD_DBUS_INTERFACE,
132 "DeviceChanged",
Richard Hughese0bd53e2017-09-17 08:29:02 +0100133 g_variant_new_tuple (&val, 1), NULL);
Richard Hughes8ca33782016-04-28 15:04:31 +0100134}
135
Richard Hughes773ce982015-03-09 22:40:57 +0000136static void
137fu_main_emit_property_changed (FuMainPrivate *priv,
138 const gchar *property_name,
139 GVariant *property_value)
140{
141 GVariantBuilder builder;
142 GVariantBuilder invalidated_builder;
143
144 /* not yet connected */
Richard Hughes34fcc022018-09-19 16:16:15 +0100145 if (priv->connection == NULL) {
146 g_variant_unref (g_variant_ref_sink (property_value));
Richard Hughes773ce982015-03-09 22:40:57 +0000147 return;
Richard Hughes34fcc022018-09-19 16:16:15 +0100148 }
Richard Hughes773ce982015-03-09 22:40:57 +0000149
150 /* build the dict */
151 g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
Richard Hughes8356a832019-03-21 17:04:38 +0000152 g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
Richard Hughes773ce982015-03-09 22:40:57 +0000153 g_variant_builder_add (&builder,
154 "{sv}",
155 property_name,
156 property_value);
157 g_dbus_connection_emit_signal (priv->connection,
158 NULL,
159 FWUPD_DBUS_PATH,
160 "org.freedesktop.DBus.Properties",
161 "PropertiesChanged",
162 g_variant_new ("(sa{sv}as)",
163 FWUPD_DBUS_INTERFACE,
164 &builder,
165 &invalidated_builder),
166 NULL);
167 g_variant_builder_clear (&builder);
168 g_variant_builder_clear (&invalidated_builder);
169}
170
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100171static void
172fu_main_set_status (FuMainPrivate *priv, FwupdStatus status)
173{
174 g_debug ("Emitting PropertyChanged('Status'='%s')",
175 fwupd_status_to_string (status));
176 fu_main_emit_property_changed (priv, "Status",
177 g_variant_new_uint32 (status));
178}
Richard Hughes773ce982015-03-09 22:40:57 +0000179
Richard Hughes9945edb2017-06-19 10:03:55 +0100180static void
181fu_main_engine_status_changed_cb (FuEngine *engine,
182 FwupdStatus status,
183 FuMainPrivate *priv)
184{
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100185 fu_main_set_status (priv, status);
Richard Hughes75b965d2018-11-15 13:51:21 +0000186
187 /* engine has gone idle */
188 if (status == FWUPD_STATUS_SHUTDOWN)
189 g_main_loop_quit (priv->loop);
Richard Hughes773ce982015-03-09 22:40:57 +0000190}
191
Richard Hughes876c0072016-08-17 14:51:03 +0100192static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100193fu_main_engine_percentage_changed_cb (FuEngine *engine,
194 guint percentage,
195 FuMainPrivate *priv)
Richard Hughes876c0072016-08-17 14:51:03 +0100196{
Richard Hughes876c0072016-08-17 14:51:03 +0100197 g_debug ("Emitting PropertyChanged('Percentage'='%u%%')", percentage);
198 fu_main_emit_property_changed (priv, "Percentage",
199 g_variant_new_uint32 (percentage));
200}
201
Mario Limoncielloe3016602018-09-06 11:20:59 -0500202static gboolean
203fu_main_get_device_flags_for_sender (FuMainPrivate *priv, const char *sender,
204 FwupdDeviceFlags *flags, GError **error)
205{
206 uid_t calling_uid;
207 g_autoptr(GVariant) value = NULL;
208
209 g_return_val_if_fail (sender != NULL, FALSE);
210 g_return_val_if_fail (flags != NULL, FALSE);
211
212 value = g_dbus_proxy_call_sync (priv->proxy_uid,
213 "GetConnectionUnixUser",
214 g_variant_new ("(s)", sender),
215 G_DBUS_CALL_FLAGS_NONE,
216 2000,
217 NULL,
218 error);
219 if (value == NULL) {
220 g_prefix_error (error, "failed to read user id of caller: ");
221 return FALSE;
222 }
223 g_variant_get (value, "(u)", &calling_uid);
224 if (calling_uid == 0)
225 *flags |= FWUPD_DEVICE_FLAG_TRUSTED;
226
227 return TRUE;
228}
229
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000230static GVariant *
Mario Limoncielloe3016602018-09-06 11:20:59 -0500231fu_main_device_array_to_variant (FuMainPrivate *priv, const gchar *sender,
232 GPtrArray *devices, GError **error)
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000233{
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000234 GVariantBuilder builder;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500235 FwupdDeviceFlags flags = FWUPD_DEVICE_FLAG_NONE;
236
Richard Hughes9945edb2017-06-19 10:03:55 +0100237 g_return_val_if_fail (devices->len > 0, NULL);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000238 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500239
240 if (!fu_main_get_device_flags_for_sender (priv, sender, &flags, error))
Richard Hughes83cce1b2018-09-10 16:42:30 +0100241 return NULL;
Mario Limoncielloe3016602018-09-06 11:20:59 -0500242
Richard Hughesf192bf02016-07-22 08:26:43 +0100243 for (guint i = 0; i < devices->len; i++) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100244 FuDevice *device = g_ptr_array_index (devices, i);
Mario Limoncielloe3016602018-09-06 11:20:59 -0500245 GVariant *tmp = fwupd_device_to_variant_full (FWUPD_DEVICE (device),
246 flags);
Richard Hughes1ffde6c2015-03-02 22:44:48 +0000247 g_variant_builder_add_value (&builder, tmp);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000248 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100249 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000250}
251
Richard Hughes9945edb2017-06-19 10:03:55 +0100252static GVariant *
253fu_main_release_array_to_variant (GPtrArray *results)
Richard Hughes060af612016-08-17 17:32:34 +0100254{
Richard Hughes9945edb2017-06-19 10:03:55 +0100255 GVariantBuilder builder;
256 g_return_val_if_fail (results->len > 0, NULL);
257 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
258 for (guint i = 0; i < results->len; i++) {
259 FwupdRelease *rel = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100260 GVariant *tmp = fwupd_release_to_variant (rel);
Richard Hughes9945edb2017-06-19 10:03:55 +0100261 g_variant_builder_add_value (&builder, tmp);
262 }
263 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100264}
265
Richard Hughes9945edb2017-06-19 10:03:55 +0100266static GVariant *
267fu_main_remote_array_to_variant (GPtrArray *remotes)
Richard Hughes060af612016-08-17 17:32:34 +0100268{
Richard Hughes9945edb2017-06-19 10:03:55 +0100269 GVariantBuilder builder;
270 g_return_val_if_fail (remotes->len > 0, NULL);
271 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
272 for (guint i = 0; i < remotes->len; i++) {
273 FwupdRemote *remote = g_ptr_array_index (remotes, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100274 GVariant *tmp = fwupd_remote_to_variant (remote);
Richard Hughes9945edb2017-06-19 10:03:55 +0100275 g_variant_builder_add_value (&builder, tmp);
276 }
277 return g_variant_new ("(aa{sv})", &builder);
Richard Hughes060af612016-08-17 17:32:34 +0100278}
279
Richard Hughes9945edb2017-06-19 10:03:55 +0100280static GVariant *
281fu_main_result_array_to_variant (GPtrArray *results)
Richard Hughes8bbfdf42015-02-26 22:28:09 +0000282{
Richard Hughes9945edb2017-06-19 10:03:55 +0100283 GVariantBuilder builder;
284 g_return_val_if_fail (results->len > 0, NULL);
285 g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
286 for (guint i = 0; i < results->len; i++) {
Richard Hughes93b15762017-09-15 11:05:23 +0100287 FwupdDevice *result = g_ptr_array_index (results, i);
Richard Hughese0bd53e2017-09-17 08:29:02 +0100288 GVariant *tmp = fwupd_device_to_variant (result);
Richard Hughes9945edb2017-06-19 10:03:55 +0100289 g_variant_builder_add_value (&builder, tmp);
290 }
Richard Hughes9e1b1402017-09-15 16:29:54 +0100291 return g_variant_new ("(aa{sv})", &builder);
Richard Hughesf508e762015-02-27 12:49:36 +0000292}
293
Richard Hughesf508e762015-02-27 12:49:36 +0000294typedef struct {
295 GDBusMethodInvocation *invocation;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100296 PolkitSubject *subject;
297 GPtrArray *install_tasks;
298 GPtrArray *action_ids;
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000299 GPtrArray *checksums;
Richard Hughes3d607622019-03-07 16:59:27 +0000300 guint64 flags;
Richard Hughes5d14def2015-10-07 17:43:10 +0100301 GBytes *blob_cab;
Richard Hughes67ec8982015-03-03 11:39:27 +0000302 FuMainPrivate *priv;
Richard Hughes9945edb2017-06-19 10:03:55 +0100303 gchar *device_id;
Richard Hughesa6bd5582017-09-07 14:32:22 +0100304 gchar *remote_id;
305 gchar *key;
306 gchar *value;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100307 XbSilo *silo;
Richard Hughesf508e762015-02-27 12:49:36 +0000308} FuMainAuthHelper;
309
Richard Hughesf508e762015-02-27 12:49:36 +0000310static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100311fu_main_auth_helper_free (FuMainAuthHelper *helper)
Richard Hughesf508e762015-02-27 12:49:36 +0000312{
Richard Hughes4ced4662016-08-26 11:02:31 +0100313 if (helper->blob_cab != NULL)
Richard Hughes5d14def2015-10-07 17:43:10 +0100314 g_bytes_unref (helper->blob_cab);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100315 if (helper->subject != NULL)
316 g_object_unref (helper->subject);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100317 if (helper->silo != NULL)
318 g_object_unref (helper->silo);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100319 if (helper->install_tasks != NULL)
320 g_ptr_array_unref (helper->install_tasks);
321 if (helper->action_ids != NULL)
322 g_ptr_array_unref (helper->action_ids);
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000323 if (helper->checksums != NULL)
324 g_ptr_array_unref (helper->checksums);
Richard Hughes9945edb2017-06-19 10:03:55 +0100325 g_free (helper->device_id);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100326 g_free (helper->remote_id);
327 g_free (helper->key);
328 g_free (helper->value);
Richard Hughes67ec8982015-03-03 11:39:27 +0000329 g_object_unref (helper->invocation);
Richard Hughesf508e762015-02-27 12:49:36 +0000330 g_free (helper);
331}
332
Mario Limoncielloa98df552018-04-16 12:15:51 -0500333#pragma clang diagnostic push
334#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughes9945edb2017-06-19 10:03:55 +0100335G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainAuthHelper, fu_main_auth_helper_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -0500336#pragma clang diagnostic pop
Richard Hughes9945edb2017-06-19 10:03:55 +0100337
338/* error may or may not already have been set */
Richard Hughesb75c92d2016-02-20 20:22:00 +0000339static gboolean
Richard Hughes9945edb2017-06-19 10:03:55 +0100340fu_main_authorization_is_valid (PolkitAuthorizationResult *auth, GError **error)
Richard Hughes9a410ce2016-02-28 15:58:54 +0000341{
Richard Hughes9945edb2017-06-19 10:03:55 +0100342 /* failed */
Richard Hughesf508e762015-02-27 12:49:36 +0000343 if (auth == NULL) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100344 g_autofree gchar *message = g_strdup ((*error)->message);
345 g_clear_error (error);
346 g_set_error (error,
Richard Hughes060af612016-08-17 17:32:34 +0100347 FWUPD_ERROR,
348 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100349 "Could not check for auth: %s", message);
350 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000351 }
352
353 /* did not auth */
354 if (!polkit_authorization_result_get_is_authorized (auth)) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100355 g_set_error_literal (error,
Richard Hughes060af612016-08-17 17:32:34 +0100356 FWUPD_ERROR,
357 FWUPD_ERROR_AUTH_FAILED,
Richard Hughes9945edb2017-06-19 10:03:55 +0100358 "Failed to obtain auth");
359 return FALSE;
Richard Hughesf508e762015-02-27 12:49:36 +0000360 }
361
362 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100363 return TRUE;
Richard Hughes5d14def2015-10-07 17:43:10 +0100364}
365
Richard Hughesdf7950b2016-01-31 10:18:40 +0000366static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100367fu_main_authorize_unlock_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100368{
Richard Hughes9945edb2017-06-19 10:03:55 +0100369 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
370 g_autoptr(GError) error = NULL;
371 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100372
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100373
Richard Hughes9945edb2017-06-19 10:03:55 +0100374 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100375 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100376 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
377 res, &error);
378 if (!fu_main_authorization_is_valid (auth, &error)) {
379 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100380 return;
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100381 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100382
383 /* authenticated */
384 if (!fu_engine_unlock (helper->priv->engine, helper->device_id, &error)) {
385 g_dbus_method_invocation_return_gerror (helper->invocation, error);
386 return;
387 }
388
389 /* success */
390 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes3d2fc1e2017-06-08 14:26:31 +0100391}
392
393static void
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000394fu_main_authorize_set_approved_firmware_cb (GObject *source, GAsyncResult *res, gpointer user_data)
395{
396 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
397 g_autoptr(GError) error = NULL;
398 g_autoptr(PolkitAuthorizationResult) auth = NULL;
399
400 /* get result */
401 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
402 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
403 res, &error);
404 if (!fu_main_authorization_is_valid (auth, &error)) {
405 g_dbus_method_invocation_return_gerror (helper->invocation, error);
406 return;
407 }
408
409 /* success */
410 for (guint i = 0; i < helper->checksums->len; i++) {
411 const gchar *csum = g_ptr_array_index (helper->checksums, i);
412 fu_engine_add_approved_firmware (helper->priv->engine, csum);
413 }
414 g_dbus_method_invocation_return_value (helper->invocation, NULL);
415}
416
417static void
Richard Hughes3d607622019-03-07 16:59:27 +0000418fu_main_authorize_self_sign_cb (GObject *source, GAsyncResult *res, gpointer user_data)
419{
420 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
421 g_autofree gchar *sig = NULL;
422 g_autoptr(GError) error = NULL;
423 g_autoptr(PolkitAuthorizationResult) auth = NULL;
424
425 /* get result */
426 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
427 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
428 res, &error);
429 if (!fu_main_authorization_is_valid (auth, &error)) {
430 g_dbus_method_invocation_return_gerror (helper->invocation, error);
431 return;
432 }
433
434 /* authenticated */
435 sig = fu_engine_self_sign (helper->priv->engine, helper->value, helper->flags, &error);
436 if (sig == NULL) {
437 g_dbus_method_invocation_return_gerror (helper->invocation, error);
438 return;
439 }
440
441 /* success */
442 g_dbus_method_invocation_return_value (helper->invocation, g_variant_new ("(s)", sig));
443}
444
445static void
Mario Limonciello96a0dd52019-02-25 13:50:03 -0600446fu_main_authorize_activate_cb (GObject *source, GAsyncResult *res, gpointer user_data)
447{
448 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
449 g_autoptr(GError) error = NULL;
450 g_autoptr(PolkitAuthorizationResult) auth = NULL;
451
452 /* get result */
453 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
454 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
455 res, &error);
456 if (!fu_main_authorization_is_valid (auth, &error)) {
457 g_dbus_method_invocation_return_gerror (helper->invocation, error);
458 return;
459 }
460
461 /* authenticated */
462 if (!fu_engine_activate (helper->priv->engine, helper->device_id, &error)) {
463 g_dbus_method_invocation_return_gerror (helper->invocation, error);
464 return;
465 }
466
467 /* success */
468 g_dbus_method_invocation_return_value (helper->invocation, NULL);
469}
470
471static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100472fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughesdf7950b2016-01-31 10:18:40 +0000473{
Richard Hughes9945edb2017-06-19 10:03:55 +0100474 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
475 g_autoptr(GError) error = NULL;
476 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughesdf7950b2016-01-31 10:18:40 +0000477
Richard Hughes9945edb2017-06-19 10:03:55 +0100478 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100479 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100480 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
481 res, &error);
482 if (!fu_main_authorization_is_valid (auth, &error)) {
483 g_dbus_method_invocation_return_gerror (helper->invocation, error);
Richard Hughesdf7950b2016-01-31 10:18:40 +0000484 return;
Richard Hughesf192bf02016-07-22 08:26:43 +0100485 }
Richard Hughesdf7950b2016-01-31 10:18:40 +0000486
Richard Hughes9945edb2017-06-19 10:03:55 +0100487 /* authenticated */
488 if (!fu_engine_verify_update (helper->priv->engine, helper->device_id, &error)) {
489 g_dbus_method_invocation_return_gerror (helper->invocation, error);
490 return;
Richard Hughes404cc512016-12-21 16:09:48 +0000491 }
492
493 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100494 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes99147f12016-05-17 09:35:04 +0100495}
496
Richard Hughes9945edb2017-06-19 10:03:55 +0100497static void
Richard Hughesa6bd5582017-09-07 14:32:22 +0100498fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data)
499{
500 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
501 g_autoptr(GError) error = NULL;
502 g_autoptr(PolkitAuthorizationResult) auth = NULL;
503
504 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100505 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughesa6bd5582017-09-07 14:32:22 +0100506 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
507 res, &error);
508 if (!fu_main_authorization_is_valid (auth, &error)) {
509 g_dbus_method_invocation_return_gerror (helper->invocation, error);
510 return;
511 }
512
513 /* authenticated */
514 if (!fu_engine_modify_remote (helper->priv->engine,
515 helper->remote_id,
516 helper->key,
517 helper->value,
518 &error)) {
519 g_dbus_method_invocation_return_gerror (helper->invocation, error);
520 return;
521 }
522
523 /* success */
524 g_dbus_method_invocation_return_value (helper->invocation, NULL);
525}
526
Richard Hughes4ad41f02018-05-08 14:35:36 +0100527static void fu_main_authorize_install_queue (FuMainAuthHelper *helper);
528
Richard Hughesa6bd5582017-09-07 14:32:22 +0100529static void
Richard Hughes9945edb2017-06-19 10:03:55 +0100530fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data)
Richard Hughes404cc512016-12-21 16:09:48 +0000531{
Richard Hughes9945edb2017-06-19 10:03:55 +0100532 g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data;
Richard Hughes46832432015-09-11 13:43:15 +0100533 g_autoptr(GError) error = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100534 g_autoptr(PolkitAuthorizationResult) auth = NULL;
Richard Hughes18423292015-03-09 17:10:50 +0000535
Richard Hughes9945edb2017-06-19 10:03:55 +0100536 /* get result */
Richard Hughes87f8a4a2017-10-02 09:42:06 +0100537 fu_main_set_status (helper->priv, FWUPD_STATUS_IDLE);
Richard Hughes9945edb2017-06-19 10:03:55 +0100538 auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source),
539 res, &error);
540 if (!fu_main_authorization_is_valid (auth, &error)) {
541 g_dbus_method_invocation_return_gerror (helper->invocation, error);
542 return;
Richard Hughes0e883ee2015-03-18 17:22:33 +0000543 }
544
Richard Hughes4ad41f02018-05-08 14:35:36 +0100545 /* do the next authentication action ID */
546 fu_main_authorize_install_queue (g_steal_pointer (&helper));
547}
548
549static void
550fu_main_authorize_install_queue (FuMainAuthHelper *helper_ref)
551{
552 FuMainPrivate *priv = helper_ref->priv;
553 g_autoptr(FuMainAuthHelper) helper = helper_ref;
554 g_autoptr(GError) error = NULL;
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500555 gboolean ret;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100556
557 /* still more things to to authenticate */
558 if (helper->action_ids->len > 0) {
559 g_autofree gchar *action_id = g_strdup (g_ptr_array_index (helper->action_ids, 0));
560 g_autoptr(PolkitSubject) subject = g_object_ref (helper->subject);
561 g_ptr_array_remove_index (helper->action_ids, 0);
562 polkit_authority_check_authorization (priv->authority, subject,
563 action_id, NULL,
564 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
565 NULL,
566 fu_main_authorize_install_cb,
567 g_steal_pointer (&helper));
Richard Hughes9945edb2017-06-19 10:03:55 +0100568 return;
Richard Hughes654f6b82016-04-25 12:29:48 +0100569 }
570
Richard Hughes4ad41f02018-05-08 14:35:36 +0100571 /* all authenticated, so install all the things */
Mario Limonciello6754f5a2018-10-11 10:50:03 -0500572 priv->update_in_progress = TRUE;
573 ret = fu_engine_install_tasks (helper->priv->engine,
574 helper->install_tasks,
575 helper->blob_cab,
576 helper->flags,
577 &error);
578 priv->update_in_progress = FALSE;
579 if (priv->pending_sigterm)
580 g_main_loop_quit (priv->loop);
581 if (!ret) {
Richard Hughesdbd8c762018-06-15 20:31:40 +0100582 g_dbus_method_invocation_return_gerror (helper->invocation, error);
583 return;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100584 }
585
Richard Hughes654f6b82016-04-25 12:29:48 +0100586 /* success */
Richard Hughes9945edb2017-06-19 10:03:55 +0100587 g_dbus_method_invocation_return_value (helper->invocation, NULL);
Richard Hughes4c369702017-06-16 15:31:38 +0100588}
589
Richard Hughes4ad41f02018-05-08 14:35:36 +0100590#if !GLIB_CHECK_VERSION(2,54,0)
591static gboolean
592g_ptr_array_find (GPtrArray *haystack, gconstpointer needle, guint *index_)
593{
594 for (guint i = 0; i < haystack->len; i++) {
595 gconstpointer *tmp = g_ptr_array_index (haystack, i);
596 if (tmp == needle) {
597 if (index_ != NULL) {
598 *index_ = i;
599 return TRUE;
600 }
601 }
602 }
603 return FALSE;
604}
605#endif
606
Richard Hughes9f86ade2018-05-10 21:11:22 +0100607static gint
608fu_main_install_task_sort_cb (gconstpointer a, gconstpointer b)
609{
610 FuInstallTask *task_a = *((FuInstallTask **) a);
611 FuInstallTask *task_b = *((FuInstallTask **) b);
Richard Hughesc02cb832018-05-20 10:31:04 +0100612 return fu_install_task_compare (task_a, task_b);
Richard Hughes9f86ade2018-05-10 21:11:22 +0100613}
614
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500615static GPtrArray *
616fu_main_get_device_family (FuMainAuthHelper *helper, GError **error)
617{
618 FuDevice *parent;
619 GPtrArray *children;
620 g_autoptr(FuDevice) device = NULL;
621 g_autoptr(GPtrArray) devices_possible = NULL;
622
623 /* get the device */
624 device = fu_engine_get_device (helper->priv->engine, helper->device_id, error);
625 if (device == NULL)
626 return NULL;
627
628 /* device itself */
629 devices_possible = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
630 g_ptr_array_add (devices_possible, g_object_ref (device));
631
632 /* add device children */
633 children = fu_device_get_children (device);
634 for (guint i = 0; i < children->len; i++) {
635 FuDevice *child = g_ptr_array_index (children, i);
636 g_ptr_array_add (devices_possible, g_object_ref (child));
637 }
638
639 /* add parent and siblings, not including the device itself */
640 parent = fu_device_get_parent (device);
641 if (parent != NULL) {
642 GPtrArray *siblings = fu_device_get_children (parent);
643 g_ptr_array_add (devices_possible, g_object_ref (parent));
644 for (guint i = 0; i < siblings->len; i++) {
645 FuDevice *sibling = g_ptr_array_index (siblings, i);
646 if (sibling == device)
647 continue;
648 g_ptr_array_add (devices_possible, g_object_ref (sibling));
649 }
650 }
651
652 /* success */
653 return g_steal_pointer (&devices_possible);
654}
655
Richard Hughes4ad41f02018-05-08 14:35:36 +0100656static gboolean
657fu_main_install_with_helper (FuMainAuthHelper *helper_ref, GError **error)
658{
659 FuMainPrivate *priv = helper_ref->priv;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100660 g_autoptr(FuMainAuthHelper) helper = helper_ref;
Richard Hughes481aa2a2018-09-18 20:51:46 +0100661 g_autoptr(GPtrArray) components = NULL;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100662 g_autoptr(GPtrArray) devices_possible = NULL;
663 g_autoptr(GPtrArray) errors = NULL;
664
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500665 /* get a list of devices that in some way match the device_id */
Richard Hughes4ad41f02018-05-08 14:35:36 +0100666 if (g_strcmp0 (helper->device_id, FWUPD_DEVICE_ID_ANY) == 0) {
667 devices_possible = fu_engine_get_devices (priv->engine, error);
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500668 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100669 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100670 } else {
Mario Limonciello2dd731b2018-10-09 15:25:18 -0500671 devices_possible = fu_main_get_device_family (helper, error);
672 if (devices_possible == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100673 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100674 }
675
Richard Hughes481aa2a2018-09-18 20:51:46 +0100676 /* parse silo */
677 helper->silo = fu_engine_get_silo_from_blob (priv->engine,
678 helper->blob_cab,
679 error);
680 if (helper->silo == NULL)
Richard Hughes4ad41f02018-05-08 14:35:36 +0100681 return FALSE;
682
Richard Hughes481aa2a2018-09-18 20:51:46 +0100683 /* for each component in the silo */
Mario Limonciello51ddf182019-01-26 00:31:58 -0600684 components = xb_silo_query (helper->silo, "components/component", 0, error);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100685 if (components == NULL)
686 return FALSE;
Richard Hughes4ad41f02018-05-08 14:35:36 +0100687 helper->action_ids = g_ptr_array_new_with_free_func (g_free);
688 helper->install_tasks = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
689 errors = g_ptr_array_new_with_free_func ((GDestroyNotify) g_error_free);
Richard Hughes481aa2a2018-09-18 20:51:46 +0100690 for (guint i = 0; i < components->len; i++) {
691 XbNode *component = g_ptr_array_index (components, i);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100692
693 /* do any devices pass the requirements */
694 for (guint j = 0; j < devices_possible->len; j++) {
695 FuDevice *device = g_ptr_array_index (devices_possible, j);
696 const gchar *action_id;
697 g_autoptr(FuInstallTask) task = NULL;
698 g_autoptr(GError) error_local = NULL;
699
700 /* is this component valid for the device */
Richard Hughes481aa2a2018-09-18 20:51:46 +0100701 task = fu_install_task_new (device, component);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100702 if (!fu_engine_check_requirements (priv->engine,
Richard Hughes1d1f5cf2018-05-19 23:06:03 +0100703 task,
704 helper->flags,
Richard Hughes4ad41f02018-05-08 14:35:36 +0100705 &error_local)) {
706 g_debug ("requirement on %s:%s failed: %s",
707 fu_device_get_id (device),
Richard Hughes481aa2a2018-09-18 20:51:46 +0100708 xb_node_query_text (component, "id", NULL),
Richard Hughes4ad41f02018-05-08 14:35:36 +0100709 error_local->message);
710 g_ptr_array_add (errors, g_steal_pointer (&error_local));
711 continue;
712 }
713
Mario Limonciello7a3df4b2019-01-31 10:27:22 -0600714 /* if component should have an update message from CAB */
715 fu_device_incorporate_from_component (device, component);
716
Richard Hughes4ad41f02018-05-08 14:35:36 +0100717 /* get the action IDs for the valid device */
718 action_id = fu_install_task_get_action_id (task);
719 if (!g_ptr_array_find (helper->action_ids, action_id, NULL))
720 g_ptr_array_add (helper->action_ids, g_strdup (action_id));
721 g_ptr_array_add (helper->install_tasks, g_steal_pointer (&task));
722 }
723 }
724
Richard Hughes9f86ade2018-05-10 21:11:22 +0100725 /* order the install tasks by the device priority */
726 g_ptr_array_sort (helper->install_tasks, fu_main_install_task_sort_cb);
727
Richard Hughes4ad41f02018-05-08 14:35:36 +0100728 /* nothing suitable */
729 if (helper->install_tasks->len == 0) {
Richard Hughese82eef32018-05-20 10:41:26 +0100730 GError *error_tmp = fu_common_error_array_get_best (errors);
Richard Hughes4ad41f02018-05-08 14:35:36 +0100731 g_propagate_error (error, error_tmp);
732 return FALSE;
733 }
734
735 /* authenticate all things in the action_ids */
736 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
737 fu_main_authorize_install_queue (g_steal_pointer (&helper));
738 return TRUE;
739}
740
Richard Hughesb6f79552017-11-11 07:58:17 +0000741static gboolean
742fu_main_device_id_valid (const gchar *device_id, GError **error)
743{
744 if (g_strcmp0 (device_id, FWUPD_DEVICE_ID_ANY) == 0)
745 return TRUE;
746 if (device_id != NULL && strlen (device_id) >= 4)
747 return TRUE;
748 g_set_error (error,
749 FWUPD_ERROR,
750 FWUPD_ERROR_INTERNAL,
751 "invalid device ID: %s",
752 device_id);
753 return FALSE;
754}
755
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000756static void
757fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender,
758 const gchar *object_path, const gchar *interface_name,
759 const gchar *method_name, GVariant *parameters,
760 GDBusMethodInvocation *invocation, gpointer user_data)
761{
762 FuMainPrivate *priv = (FuMainPrivate *) user_data;
Richard Hughes9945edb2017-06-19 10:03:55 +0100763 GVariant *val = NULL;
Richard Hughes060af612016-08-17 17:32:34 +0100764 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000765
Richard Hughes75b965d2018-11-15 13:51:21 +0000766 /* activity */
767 fu_engine_idle_reset (priv->engine);
768
Richard Hughes8dbfb1c2015-02-26 13:07:40 +0000769 if (g_strcmp0 (method_name, "GetDevices") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100770 g_autoptr(GPtrArray) devices = NULL;
Richard Hughesf508e762015-02-27 12:49:36 +0000771 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100772 devices = fu_engine_get_devices (priv->engine, &error);
773 if (devices == NULL) {
774 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100775 return;
776 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500777 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
778 if (val == NULL) {
779 g_dbus_method_invocation_return_gerror (invocation, error);
780 return;
781 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100782 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7708a0f2015-07-21 08:41:22 +0100783 return;
784 }
Richard Hughese4a100c2017-06-04 21:23:50 +0100785 if (g_strcmp0 (method_name, "GetReleases") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100786 const gchar *device_id;
Richard Hughese4a100c2017-06-04 21:23:50 +0100787 g_autoptr(GPtrArray) releases = NULL;
Richard Hughese4a100c2017-06-04 21:23:50 +0100788 g_variant_get (parameters, "(&s)", &device_id);
789 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000790 if (!fu_main_device_id_valid (device_id, &error)) {
791 g_dbus_method_invocation_return_gerror (invocation, error);
792 return;
793 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100794 releases = fu_engine_get_releases (priv->engine, device_id, &error);
795 if (releases == NULL) {
796 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughese4a100c2017-06-04 21:23:50 +0100797 return;
798 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100799 val = fu_main_release_array_to_variant (releases);
800 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughese4a100c2017-06-04 21:23:50 +0100801 return;
802 }
Richard Hughes8dd4c1c2019-03-03 18:27:57 +0000803 if (g_strcmp0 (method_name, "GetApprovedFirmware") == 0) {
804 GVariantBuilder builder;
805 GPtrArray *checksums = fu_engine_get_approved_firmware (priv->engine);
806 g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
807 for (guint i = 0; i < checksums->len; i++) {
808 const gchar *checksum = g_ptr_array_index (checksums, i);
809 g_variant_builder_add_value (&builder, g_variant_new_string (checksum));
810 }
811 val = g_variant_builder_end (&builder);
812 g_dbus_method_invocation_return_value (invocation,
813 g_variant_new_tuple (&val, 1));
814 return;
815 }
816 if (g_strcmp0 (method_name, "SetApprovedFirmware") == 0) {
817 g_autofree gchar *checksums_str = NULL;
818 g_auto(GStrv) checksums = NULL;
819 g_autoptr(FuMainAuthHelper) helper = NULL;
820 g_autoptr(PolkitSubject) subject = NULL;
821
822 g_variant_get (parameters, "(^as)", &checksums);
823 checksums_str = g_strjoinv (",", checksums);
824 g_debug ("Called %s(%s)", method_name, checksums_str);
825
826 /* authenticate */
827 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
828 helper = g_new0 (FuMainAuthHelper, 1);
829 helper->priv = priv;
830 helper->invocation = g_object_ref (invocation);
831 helper->checksums = g_ptr_array_new_with_free_func (g_free);
832 for (guint i = 0; checksums[i] != NULL; i++)
833 g_ptr_array_add (helper->checksums, g_strdup (checksums[i]));
834 subject = polkit_system_bus_name_new (sender);
835 polkit_authority_check_authorization (priv->authority, subject,
836 "org.freedesktop.fwupd.set-approved-firmware",
837 NULL,
838 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
839 NULL,
840 fu_main_authorize_set_approved_firmware_cb,
841 g_steal_pointer (&helper));
842 return;
843 }
Richard Hughes3d607622019-03-07 16:59:27 +0000844 if (g_strcmp0 (method_name, "SelfSign") == 0) {
845 GVariant *prop_value;
846 gchar *prop_key;
847 g_autofree gchar *value = NULL;
848 g_autoptr(FuMainAuthHelper) helper = NULL;
849 g_autoptr(PolkitSubject) subject = NULL;
850 g_autoptr(GVariantIter) iter = NULL;
851
852 g_variant_get (parameters, "(sa{sv})", &value, &iter);
853 g_debug ("Called %s(%s)", method_name, value);
854
855 /* get flags */
856 helper = g_new0 (FuMainAuthHelper, 1);
857 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
858 g_debug ("got option %s", prop_key);
859 if (g_strcmp0 (prop_key, "add-timestamp") == 0 &&
860 g_variant_get_boolean (prop_value) == TRUE)
861 helper->flags |= FU_KEYRING_SIGN_FLAG_ADD_TIMESTAMP;
862 if (g_strcmp0 (prop_key, "add-cert") == 0 &&
863 g_variant_get_boolean (prop_value) == TRUE)
864 helper->flags |= FU_KEYRING_SIGN_FLAG_ADD_CERT;
865 g_variant_unref (prop_value);
866 }
867
868 /* authenticate */
869 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
870 helper->priv = priv;
871 helper->value = g_steal_pointer (&value);
872 helper->invocation = g_object_ref (invocation);
873 subject = polkit_system_bus_name_new (sender);
874 polkit_authority_check_authorization (priv->authority, subject,
875 "org.freedesktop.fwupd.self-sign",
876 NULL,
877 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
878 NULL,
879 fu_main_authorize_self_sign_cb,
880 g_steal_pointer (&helper));
881 return;
882 }
Richard Hughes97284b12017-09-13 17:07:58 +0100883 if (g_strcmp0 (method_name, "GetDowngrades") == 0) {
884 const gchar *device_id;
885 g_autoptr(GPtrArray) releases = NULL;
886 g_variant_get (parameters, "(&s)", &device_id);
887 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000888 if (!fu_main_device_id_valid (device_id, &error)) {
889 g_dbus_method_invocation_return_gerror (invocation, error);
890 return;
891 }
Richard Hughes97284b12017-09-13 17:07:58 +0100892 releases = fu_engine_get_downgrades (priv->engine, device_id, &error);
893 if (releases == NULL) {
894 g_dbus_method_invocation_return_gerror (invocation, error);
895 return;
896 }
897 val = fu_main_release_array_to_variant (releases);
898 g_dbus_method_invocation_return_value (invocation, val);
899 return;
900 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100901 if (g_strcmp0 (method_name, "GetUpgrades") == 0) {
902 const gchar *device_id;
903 g_autoptr(GPtrArray) releases = NULL;
904 g_variant_get (parameters, "(&s)", &device_id);
905 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000906 if (!fu_main_device_id_valid (device_id, &error)) {
907 g_dbus_method_invocation_return_gerror (invocation, error);
908 return;
909 }
Richard Hughesa96413a2017-09-13 17:19:59 +0100910 releases = fu_engine_get_upgrades (priv->engine, device_id, &error);
911 if (releases == NULL) {
912 g_dbus_method_invocation_return_gerror (invocation, error);
913 return;
914 }
915 val = fu_main_release_array_to_variant (releases);
916 g_dbus_method_invocation_return_value (invocation, val);
917 return;
918 }
Richard Hughes4c369702017-06-16 15:31:38 +0100919 if (g_strcmp0 (method_name, "GetRemotes") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100920 g_autoptr(GPtrArray) remotes = NULL;
Richard Hughes4c369702017-06-16 15:31:38 +0100921 g_debug ("Called %s()", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +0100922 remotes = fu_engine_get_remotes (priv->engine, &error);
923 if (remotes == NULL) {
924 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes4c369702017-06-16 15:31:38 +0100925 return;
926 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100927 val = fu_main_remote_array_to_variant (remotes);
928 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes4c369702017-06-16 15:31:38 +0100929 return;
930 }
Richard Hughes476363a2018-01-11 10:08:58 +0000931 if (g_strcmp0 (method_name, "GetHistory") == 0) {
932 g_autoptr(GPtrArray) devices = NULL;
933 g_debug ("Called %s()", method_name);
934 devices = fu_engine_get_history (priv->engine, &error);
935 if (devices == NULL) {
936 g_dbus_method_invocation_return_gerror (invocation, error);
937 return;
938 }
Mario Limoncielloe3016602018-09-06 11:20:59 -0500939 val = fu_main_device_array_to_variant (priv, sender, devices, &error);
940 if (val == NULL) {
941 g_dbus_method_invocation_return_gerror (invocation, error);
942 return;
943 }
Richard Hughes476363a2018-01-11 10:08:58 +0000944 g_dbus_method_invocation_return_value (invocation, val);
945 return;
946 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000947 if (g_strcmp0 (method_name, "ClearResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100948 const gchar *device_id;
949 g_variant_get (parameters, "(&s)", &device_id);
950 g_debug ("Called %s(%s)", method_name, device_id);
951 if (!fu_engine_clear_results (priv->engine, device_id, &error)) {
952 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000953 return;
954 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100955 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000956 return;
957 }
Richard Hughes6b222952018-01-11 10:20:48 +0000958 if (g_strcmp0 (method_name, "ModifyDevice") == 0) {
959 const gchar *device_id;
960 const gchar *key = NULL;
961 const gchar *value = NULL;
962
963 /* check the id exists */
964 g_variant_get (parameters, "(&s&s&s)", &device_id, &key, &value);
965 g_debug ("Called %s(%s,%s=%s)", method_name, device_id, key, value);
966 if (!fu_engine_modify_device (priv->engine, device_id, key, value, &error)) {
967 g_dbus_method_invocation_return_gerror (invocation, error);
968 return;
969 }
970 g_dbus_method_invocation_return_value (invocation, NULL);
971 return;
972 }
Richard Hughes0e883ee2015-03-18 17:22:33 +0000973 if (g_strcmp0 (method_name, "GetResults") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +0100974 const gchar *device_id = NULL;
Richard Hughes93b15762017-09-15 11:05:23 +0100975 g_autoptr(FwupdDevice) result = NULL;
Richard Hughes9945edb2017-06-19 10:03:55 +0100976 g_variant_get (parameters, "(&s)", &device_id);
977 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +0000978 if (!fu_main_device_id_valid (device_id, &error)) {
979 g_dbus_method_invocation_return_gerror (invocation, error);
980 return;
981 }
Richard Hughes9945edb2017-06-19 10:03:55 +0100982 result = fu_engine_get_results (priv->engine, device_id, &error);
983 if (result == NULL) {
984 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes0e883ee2015-03-18 17:22:33 +0000985 return;
986 }
Richard Hughese0bd53e2017-09-17 08:29:02 +0100987 val = fwupd_device_to_variant (result);
988 g_dbus_method_invocation_return_value (invocation,
989 g_variant_new_tuple (&val, 1));
Richard Hughes0e883ee2015-03-18 17:22:33 +0000990 return;
991 }
Richard Hughesba73c762017-09-15 14:31:17 +0100992 if (g_strcmp0 (method_name, "UpdateMetadata") == 0) {
Richard Hughes1b50d962017-06-02 12:23:00 +0100993 GDBusMessage *message;
994 GUnixFDList *fd_list;
Richard Hughes9945edb2017-06-19 10:03:55 +0100995 const gchar *remote_id = NULL;
Richard Hughes1b50d962017-06-02 12:23:00 +0100996 gint fd_data;
997 gint fd_sig;
998
Richard Hughes9945edb2017-06-19 10:03:55 +0100999 g_variant_get (parameters, "(&shh)", &remote_id, &fd_data, &fd_sig);
1000 g_debug ("Called %s(%s,%i,%i)", method_name, remote_id, fd_data, fd_sig);
Richard Hughes1b50d962017-06-02 12:23:00 +01001001
Richard Hughes5935ebd2017-06-16 15:40:31 +01001002 /* update the metadata store */
Richard Hughes1b50d962017-06-02 12:23:00 +01001003 message = g_dbus_method_invocation_get_message (invocation);
1004 fd_list = g_dbus_message_get_unix_fd_list (message);
1005 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 2) {
1006 g_set_error (&error,
1007 FWUPD_ERROR,
1008 FWUPD_ERROR_INTERNAL,
1009 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001010 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001011 return;
1012 }
1013 fd_data = g_unix_fd_list_get (fd_list, 0, &error);
1014 if (fd_data < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001015 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001016 return;
1017 }
1018 fd_sig = g_unix_fd_list_get (fd_list, 1, &error);
1019 if (fd_sig < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001020 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes1b50d962017-06-02 12:23:00 +01001021 return;
1022 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001023
1024 /* store new metadata (will close the fds when done) */
1025 if (!fu_engine_update_metadata (priv->engine, remote_id,
1026 fd_data, fd_sig, &error)) {
Richard Hughesf3d46c62017-11-28 14:01:30 +00001027 g_prefix_error (&error, "Failed to update metadata for %s: ", remote_id);
Richard Hughes9945edb2017-06-19 10:03:55 +01001028 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesae0efdc2015-06-24 16:18:29 +01001029 return;
1030 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001031 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesae0efdc2015-06-24 16:18:29 +01001032 return;
1033 }
Richard Hughes9a410ce2016-02-28 15:58:54 +00001034 if (g_strcmp0 (method_name, "Unlock") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001035 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001036 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes9a410ce2016-02-28 15:58:54 +00001037 g_autoptr(PolkitSubject) subject = NULL;
1038
Richard Hughes9945edb2017-06-19 10:03:55 +01001039 g_variant_get (parameters, "(&s)", &device_id);
1040 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001041 if (!fu_main_device_id_valid (device_id, &error)) {
1042 g_dbus_method_invocation_return_gerror (invocation, error);
1043 return;
1044 }
Richard Hughesfe5cc902016-06-29 10:00:00 +01001045
Richard Hughes9a410ce2016-02-28 15:58:54 +00001046 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001047 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes9945edb2017-06-19 10:03:55 +01001048 helper = g_new0 (FuMainAuthHelper, 1);
1049 helper->priv = priv;
1050 helper->invocation = g_object_ref (invocation);
1051 helper->device_id = g_strdup (device_id);
Richard Hughes9a410ce2016-02-28 15:58:54 +00001052 subject = polkit_system_bus_name_new (sender);
Richard Hughes9945edb2017-06-19 10:03:55 +01001053 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes9a410ce2016-02-28 15:58:54 +00001054 "org.freedesktop.fwupd.device-unlock",
1055 NULL,
1056 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1057 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +01001058 fu_main_authorize_unlock_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001059 g_steal_pointer (&helper));
Richard Hughes9a410ce2016-02-28 15:58:54 +00001060 return;
1061 }
Mario Limonciello96a0dd52019-02-25 13:50:03 -06001062 if (g_strcmp0 (method_name, "Activate") == 0) {
1063 const gchar *device_id = NULL;
1064 g_autoptr(FuMainAuthHelper) helper = NULL;
1065 g_autoptr(PolkitSubject) subject = NULL;
1066
1067 g_variant_get (parameters, "(&s)", &device_id);
1068 g_debug ("Called %s(%s)", method_name, device_id);
1069 if (!fu_main_device_id_valid (device_id, &error)) {
1070 g_dbus_method_invocation_return_gerror (invocation, error);
1071 return;
1072 }
1073
1074 /* authenticate */
1075 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
1076 helper = g_new0 (FuMainAuthHelper, 1);
1077 helper->priv = priv;
1078 helper->invocation = g_object_ref (invocation);
1079 helper->device_id = g_strdup (device_id);
1080 subject = polkit_system_bus_name_new (sender);
1081 polkit_authority_check_authorization (priv->authority, subject,
1082 "org.freedesktop.fwupd.device-activate",
1083 NULL,
1084 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1085 NULL,
1086 fu_main_authorize_activate_cb,
1087 g_steal_pointer (&helper));
1088 return;
1089 }
Richard Hughesa6bd5582017-09-07 14:32:22 +01001090 if (g_strcmp0 (method_name, "ModifyRemote") == 0) {
Richard Hughesa6bd5582017-09-07 14:32:22 +01001091 const gchar *remote_id = NULL;
1092 const gchar *key = NULL;
1093 const gchar *value = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001094 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughesa6bd5582017-09-07 14:32:22 +01001095 g_autoptr(PolkitSubject) subject = NULL;
1096
1097 /* check the id exists */
1098 g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value);
1099 g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value);
1100
1101 /* create helper object */
1102 helper = g_new0 (FuMainAuthHelper, 1);
1103 helper->invocation = g_object_ref (invocation);
1104 helper->remote_id = g_strdup (remote_id);
1105 helper->key = g_strdup (key);
1106 helper->value = g_strdup (value);
1107 helper->priv = priv;
1108
1109 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001110 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughesa6bd5582017-09-07 14:32:22 +01001111 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -05001112 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughesa6bd5582017-09-07 14:32:22 +01001113 "org.freedesktop.fwupd.modify-remote",
1114 NULL,
1115 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1116 NULL,
1117 fu_main_authorize_modify_remote_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001118 g_steal_pointer (&helper));
Richard Hughesa6bd5582017-09-07 14:32:22 +01001119 return;
1120 }
Richard Hughes29c220d2016-12-14 17:09:54 +00001121 if (g_strcmp0 (method_name, "VerifyUpdate") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001122 const gchar *device_id = NULL;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001123 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes29c220d2016-12-14 17:09:54 +00001124 g_autoptr(PolkitSubject) subject = NULL;
1125
1126 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +01001127 g_variant_get (parameters, "(&s)", &device_id);
1128 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001129 if (!fu_main_device_id_valid (device_id, &error)) {
1130 g_dbus_method_invocation_return_gerror (invocation, error);
1131 return;
1132 }
Richard Hughes29c220d2016-12-14 17:09:54 +00001133
Richard Hughes9945edb2017-06-19 10:03:55 +01001134 /* create helper object */
Richard Hughes29c220d2016-12-14 17:09:54 +00001135 helper = g_new0 (FuMainAuthHelper, 1);
Richard Hughes29c220d2016-12-14 17:09:54 +00001136 helper->invocation = g_object_ref (invocation);
Richard Hughes9945edb2017-06-19 10:03:55 +01001137 helper->device_id = g_strdup (device_id);
Richard Hughes29c220d2016-12-14 17:09:54 +00001138 helper->priv = priv;
Richard Hughes29c220d2016-12-14 17:09:54 +00001139
1140 /* authenticate */
Richard Hughes87f8a4a2017-10-02 09:42:06 +01001141 fu_main_set_status (priv, FWUPD_STATUS_WAITING_FOR_AUTH);
Richard Hughes29c220d2016-12-14 17:09:54 +00001142 subject = polkit_system_bus_name_new (sender);
Mario Limonciello6b9f07c2018-04-16 13:52:09 -05001143 polkit_authority_check_authorization (priv->authority, subject,
Richard Hughes29c220d2016-12-14 17:09:54 +00001144 "org.freedesktop.fwupd.verify-update",
1145 NULL,
1146 POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
1147 NULL,
Richard Hughes9945edb2017-06-19 10:03:55 +01001148 fu_main_authorize_verify_update_cb,
Richard Hughes747b9ee2018-04-16 16:46:58 +01001149 g_steal_pointer (&helper));
Richard Hughes29c220d2016-12-14 17:09:54 +00001150 return;
1151 }
Richard Hughesa043c2e2015-06-29 08:43:18 +01001152 if (g_strcmp0 (method_name, "Verify") == 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001153 const gchar *device_id = NULL;
1154 g_variant_get (parameters, "(&s)", &device_id);
1155 g_debug ("Called %s(%s)", method_name, device_id);
Richard Hughesb6f79552017-11-11 07:58:17 +00001156 if (!fu_main_device_id_valid (device_id, &error)) {
1157 g_dbus_method_invocation_return_gerror (invocation, error);
1158 return;
1159 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001160 if (!fu_engine_verify (priv->engine, device_id, &error)) {
1161 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001162 return;
1163 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001164 g_dbus_method_invocation_return_value (invocation, NULL);
Richard Hughesa043c2e2015-06-29 08:43:18 +01001165 return;
1166 }
Richard Hughes63a407a2015-07-22 08:54:14 +01001167 if (g_strcmp0 (method_name, "Install") == 0) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001168 GVariant *prop_value;
Richard Hughes9945edb2017-06-19 10:03:55 +01001169 const gchar *device_id = NULL;
Richard Hughes74cc2172015-02-27 13:19:46 +00001170 gchar *prop_key;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001171 gint32 fd_handle = 0;
1172 gint fd;
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001173 guint64 archive_size_max;
Richard Hughes9945edb2017-06-19 10:03:55 +01001174 GDBusMessage *message;
1175 GUnixFDList *fd_list;
Richard Hughes747b9ee2018-04-16 16:46:58 +01001176 g_autoptr(FuMainAuthHelper) helper = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001177 g_autoptr(GVariantIter) iter = NULL;
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001178
1179 /* check the id exists */
Richard Hughes9945edb2017-06-19 10:03:55 +01001180 g_variant_get (parameters, "(&sha{sv})", &device_id, &fd_handle, &iter);
1181 g_debug ("Called %s(%s,%i)", method_name, device_id, fd_handle);
Richard Hughesb6f79552017-11-11 07:58:17 +00001182 if (!fu_main_device_id_valid (device_id, &error)) {
1183 g_dbus_method_invocation_return_gerror (invocation, error);
1184 return;
1185 }
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001186
Richard Hughes9945edb2017-06-19 10:03:55 +01001187 /* create helper object */
1188 helper = g_new0 (FuMainAuthHelper, 1);
1189 helper->invocation = g_object_ref (invocation);
1190 helper->device_id = g_strdup (device_id);
1191 helper->priv = priv;
1192
1193 /* get flags */
1194 while (g_variant_iter_next (iter, "{&sv}", &prop_key, &prop_value)) {
Richard Hughes74cc2172015-02-27 13:19:46 +00001195 g_debug ("got option %s", prop_key);
1196 if (g_strcmp0 (prop_key, "offline") == 0 &&
1197 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001198 helper->flags |= FWUPD_INSTALL_FLAG_OFFLINE;
Richard Hughese7c12642015-03-04 20:28:59 +00001199 if (g_strcmp0 (prop_key, "allow-older") == 0 &&
1200 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001201 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_OLDER;
Richard Hughese7c12642015-03-04 20:28:59 +00001202 if (g_strcmp0 (prop_key, "allow-reinstall") == 0 &&
1203 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001204 helper->flags |= FWUPD_INSTALL_FLAG_ALLOW_REINSTALL;
Mario Limonciello71a5b982016-05-10 15:38:53 -05001205 if (g_strcmp0 (prop_key, "force") == 0 &&
1206 g_variant_get_boolean (prop_value) == TRUE)
Richard Hughes9945edb2017-06-19 10:03:55 +01001207 helper->flags |= FWUPD_INSTALL_FLAG_FORCE;
Richard Hughes76e0f942018-05-14 16:24:00 +01001208 if (g_strcmp0 (prop_key, "no-history") == 0 &&
1209 g_variant_get_boolean (prop_value) == TRUE)
1210 helper->flags |= FWUPD_INSTALL_FLAG_NO_HISTORY;
Richard Hughes1ffde6c2015-03-02 22:44:48 +00001211 g_variant_unref (prop_value);
Richard Hughes74cc2172015-02-27 13:19:46 +00001212 }
1213
Richard Hughes9945edb2017-06-19 10:03:55 +01001214
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001215 /* get the fd */
1216 message = g_dbus_method_invocation_get_message (invocation);
1217 fd_list = g_dbus_message_get_unix_fd_list (message);
1218 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001219 g_set_error (&error,
1220 FWUPD_ERROR,
1221 FWUPD_ERROR_INTERNAL,
1222 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001223 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001224 return;
1225 }
Richard Hughes7419e962016-11-22 19:48:06 +00001226 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001227 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001228 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001229 return;
1230 }
1231
Richard Hughes9945edb2017-06-19 10:03:55 +01001232 /* parse the cab file before authenticating so we can work out
1233 * what action ID to use, for instance, if this is trusted --
1234 * this will also close the fd when done */
Richard Hughesc7bbbc22018-01-02 22:22:25 +00001235 archive_size_max = fu_engine_get_archive_size_max (priv->engine);
1236 helper->blob_cab = fu_common_get_contents_fd (fd, archive_size_max, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001237 if (helper->blob_cab == NULL) {
1238 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes5d14def2015-10-07 17:43:10 +01001239 return;
1240 }
Richard Hughes4ad41f02018-05-08 14:35:36 +01001241
1242 /* install all the things in the store */
1243 helper->subject = polkit_system_bus_name_new (sender);
1244 if (!fu_main_install_with_helper (g_steal_pointer (&helper), &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001245 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes18423292015-03-09 17:10:50 +00001246 return;
1247 }
1248
Richard Hughes4ad41f02018-05-08 14:35:36 +01001249 /* async return */
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001250 return;
1251 }
Richard Hughes07f963a2017-09-15 14:28:47 +01001252 if (g_strcmp0 (method_name, "GetDetails") == 0) {
Richard Hughes7289a6b2016-05-29 09:27:47 +01001253 GDBusMessage *message;
1254 GUnixFDList *fd_list;
1255 gint32 fd_handle = 0;
1256 gint fd;
Richard Hughes9945edb2017-06-19 10:03:55 +01001257 g_autoptr(GPtrArray) results = NULL;
Richard Hughes7289a6b2016-05-29 09:27:47 +01001258
1259 /* get parameters */
1260 g_variant_get (parameters, "(h)", &fd_handle);
1261 g_debug ("Called %s(%i)", method_name, fd_handle);
1262
1263 /* get the fd */
1264 message = g_dbus_method_invocation_get_message (invocation);
1265 fd_list = g_dbus_message_get_unix_fd_list (message);
1266 if (fd_list == NULL || g_unix_fd_list_get_length (fd_list) != 1) {
Richard Hughes060af612016-08-17 17:32:34 +01001267 g_set_error (&error,
1268 FWUPD_ERROR,
1269 FWUPD_ERROR_INTERNAL,
1270 "invalid handle");
Richard Hughes9945edb2017-06-19 10:03:55 +01001271 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001272 return;
1273 }
Richard Hughes7419e962016-11-22 19:48:06 +00001274 fd = g_unix_fd_list_get (fd_list, 0, &error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001275 if (fd < 0) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001276 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001277 return;
1278 }
1279
Richard Hughes9945edb2017-06-19 10:03:55 +01001280 /* get details about the file (will close the fd when done) */
Richard Hughes07f963a2017-09-15 14:28:47 +01001281 results = fu_engine_get_details (priv->engine, fd, &error);
Richard Hughes9945edb2017-06-19 10:03:55 +01001282 if (results == NULL) {
1283 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001284 return;
1285 }
Richard Hughes9945edb2017-06-19 10:03:55 +01001286 val = fu_main_result_array_to_variant (results);
1287 g_dbus_method_invocation_return_value (invocation, val);
Richard Hughes7289a6b2016-05-29 09:27:47 +01001288 return;
1289 }
Richard Hughes060af612016-08-17 17:32:34 +01001290 g_set_error (&error,
1291 G_DBUS_ERROR,
1292 G_DBUS_ERROR_UNKNOWN_METHOD,
1293 "no such method %s", method_name);
Richard Hughes9945edb2017-06-19 10:03:55 +01001294 g_dbus_method_invocation_return_gerror (invocation, error);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001295}
1296
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001297static GVariant *
1298fu_main_daemon_get_property (GDBusConnection *connection_, const gchar *sender,
1299 const gchar *object_path, const gchar *interface_name,
1300 const gchar *property_name, GError **error,
1301 gpointer user_data)
1302{
Richard Hughes773ce982015-03-09 22:40:57 +00001303 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1304
Richard Hughes75b965d2018-11-15 13:51:21 +00001305 /* activity */
1306 fu_engine_idle_reset (priv->engine);
1307
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001308 if (g_strcmp0 (property_name, "DaemonVersion") == 0)
1309 return g_variant_new_string (VERSION);
1310
Richard Hughesf425d292019-01-18 17:57:39 +00001311 if (g_strcmp0 (property_name, "Tainted") == 0)
1312 return g_variant_new_boolean (fu_engine_get_tainted (priv->engine));
1313
Richard Hughes773ce982015-03-09 22:40:57 +00001314 if (g_strcmp0 (property_name, "Status") == 0)
Richard Hughes9945edb2017-06-19 10:03:55 +01001315 return g_variant_new_uint32 (fu_engine_get_status (priv->engine));
Richard Hughes773ce982015-03-09 22:40:57 +00001316
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001317 /* return an error */
1318 g_set_error (error,
Richard Hughes8645ec92015-03-19 10:14:32 +00001319 G_DBUS_ERROR,
1320 G_DBUS_ERROR_UNKNOWN_PROPERTY,
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001321 "failed to get daemon property %s",
1322 property_name);
1323 return NULL;
1324}
1325
Richard Hughesf517c9a2019-03-22 19:50:35 +00001326static gboolean
1327fu_main_is_running_offline_update (FuMainPrivate *priv)
1328{
1329 const gchar *default_target = NULL;
1330 g_autoptr(GError) error = NULL;
1331 g_autoptr(GVariant) val = NULL;
1332
1333 val = g_dbus_connection_call_sync (priv->connection,
1334 "org.freedesktop.systemd1",
1335 "/org/freedesktop/systemd1",
1336 "org.freedesktop.systemd1.Manager",
1337 "GetDefaultTarget",
1338 NULL, NULL,
1339 G_DBUS_CALL_FLAGS_NONE,
1340 1500, NULL, &error);
1341 if (val == NULL) {
1342 g_warning ("failed to get default.target: %s", error->message);
1343 return FALSE;
1344 }
1345 g_variant_get (val, "(&s)", &default_target);
1346 return g_strcmp0 (default_target, "system-update.target") == 0;
1347}
1348
Richard Hughesfd468842015-04-22 16:44:08 +01001349static void
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001350fu_main_on_bus_acquired_cb (GDBusConnection *connection,
1351 const gchar *name,
1352 gpointer user_data)
1353{
1354 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1355 guint registration_id;
Richard Hughes46832432015-09-11 13:43:15 +01001356 g_autoptr(GError) error = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001357 static const GDBusInterfaceVTable interface_vtable = {
1358 fu_main_daemon_method_call,
1359 fu_main_daemon_get_property,
1360 NULL
1361 };
1362
1363 priv->connection = g_object_ref (connection);
1364 registration_id = g_dbus_connection_register_object (connection,
1365 FWUPD_DBUS_PATH,
1366 priv->introspection_daemon->interfaces[0],
1367 &interface_vtable,
1368 priv, /* user_data */
1369 NULL, /* user_data_free_func */
1370 NULL); /* GError** */
1371 g_assert (registration_id > 0);
Richard Hughes18423292015-03-09 17:10:50 +00001372
Richard Hughesf517c9a2019-03-22 19:50:35 +00001373 /* are we running in the offline target */
1374 if (fu_main_is_running_offline_update (priv))
Richard Hughes86923b92019-03-23 13:57:51 +00001375 fu_engine_add_app_flag (priv->engine, FU_APP_FLAGS_IS_OFFLINE);
Richard Hughesf517c9a2019-03-22 19:50:35 +00001376
Richard Hughes18423292015-03-09 17:10:50 +00001377 /* connect to D-Bus directly */
1378 priv->proxy_uid =
1379 g_dbus_proxy_new_sync (priv->connection,
1380 G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
1381 G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
1382 NULL,
1383 "org.freedesktop.DBus",
1384 "/org/freedesktop/DBus",
1385 "org.freedesktop.DBus",
1386 NULL,
1387 &error);
1388 if (priv->proxy_uid == NULL) {
1389 g_warning ("cannot connect to DBus: %s", error->message);
1390 return;
1391 }
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001392}
1393
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001394static void
1395fu_main_on_name_acquired_cb (GDBusConnection *connection,
1396 const gchar *name,
1397 gpointer user_data)
1398{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001399 g_debug ("FuMain: acquired name: %s", name);
1400}
1401
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001402static void
1403fu_main_on_name_lost_cb (GDBusConnection *connection,
1404 const gchar *name,
1405 gpointer user_data)
1406{
1407 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1408 g_debug ("FuMain: lost name: %s", name);
1409 g_main_loop_quit (priv->loop);
1410}
1411
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001412static gboolean
1413fu_main_timed_exit_cb (gpointer user_data)
1414{
1415 GMainLoop *loop = (GMainLoop *) user_data;
1416 g_main_loop_quit (loop);
1417 return G_SOURCE_REMOVE;
1418}
1419
Richard Hughesf3dc1622019-03-27 12:48:39 +00001420static void
1421fu_main_argv_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file,
1422 GFileMonitorEvent event_type, gpointer user_data)
1423{
1424 FuMainPrivate *priv = (FuMainPrivate *) user_data;
1425
1426 /* can do straight away? */
1427 if (priv->update_in_progress) {
1428 g_warning ("binary changed during a firmware update, ignoring");
1429 return;
1430 }
1431 g_debug ("binary changed, shutting down");
1432 g_main_loop_quit (priv->loop);
1433}
1434
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001435static GDBusNodeInfo *
1436fu_main_load_introspection (const gchar *filename, GError **error)
1437{
Richard Hughes46832432015-09-11 13:43:15 +01001438 g_autoptr(GBytes) data = NULL;
1439 g_autofree gchar *path = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001440
1441 /* lookup data */
1442 path = g_build_filename ("/org/freedesktop/fwupd", filename, NULL);
1443 data = g_resource_lookup_data (fu_get_resource (),
1444 path,
1445 G_RESOURCE_LOOKUP_FLAGS_NONE,
1446 error);
1447 if (data == NULL)
1448 return NULL;
1449
1450 /* build introspection from XML */
1451 return g_dbus_node_info_new_for_xml (g_bytes_get_data (data, NULL), error);
1452}
1453
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001454static void
1455fu_main_private_free (FuMainPrivate *priv)
1456{
1457 if (priv->loop != NULL)
1458 g_main_loop_unref (priv->loop);
1459 if (priv->owner_id > 0)
1460 g_bus_unown_name (priv->owner_id);
1461 if (priv->proxy_uid != NULL)
1462 g_object_unref (priv->proxy_uid);
Richard Hughes9945edb2017-06-19 10:03:55 +01001463 if (priv->engine != NULL)
1464 g_object_unref (priv->engine);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001465 if (priv->connection != NULL)
1466 g_object_unref (priv->connection);
1467 if (priv->authority != NULL)
1468 g_object_unref (priv->authority);
Richard Hughesf3dc1622019-03-27 12:48:39 +00001469 if (priv->argv0_monitor != NULL)
1470 g_object_unref (priv->argv0_monitor);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001471 if (priv->introspection_daemon != NULL)
1472 g_dbus_node_info_unref (priv->introspection_daemon);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001473 g_free (priv);
1474}
1475
Mario Limoncielloa98df552018-04-16 12:15:51 -05001476#pragma clang diagnostic push
1477#pragma clang diagnostic ignored "-Wunused-function"
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001478G_DEFINE_AUTOPTR_CLEANUP_FUNC(FuMainPrivate, fu_main_private_free)
Mario Limoncielloa98df552018-04-16 12:15:51 -05001479#pragma clang diagnostic pop
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001480
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001481int
1482main (int argc, char *argv[])
1483{
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001484 gboolean immediate_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001485 gboolean timed_exit = FALSE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001486 const GOptionEntry options[] = {
1487 { "timed-exit", '\0', 0, G_OPTION_ARG_NONE, &timed_exit,
1488 /* TRANSLATORS: exit after we've started up, used for user profiling */
1489 _("Exit after a small delay"), NULL },
1490 { "immediate-exit", '\0', 0, G_OPTION_ARG_NONE, &immediate_exit,
1491 /* TRANSLATORS: exit straight away, used for automatic profiling */
1492 _("Exit after the engine has loaded"), NULL },
1493 { NULL}
1494 };
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001495 g_autoptr(FuMainPrivate) priv = NULL;
Richard Hughes46832432015-09-11 13:43:15 +01001496 g_autoptr(GError) error = NULL;
Richard Hughesf3dc1622019-03-27 12:48:39 +00001497 g_autoptr(GFile) argv0_file = g_file_new_for_path (argv[0]);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001498 g_autoptr(GOptionContext) context = NULL;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001499
1500 setlocale (LC_ALL, "");
1501
1502 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1503 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1504 textdomain (GETTEXT_PACKAGE);
1505
1506 /* TRANSLATORS: program name */
Richard Hughes63a407a2015-07-22 08:54:14 +01001507 g_set_application_name (_("Firmware Update Daemon"));
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001508 context = g_option_context_new (NULL);
1509 g_option_context_add_main_entries (context, options, NULL);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001510 g_option_context_add_group (context, fu_debug_get_option_group ());
Richard Hughes8ded6ca2015-03-16 12:51:36 +00001511 /* TRANSLATORS: program summary */
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001512 g_option_context_set_summary (context, _("Firmware Update D-Bus Service"));
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001513 if (!g_option_context_parse (context, &argc, &argv, &error)) {
1514 g_printerr ("Failed to parse command line: %s\n", error->message);
1515 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001516 }
1517
1518 /* create new objects */
1519 priv = g_new0 (FuMainPrivate, 1);
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001520 priv->loop = g_main_loop_new (NULL, FALSE);
Richard Hughes8bbfdf42015-02-26 22:28:09 +00001521
Richard Hughes9945edb2017-06-19 10:03:55 +01001522 /* load engine */
Richard Hughes5b5f6552018-05-18 10:22:39 +01001523 priv->engine = fu_engine_new (FU_APP_FLAGS_NONE);
Richard Hughes9945edb2017-06-19 10:03:55 +01001524 g_signal_connect (priv->engine, "changed",
1525 G_CALLBACK (fu_main_engine_changed_cb),
1526 priv);
1527 g_signal_connect (priv->engine, "device-added",
1528 G_CALLBACK (fu_main_engine_device_added_cb),
1529 priv);
1530 g_signal_connect (priv->engine, "device-removed",
1531 G_CALLBACK (fu_main_engine_device_removed_cb),
1532 priv);
1533 g_signal_connect (priv->engine, "device-changed",
1534 G_CALLBACK (fu_main_engine_device_changed_cb),
1535 priv);
1536 g_signal_connect (priv->engine, "status-changed",
1537 G_CALLBACK (fu_main_engine_status_changed_cb),
1538 priv);
1539 g_signal_connect (priv->engine, "percentage-changed",
1540 G_CALLBACK (fu_main_engine_percentage_changed_cb),
1541 priv);
Richard Hughesc8cc77c2019-03-07 11:57:24 +00001542 if (!fu_engine_load (priv->engine, FU_ENGINE_LOAD_FLAG_NONE, &error)) {
Richard Hughes9945edb2017-06-19 10:03:55 +01001543 g_printerr ("Failed to load engine: %s\n", error->message);
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001544 return EXIT_FAILURE;
Richard Hughes804c0752015-08-04 14:53:52 +01001545 }
1546
Mario Limonciello6754f5a2018-10-11 10:50:03 -05001547 g_unix_signal_add_full (G_PRIORITY_DEFAULT,
1548 SIGTERM, fu_main_sigterm_cb,
1549 priv, NULL);
1550
Richard Hughesf3dc1622019-03-27 12:48:39 +00001551 /* restart the daemon if the binary gets replaced */
1552 priv->argv0_monitor = g_file_monitor_file (argv0_file, G_FILE_MONITOR_NONE,
1553 NULL, &error);
1554 g_signal_connect (priv->argv0_monitor, "changed",
1555 G_CALLBACK (fu_main_argv_changed_cb), priv);
1556
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001557 /* load introspection from file */
1558 priv->introspection_daemon = fu_main_load_introspection (FWUPD_DBUS_INTERFACE ".xml",
1559 &error);
1560 if (priv->introspection_daemon == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001561 g_printerr ("Failed to load introspection: %s\n", error->message);
1562 return EXIT_FAILURE;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001563 }
1564
Richard Hughesf508e762015-02-27 12:49:36 +00001565 /* get authority */
1566 priv->authority = polkit_authority_get_sync (NULL, &error);
1567 if (priv->authority == NULL) {
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001568 g_printerr ("Failed to load authority: %s\n", error->message);
1569 return EXIT_FAILURE;
Richard Hughesf508e762015-02-27 12:49:36 +00001570 }
1571
Richard Hughesebae3962018-09-09 13:40:49 +01001572 /* own the object */
1573 priv->owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
1574 FWUPD_DBUS_SERVICE,
1575 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
1576 G_BUS_NAME_OWNER_FLAGS_REPLACE,
1577 fu_main_on_bus_acquired_cb,
1578 fu_main_on_name_acquired_cb,
1579 fu_main_on_name_lost_cb,
1580 priv, NULL);
1581
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001582 /* Only timeout and close the mainloop if we have specified it
1583 * on the command line */
1584 if (immediate_exit)
1585 g_idle_add (fu_main_timed_exit_cb, priv->loop);
1586 else if (timed_exit)
1587 g_timeout_add_seconds (5, fu_main_timed_exit_cb, priv->loop);
1588
Mario Limonciello46bb4e92019-01-07 09:44:31 -06001589 g_debug ("Started with locale %s", g_getenv ("LANG"));
1590
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001591 /* wait */
Richard Hughes4619f9f2017-06-14 13:55:30 +01001592 g_message ("Daemon ready for requests");
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001593 g_main_loop_run (priv->loop);
1594
1595 /* success */
Richard Hughesf29a6ee2017-06-02 19:50:37 +01001596 return EXIT_SUCCESS;
Richard Hughes8dbfb1c2015-02-26 13:07:40 +00001597}