diff --git a/data/daemon.conf b/data/daemon.conf index 6a576cfd5..879940813 100644 --- a/data/daemon.conf +++ b/data/daemon.conf @@ -36,3 +36,9 @@ ApprovedFirmware= # Allow blocking specific devices by their checksum, either SHA1 or SHA256 # Uses semicolons as delimiter BlockedFirmware= + +# Allowed URI schemes in the preference order; failed downloads from the first +# scheme will be retried with the next in order until no choices remain. +# +# If unset or no schemes are listed, the default will be: file,https,http,ipfs +UriSchemes= diff --git a/src/fu-config.c b/src/fu-config.c index 4b6fac9ca..6dc31cc88 100644 --- a/src/fu-config.c +++ b/src/fu-config.c @@ -31,6 +31,7 @@ struct _FuConfig GPtrArray *disabled_plugins; /* (element-type utf-8) */ GPtrArray *approved_firmware; /* (element-type utf-8) */ GPtrArray *blocked_firmware; /* (element-type utf-8) */ + GPtrArray *uri_schemes; /* (element-type utf-8) */ guint64 archive_size_max; guint idle_timeout; gchar *config_file; @@ -54,6 +55,7 @@ fu_config_reload (FuConfig *self, GError **error) guint idle_timeout; g_auto(GStrv) approved_firmware = NULL; g_auto(GStrv) blocked_firmware = NULL; + g_auto(GStrv) uri_schemes = NULL; g_auto(GStrv) devices = NULL; g_auto(GStrv) plugins = NULL; g_autofree gchar *domains = NULL; @@ -122,6 +124,26 @@ fu_config_reload (FuConfig *self, GError **error) } } + /* get download schemes */ + g_ptr_array_set_size (self->uri_schemes, 0); + uri_schemes = g_key_file_get_string_list (keyfile, + "fwupd", + "UriSchemes", + NULL, /* length */ + NULL); + if (uri_schemes != NULL) { + for (guint i = 0; uri_schemes[i] != NULL; i++) { + g_ptr_array_add (self->uri_schemes, + g_strdup (uri_schemes[i])); + } + } + if (self->uri_schemes->len == 0) { + g_ptr_array_add (self->uri_schemes, g_strdup ("file")); + g_ptr_array_add (self->uri_schemes, g_strdup ("https")); + g_ptr_array_add (self->uri_schemes, g_strdup ("http")); + g_ptr_array_add (self->uri_schemes, g_strdup ("ipfs")); + } + /* get maximum archive size, defaulting to something sane */ archive_size_max = g_key_file_get_uint64 (keyfile, "fwupd", @@ -263,6 +285,24 @@ fu_config_get_blocked_firmware (FuConfig *self) return self->blocked_firmware; } +guint +fu_config_get_uri_scheme_prio (FuConfig *self, const gchar *scheme) +{ +#if GLIB_CHECK_VERSION(2,54,0) + guint idx = G_MAXUINT; + g_ptr_array_find_with_equal_func (self->uri_schemes, + scheme, g_str_equal, &idx); + return idx; +#else + for (guint i = 0; i < self->uri_schemes->len; i++) + const gchar *scheme_tmp = g_ptr_array_index (self->uri_schemes, i); + if (g_str_equal (scheme_tmp, scheme)) + return i; + } + return G_MAXUINT; +#endif +} + guint64 fu_config_get_archive_size_max (FuConfig *self) { @@ -318,6 +358,7 @@ fu_config_init (FuConfig *self) self->disabled_plugins = g_ptr_array_new_with_free_func (g_free); self->approved_firmware = g_ptr_array_new_with_free_func (g_free); self->blocked_firmware = g_ptr_array_new_with_free_func (g_free); + self->uri_schemes = g_ptr_array_new_with_free_func (g_free); } static void @@ -333,6 +374,7 @@ fu_config_finalize (GObject *obj) g_ptr_array_unref (self->disabled_plugins); g_ptr_array_unref (self->approved_firmware); g_ptr_array_unref (self->blocked_firmware); + g_ptr_array_unref (self->uri_schemes); g_free (self->config_file); G_OBJECT_CLASS (fu_config_parent_class)->finalize (obj); diff --git a/src/fu-config.h b/src/fu-config.h index 6c8d6e340..dea287407 100644 --- a/src/fu-config.h +++ b/src/fu-config.h @@ -27,5 +27,7 @@ GPtrArray *fu_config_get_disabled_devices (FuConfig *self); GPtrArray *fu_config_get_disabled_plugins (FuConfig *self); GPtrArray *fu_config_get_approved_firmware (FuConfig *self); GPtrArray *fu_config_get_blocked_firmware (FuConfig *self); +guint fu_config_get_uri_scheme_prio (FuConfig *self, + const gchar *protocol); gboolean fu_config_get_update_motd (FuConfig *self); gboolean fu_config_get_enumerate_all_devices (FuConfig *self); diff --git a/src/fu-engine.c b/src/fu-engine.c index 1b60f8dd6..36134d1da 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -325,6 +325,23 @@ fu_engine_get_release_version (FuEngine *self, FuDevice *dev, XbNode *rel, GErro return fu_common_version_from_uint32 ((guint32) ver_uint32, fmt); } +static gint +fu_engine_scheme_compare_cb (gconstpointer a, gconstpointer b, gpointer user_data) +{ + FuEngine *self = FU_ENGINE (user_data); + const gchar *location1 = *((const gchar ** )a); + const gchar *location2 = *((const gchar **) b); + g_autofree gchar *scheme1 = fu_common_uri_get_scheme (location1); + g_autofree gchar *scheme2 = fu_common_uri_get_scheme (location2); + guint prio1 = fu_config_get_uri_scheme_prio (self->config, scheme1); + guint prio2 = fu_config_get_uri_scheme_prio (self->config, scheme2); + if (prio1 < prio2) + return -1; + if (prio1 > prio2) + return 1; + return 0; +} + static gboolean fu_engine_set_release_from_artifact (FuEngine *self, FwupdRelease *rel, @@ -341,6 +358,17 @@ fu_engine_set_release_from_artifact (FuEngine *self, if (locations != NULL) { for (guint i = 0; i < locations->len; i++) { XbNode *n = g_ptr_array_index (locations, i); + g_autofree gchar *scheme = NULL; + + /* check the scheme is allowed */ + scheme = fu_common_uri_get_scheme (xb_node_get_text (n)); + if (scheme != NULL) { + guint prio = fu_config_get_uri_scheme_prio (self->config, scheme); + if (prio == G_MAXUINT) + continue; + } + + /* build the complete URI */ if (remote != NULL) { g_autofree gchar *uri = NULL; uri = fwupd_remote_build_firmware_uri (remote, @@ -530,6 +558,10 @@ fu_engine_set_release_from_appstream (FuEngine *self, tmp = xb_node_query_text (component, "custom/value[@key='LVFS::UpdateImage']", NULL); if (tmp != NULL) fwupd_release_set_update_image (rel, tmp); + + /* sort the locations by scheme */ + g_ptr_array_sort_with_data (fwupd_release_get_locations (rel), + fu_engine_scheme_compare_cb, self); return TRUE; }