diff --git a/libfwupd/fwupd-client.c b/libfwupd/fwupd-client.c index 15369a927..1d6ab65ef 100644 --- a/libfwupd/fwupd-client.c +++ b/libfwupd/fwupd-client.c @@ -1296,6 +1296,61 @@ fwupd_client_get_remotes (FwupdClient *client, GCancellable *cancellable, GError return fwupd_client_parse_remotes_from_data (val); } +/** + * fwupd_client_modify_remote: + * @client: A #FwupdClient + * @remote_id: the remote ID, e.g. "lvfs-testing" + * @key: the key, e.g. "Enabled" + * @value: the key, e.g. "true" + * @cancellable: the #GCancellable, or %NULL + * @error: the #GError, or %NULL + * + * Modifies a system remote in a specific way. + * + * NOTE: User authentication may be required to complete this action. + * + * Returns: %TRUE for success + * + * Since: 0.9.8 + **/ +gboolean +fwupd_client_modify_remote (FwupdClient *client, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error) +{ + FwupdClientPrivate *priv = GET_PRIVATE (client); + g_autoptr(GVariant) val = NULL; + + g_return_val_if_fail (FWUPD_IS_CLIENT (client), FALSE); + g_return_val_if_fail (remote_id != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + /* connect */ + if (!fwupd_client_connect (client, cancellable, error)) + return FALSE; + + /* call into daemon */ + val = g_dbus_proxy_call_sync (priv->proxy, + "ModifyRemote", + g_variant_new ("(sss)", remote_id, key, value), + G_DBUS_CALL_FLAGS_NONE, + -1, + cancellable, + error); + if (val == NULL) { + if (error != NULL) + fwupd_client_fixup_dbus_error (*error); + return FALSE; + } + return TRUE; +} + static FwupdRemote * fwupd_client_get_remote_by_id_noref (GPtrArray *remotes, const gchar *remote_id) { diff --git a/libfwupd/fwupd-client.h b/libfwupd/fwupd-client.h index 9fbedfdc1..c4a7f266a 100644 --- a/libfwupd/fwupd-client.h +++ b/libfwupd/fwupd-client.h @@ -122,6 +122,12 @@ gboolean fwupd_client_update_metadata_with_id (FwupdClient *client, const gchar *signature_fn, GCancellable *cancellable, GError **error); +gboolean fwupd_client_modify_remote (FwupdClient *client, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GCancellable *cancellable, + GError **error); FwupdStatus fwupd_client_get_status (FwupdClient *client); guint fwupd_client_get_percentage (FwupdClient *client); const gchar *fwupd_client_get_daemon_version (FwupdClient *client); diff --git a/libfwupd/fwupd-remote.c b/libfwupd/fwupd-remote.c index 4c7c5ca32..a11780a37 100644 --- a/libfwupd/fwupd-remote.c +++ b/libfwupd/fwupd-remote.c @@ -41,6 +41,7 @@ struct _FwupdRemote gchar *filename_asc; gchar *filename_cache; gchar *filename_cache_sig; + gchar *filename_source; gboolean enabled; SoupURI *uri; SoupURI *uri_asc; @@ -104,6 +105,13 @@ fwupd_remote_set_id (FwupdRemote *self, const gchar *id) g_strdelimit (self->id, ".", '\0'); } +static void +fwupd_remote_set_filename_source (FwupdRemote *self, const gchar *filename_source) +{ + g_free (self->filename_source); + self->filename_source = g_strdup (filename_source); +} + static const gchar * fwupd_remote_get_suffix_for_keyring_kind (FwupdKeyringKind keyring_kind) { @@ -350,6 +358,7 @@ fwupd_remote_load_from_filename (FwupdRemote *self, self->order_after = g_strsplit_set (order_after, ",:;", -1); /* success */ + fwupd_remote_set_filename_source (self, filename); return TRUE; } @@ -403,6 +412,23 @@ fwupd_remote_get_filename_cache_sig (FwupdRemote *self) return self->filename_cache_sig; } +/** + * fwupd_remote_get_filename_source: + * @self: A #FwupdRemote + * + * Gets the path and filename of the remote itself, typically a `.conf` file. + * + * Returns: a string, or %NULL for unset + * + * Since: 0.9.8 + **/ +const gchar * +fwupd_remote_get_filename_source (FwupdRemote *self) +{ + g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); + return self->filename_source; +} + /** * fwupd_remote_get_priority: * @self: A #FwupdRemote @@ -767,6 +793,10 @@ fwupd_remote_to_variant_builder (FwupdRemote *self, GVariantBuilder *builder) g_variant_builder_add (builder, "{sv}", "FilenameCache", g_variant_new_string (self->filename_cache)); } + if (self->filename_source != NULL) { + g_variant_builder_add (builder, "{sv}", "FilenameSource", + g_variant_new_string (self->filename_source)); + } g_variant_builder_add (builder, "{sv}", "Enabled", g_variant_new_boolean (self->enabled)); } @@ -793,6 +823,8 @@ fwupd_remote_set_from_variant_iter (FwupdRemote *self, GVariantIter *iter) fwupd_remote_set_metadata_uri (self, g_variant_get_string (value, NULL)); if (g_strcmp0 (key, "FilenameCache") == 0) fwupd_remote_set_filename_cache (self, g_variant_get_string (value, NULL)); + if (g_strcmp0 (key, "FilenameSource") == 0) + fwupd_remote_set_filename_source (self, g_variant_get_string (value, NULL)); } while (g_variant_iter_loop (iter3, "{sv}", &key, &value)) { if (g_strcmp0 (key, "Username") == 0) { @@ -932,6 +964,7 @@ fwupd_remote_finalize (GObject *obj) g_free (self->filename_asc); g_free (self->filename_cache); g_free (self->filename_cache_sig); + g_free (self->filename_source); g_strfreev (self->order_after); g_strfreev (self->order_before); if (self->uri != NULL) diff --git a/libfwupd/fwupd-remote.h b/libfwupd/fwupd-remote.h index 2f7171770..33aa82089 100644 --- a/libfwupd/fwupd-remote.h +++ b/libfwupd/fwupd-remote.h @@ -50,6 +50,7 @@ const gchar *fwupd_remote_get_username (FwupdRemote *self); const gchar *fwupd_remote_get_password (FwupdRemote *self); const gchar *fwupd_remote_get_filename_cache (FwupdRemote *self); const gchar *fwupd_remote_get_filename_cache_sig (FwupdRemote *self); +const gchar *fwupd_remote_get_filename_source (FwupdRemote *self); const gchar *fwupd_remote_get_firmware_base_uri (FwupdRemote *self); const gchar *fwupd_remote_get_metadata_uri (FwupdRemote *self); const gchar *fwupd_remote_get_metadata_uri_sig (FwupdRemote *self); diff --git a/policy/org.freedesktop.fwupd.policy.in b/policy/org.freedesktop.fwupd.policy.in index c157e65f0..04d2c6370 100644 --- a/policy/org.freedesktop.fwupd.policy.in +++ b/policy/org.freedesktop.fwupd.policy.in @@ -101,4 +101,15 @@ + + Modify a configured remote + + Authentication is required to modify a configured remote used for firmware updates + + auth_admin + no + auth_admin_keep + + + diff --git a/src/fu-engine.c b/src/fu-engine.c index 0a01058d8..a5837a8d0 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -496,6 +496,61 @@ fu_engine_load_verify_store (GError **error) return g_steal_pointer (&store); } +/** + * fu_engine_modify_remote: + * @self: A #FuEngine + * @remote_id: A remote ID + * @key: the key, e.g. "Enabled" + * @value: the key, e.g. "true" + * @error: A #GError, or %NULL + * + * Updates the verification store entry for a specific device. + * + * Returns: %TRUE for success + **/ +gboolean +fu_engine_modify_remote (FuEngine *self, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GError **error) +{ + FwupdRemote *remote; + const gchar *filename; + const gchar *keys[] = { "Enabled", "MetadataURI", "FirmwareBaseURI", NULL }; + g_autoptr(GKeyFile) keyfile = g_key_file_new (); + + /* check remote is valid */ + remote = fu_config_get_remote_by_id (self->config, remote_id); + if (remote == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "remote %s not found", remote_id); + return FALSE; + } + + /* check keys are valid */ + if (!g_strv_contains (keys, key)) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_NOT_FOUND, + "key %s not supported", key); + return FALSE; + } + + /* modify the remote filename */ + filename = fwupd_remote_get_filename_source (remote); + if (!g_key_file_load_from_file (keyfile, filename, + G_KEY_FILE_KEEP_COMMENTS, + error)) { + g_prefix_error (error, "failed to load %s: ", filename); + return FALSE; + } + g_key_file_set_string (keyfile, "fwupd Remote", key, value); + return g_key_file_save_to_file (keyfile, filename, error); +} + /** * fu_engine_verify_update: * @self: A #FuEngine diff --git a/src/fu-engine.h b/src/fu-engine.h index 027f6bfe9..5e8dbb403 100644 --- a/src/fu-engine.h +++ b/src/fu-engine.h @@ -80,6 +80,11 @@ gboolean fu_engine_verify (FuEngine *self, gboolean fu_engine_verify_update (FuEngine *self, const gchar *device_id, GError **error); +gboolean fu_engine_modify_remote (FuEngine *self, + const gchar *remote_id, + const gchar *key, + const gchar *value, + GError **error); gboolean fu_engine_install (FuEngine *self, const gchar *device_id, AsStore *store, diff --git a/src/fu-main.c b/src/fu-main.c index cf066291b..6adef59a2 100644 --- a/src/fu-main.c +++ b/src/fu-main.c @@ -242,6 +242,9 @@ typedef struct { GBytes *blob_cab; FuMainPrivate *priv; gchar *device_id; + gchar *remote_id; + gchar *key; + gchar *value; } FuMainAuthHelper; static void @@ -252,6 +255,9 @@ fu_main_auth_helper_free (FuMainAuthHelper *helper) if (helper->store != NULL) g_object_unref (helper->store); g_free (helper->device_id); + g_free (helper->remote_id); + g_free (helper->key); + g_free (helper->value); g_object_unref (helper->invocation); g_free (helper); } @@ -336,6 +342,35 @@ fu_main_authorize_verify_update_cb (GObject *source, GAsyncResult *res, gpointer g_dbus_method_invocation_return_value (helper->invocation, NULL); } +static void +fu_main_authorize_modify_remote_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr(FuMainAuthHelper) helper = (FuMainAuthHelper *) user_data; + g_autoptr(GError) error = NULL; + g_autoptr(PolkitAuthorizationResult) auth = NULL; + + /* get result */ + auth = polkit_authority_check_authorization_finish (POLKIT_AUTHORITY (source), + res, &error); + if (!fu_main_authorization_is_valid (auth, &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* authenticated */ + if (!fu_engine_modify_remote (helper->priv->engine, + helper->remote_id, + helper->key, + helper->value, + &error)) { + g_dbus_method_invocation_return_gerror (helper->invocation, error); + return; + } + + /* success */ + g_dbus_method_invocation_return_value (helper->invocation, NULL); +} + static void fu_main_authorize_install_cb (GObject *source, GAsyncResult *res, gpointer user_data) { @@ -516,6 +551,36 @@ fu_main_daemon_method_call (GDBusConnection *connection, const gchar *sender, helper); return; } + if (g_strcmp0 (method_name, "ModifyRemote") == 0) { + FuMainAuthHelper *helper; + const gchar *remote_id = NULL; + const gchar *key = NULL; + const gchar *value = NULL; + g_autoptr(PolkitSubject) subject = NULL; + + /* check the id exists */ + g_variant_get (parameters, "(&s&s&s)", &remote_id, &key, &value); + g_debug ("Called %s(%s,%s=%s)", method_name, remote_id, key, value); + + /* create helper object */ + helper = g_new0 (FuMainAuthHelper, 1); + helper->invocation = g_object_ref (invocation); + helper->remote_id = g_strdup (remote_id); + helper->key = g_strdup (key); + helper->value = g_strdup (value); + helper->priv = priv; + + /* authenticate */ + subject = polkit_system_bus_name_new (sender); + polkit_authority_check_authorization (helper->priv->authority, subject, + "org.freedesktop.fwupd.modify-remote", + NULL, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, + fu_main_authorize_modify_remote_cb, + helper); + return; + } if (g_strcmp0 (method_name, "VerifyUpdate") == 0) { FuMainAuthHelper *helper; const gchar *device_id = NULL; diff --git a/src/fu-util.c b/src/fu-util.c index cbb72c4c9..343768bf2 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -1409,6 +1409,21 @@ fu_util_update (FuUtilPrivate *priv, gchar **values, GError **error) return TRUE; } +static gboolean +fu_util_modify_remote (FuUtilPrivate *priv, gchar **values, GError **error) +{ + if (g_strv_length (values) < 3) { + g_set_error_literal (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_ARGS, + "Invalid arguments: expected REMOTE-ID KEY VALUE"); + return FALSE; + } + return fwupd_client_modify_remote (priv->client, + values[0], values[1], values[2], + NULL, error); +} + static gboolean fu_util_downgrade (FuUtilPrivate *priv, gchar **values, GError **error) { @@ -1737,6 +1752,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Dump SMBIOS data from a file"), fu_util_smbios_dump); + fu_util_add (priv->cmd_array, + "modify-remote", + NULL, + /* TRANSLATORS: command description */ + _("Modifies a given remote"), + fu_util_modify_remote); /* do stuff on ctrl+c */ priv->cancellable = g_cancellable_new (); diff --git a/src/org.freedesktop.fwupd.xml b/src/org.freedesktop.fwupd.xml index 8f6e25999..0a4df29e7 100644 --- a/src/org.freedesktop.fwupd.xml +++ b/src/org.freedesktop.fwupd.xml @@ -339,6 +339,44 @@ + + + + + + Modifies a remote in some way. + + + + + + + + Remote ID, e.g. 'lvfs-testing'. + + + + + + + + + The key, e.g. 'Enabled'. + + + + + + + + + The value of the correct type, e.g. a URL. + + + + + +