| /* |
| * Copyright 2017 Richard Hughes <richard@hughsie.com> |
| * |
| * SPDX-License-Identifier: LGPL-2.1-or-later |
| */ |
| |
| #define G_LOG_DOMAIN "FuEngineConfig" |
| |
| #include "config.h" |
| |
| #include <fwupdplugin.h> |
| |
| #include "fu-engine-config.h" |
| |
| struct _FuEngineConfig { |
| FuConfig parent_instance; |
| GPtrArray *disabled_devices; /* (element-type utf-8) */ |
| 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) */ |
| GPtrArray *trusted_reports; /* (element-type FwupdReport) */ |
| GArray *trusted_uids; /* (element-type guint64) */ |
| gchar *host_bkc; |
| gchar *esp_location; |
| }; |
| |
| G_DEFINE_TYPE(FuEngineConfig, fu_engine_config, FU_TYPE_CONFIG) |
| |
| static gboolean |
| fu_engine_config_report_from_flags(FwupdReport *report, const gchar *flags_str, GError **error) |
| { |
| g_auto(GStrv) flags_strv = g_strsplit(flags_str, ",", -1); |
| for (guint i = 0; flags_strv[i] != NULL; i++) { |
| FwupdReportFlags flag = fwupd_report_flag_from_string(flags_strv[i]); |
| if (flag == FWUPD_REPORT_FLAG_UNKNOWN) { |
| g_set_error(error, |
| FWUPD_ERROR, |
| FWUPD_ERROR_INVALID_DATA, |
| "report flag '%s' unknown", |
| flags_strv[i]); |
| return FALSE; |
| } |
| fwupd_report_add_flag(report, flag); |
| } |
| return TRUE; |
| } |
| |
| static FwupdReport * |
| fu_engine_config_report_from_spec(FuEngineConfig *self, const gchar *report_spec, GError **error) |
| { |
| g_auto(GStrv) parts = g_strsplit(report_spec, "&", -1); |
| g_autoptr(FwupdReport) report = fwupd_report_new(); |
| |
| for (guint i = 0; parts[i] != NULL; i++) { |
| g_autofree gchar *value = NULL; |
| g_auto(GStrv) kv = g_strsplit(parts[i], "=", 2); |
| if (g_strv_length(kv) != 2) { |
| g_set_error(error, |
| FWUPD_ERROR, |
| FWUPD_ERROR_INVALID_DATA, |
| "failed to parse report specifier key=value %s", |
| parts[i]); |
| return NULL; |
| } |
| if (g_str_has_prefix(kv[1], "$")) |
| value = g_get_os_info(kv[1] + 1); |
| if (value == NULL) |
| value = g_strdup(kv[1]); |
| if (g_strcmp0(kv[0], "VendorId") == 0) { |
| guint64 tmp = 0; |
| if (g_strcmp0(value, "$OEM") == 0) { |
| fwupd_report_add_flag(report, FWUPD_REPORT_FLAG_FROM_OEM); |
| } else { |
| if (!fu_strtoull(value, |
| &tmp, |
| 0, |
| G_MAXUINT32, |
| FU_INTEGER_BASE_AUTO, |
| error)) { |
| g_prefix_error(error, "failed to parse '%s': ", value); |
| return NULL; |
| } |
| fwupd_report_set_vendor_id(report, tmp); |
| } |
| } else if (g_strcmp0(kv[0], "DistroId") == 0) { |
| fwupd_report_set_distro_id(report, value); |
| } else if (g_strcmp0(kv[0], "DistroVariant") == 0) { |
| fwupd_report_set_distro_variant(report, value); |
| } else if (g_strcmp0(kv[0], "DistroVersion") == 0) { |
| fwupd_report_set_distro_version(report, value); |
| } else if (g_strcmp0(kv[0], "RemoteId") == 0) { |
| fwupd_report_set_remote_id(report, value); |
| } else if (g_strcmp0(kv[0], "Flags") == 0) { |
| if (!fu_engine_config_report_from_flags(report, value, error)) |
| return NULL; |
| } else { |
| g_set_error(error, |
| FWUPD_ERROR, |
| FWUPD_ERROR_INVALID_DATA, |
| "failed to parse report specifier key %s", |
| kv[0]); |
| return NULL; |
| } |
| } |
| |
| /* success */ |
| return g_steal_pointer(&report); |
| } |
| |
| static void |
| fu_engine_config_reload(FuEngineConfig *self) |
| { |
| g_auto(GStrv) approved_firmware = NULL; |
| g_auto(GStrv) blocked_firmware = NULL; |
| g_auto(GStrv) disabled_devices = NULL; |
| g_auto(GStrv) plugins = NULL; |
| g_auto(GStrv) report_specs = NULL; |
| g_auto(GStrv) uids = NULL; |
| g_auto(GStrv) uri_schemes = NULL; |
| g_autofree gchar *domains = NULL; |
| g_autofree gchar *host_bkc = NULL; |
| g_autofree gchar *esp_location = NULL; |
| |
| /* get disabled devices */ |
| g_ptr_array_set_size(self->disabled_devices, 0); |
| disabled_devices = fu_config_get_value_strv(FU_CONFIG(self), "fwupd", "DisabledDevices"); |
| if (disabled_devices != NULL) { |
| for (guint i = 0; disabled_devices[i] != NULL; i++) |
| g_ptr_array_add(self->disabled_devices, g_strdup(disabled_devices[i])); |
| } |
| |
| /* get disabled plugins */ |
| g_ptr_array_set_size(self->disabled_plugins, 0); |
| plugins = fu_config_get_value_strv(FU_CONFIG(self), "fwupd", "DisabledPlugins"); |
| if (plugins != NULL) { |
| for (guint i = 0; plugins[i] != NULL; i++) { |
| g_autofree gchar *plugin_name = fu_strstrip(plugins[i]); |
| if (plugin_name == NULL || plugin_name[0] == '\0') |
| continue; |
| g_strdelimit(plugin_name, "-", '_'); |
| g_ptr_array_add(self->disabled_plugins, g_steal_pointer(&plugin_name)); |
| } |
| } |
| |
| /* get approved firmware */ |
| g_ptr_array_set_size(self->approved_firmware, 0); |
| approved_firmware = fu_config_get_value_strv(FU_CONFIG(self), "fwupd", "ApprovedFirmware"); |
| if (approved_firmware != NULL) { |
| for (guint i = 0; approved_firmware[i] != NULL; i++) |
| g_ptr_array_add(self->approved_firmware, g_strdup(approved_firmware[i])); |
| } |
| |
| /* get blocked firmware */ |
| g_ptr_array_set_size(self->blocked_firmware, 0); |
| blocked_firmware = fu_config_get_value_strv(FU_CONFIG(self), "fwupd", "BlockedFirmware"); |
| if (blocked_firmware != NULL) { |
| for (guint i = 0; blocked_firmware[i] != NULL; i++) |
| g_ptr_array_add(self->blocked_firmware, g_strdup(blocked_firmware[i])); |
| } |
| |
| /* get download schemes */ |
| g_ptr_array_set_size(self->uri_schemes, 0); |
| uri_schemes = fu_config_get_value_strv(FU_CONFIG(self), "fwupd", "UriSchemes"); |
| 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])); |
| } |
| |
| /* get the domains to run in verbose */ |
| domains = fu_config_get_value(FU_CONFIG(self), "fwupd", "VerboseDomains"); |
| if (domains != NULL && domains[0] != '\0') |
| (void)g_setenv("FWUPD_VERBOSE", domains, FALSE); |
| |
| /* fetch host best known configuration */ |
| host_bkc = fu_config_get_value(FU_CONFIG(self), "fwupd", "HostBkc"); |
| if (host_bkc != NULL && host_bkc[0] != '\0') |
| self->host_bkc = g_steal_pointer(&host_bkc); |
| |
| /* fetch hardcoded ESP mountpoint, removing trailing slash as required */ |
| esp_location = fu_config_get_value(FU_CONFIG(self), "fwupd", "EspLocation"); |
| if (esp_location != NULL && esp_location[0] != '\0') { |
| g_autoptr(GString) esp_location_tmp = g_string_new(esp_location); |
| if (g_str_has_suffix(esp_location_tmp->str, "/")) { |
| g_warning("removing trailing slash from EspLocation"); |
| g_string_truncate(esp_location_tmp, esp_location_tmp->len - 1); |
| } |
| self->esp_location = g_string_free(g_steal_pointer(&esp_location_tmp), FALSE); |
| } |
| |
| /* get trusted uids */ |
| g_array_set_size(self->trusted_uids, 0); |
| uids = fu_config_get_value_strv(FU_CONFIG(self), "fwupd", "TrustedUids"); |
| if (uids != NULL) { |
| for (guint i = 0; uids[i] != NULL; i++) { |
| guint64 val = 0; |
| g_autoptr(GError) error_local = NULL; |
| if (!fu_strtoull(uids[i], |
| &val, |
| 0, |
| G_MAXUINT64, |
| FU_INTEGER_BASE_AUTO, |
| &error_local)) { |
| g_warning("failed to parse UID '%s': %s", |
| uids[i], |
| error_local->message); |
| continue; |
| } |
| g_array_append_val(self->trusted_uids, val); |
| } |
| } |
| |
| /* get trusted reports */ |
| g_ptr_array_set_size(self->trusted_reports, 0); |
| report_specs = fu_config_get_value_strv(FU_CONFIG(self), "fwupd", "TrustedReports"); |
| if (report_specs != NULL) { |
| for (guint i = 0; report_specs[i] != NULL; i++) { |
| g_autoptr(GError) error_local = NULL; |
| FwupdReport *report = |
| fu_engine_config_report_from_spec(self, report_specs[i], &error_local); |
| if (report == NULL) { |
| g_warning("failed to parse %s: %s", |
| report_specs[i], |
| error_local->message); |
| continue; |
| } |
| g_ptr_array_add(self->trusted_reports, report); |
| } |
| } |
| } |
| |
| static void |
| fu_engine_config_changed_cb(FuEngineConfig *config, gpointer user_data) |
| { |
| FuEngineConfig *self = FU_ENGINE_CONFIG(config); |
| fu_engine_config_reload(self); |
| } |
| |
| guint |
| fu_engine_config_get_idle_timeout(FuEngineConfig *self) |
| { |
| return fu_config_get_value_u64(FU_CONFIG(self), "fwupd", "IdleTimeout"); |
| } |
| |
| GPtrArray * |
| fu_engine_config_get_disabled_devices(FuEngineConfig *self) |
| { |
| g_return_val_if_fail(FU_IS_ENGINE_CONFIG(self), NULL); |
| return self->disabled_devices; |
| } |
| |
| GArray * |
| fu_engine_config_get_trusted_uids(FuEngineConfig *self) |
| { |
| g_return_val_if_fail(FU_IS_ENGINE_CONFIG(self), NULL); |
| return self->trusted_uids; |
| } |
| |
| GPtrArray * |
| fu_engine_config_get_trusted_reports(FuEngineConfig *self) |
| { |
| g_return_val_if_fail(FU_IS_CONFIG(self), NULL); |
| return self->trusted_reports; |
| } |
| |
| GPtrArray * |
| fu_engine_config_get_blocked_firmware(FuEngineConfig *self) |
| { |
| g_return_val_if_fail(FU_IS_ENGINE_CONFIG(self), NULL); |
| return self->blocked_firmware; |
| } |
| |
| guint |
| fu_engine_config_get_uri_scheme_prio(FuEngineConfig *self, const gchar *scheme) |
| { |
| guint idx = 0; |
| if (!g_ptr_array_find_with_equal_func(self->uri_schemes, scheme, g_str_equal, &idx)) |
| return G_MAXUINT; |
| return idx; |
| } |
| |
| guint64 |
| fu_engine_config_get_archive_size_max(FuEngineConfig *self) |
| { |
| return fu_config_get_value_u64(FU_CONFIG(self), "fwupd", "ArchiveSizeMax"); |
| } |
| |
| GPtrArray * |
| fu_engine_config_get_disabled_plugins(FuEngineConfig *self) |
| { |
| g_return_val_if_fail(FU_IS_ENGINE_CONFIG(self), NULL); |
| return self->disabled_plugins; |
| } |
| |
| GPtrArray * |
| fu_engine_config_get_approved_firmware(FuEngineConfig *self) |
| { |
| g_return_val_if_fail(FU_IS_ENGINE_CONFIG(self), NULL); |
| return self->approved_firmware; |
| } |
| |
| gboolean |
| fu_engine_config_get_update_motd(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "UpdateMotd"); |
| } |
| |
| gboolean |
| fu_engine_config_get_ignore_power(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "IgnorePower"); |
| } |
| |
| gboolean |
| fu_engine_config_get_only_trusted(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "OnlyTrusted"); |
| } |
| |
| gboolean |
| fu_engine_config_get_show_device_private(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "ShowDevicePrivate"); |
| } |
| |
| gboolean |
| fu_engine_config_get_test_devices(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "TestDevices"); |
| } |
| |
| gboolean |
| fu_engine_config_get_ignore_requirements(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "IgnoreRequirements"); |
| } |
| |
| gboolean |
| fu_engine_config_get_ignore_efivars_free_space(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "IgnoreEfivarsFreeSpace"); |
| } |
| |
| gboolean |
| fu_engine_config_get_only_trust_pq_signatures(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "OnlyTrustPostQuantumSignatures"); |
| } |
| |
| gboolean |
| fu_engine_config_get_release_dedupe(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "ReleaseDedupe"); |
| } |
| |
| FuReleasePriority |
| fu_engine_config_get_release_priority(FuEngineConfig *self) |
| { |
| g_autofree gchar *tmp = fu_config_get_value(FU_CONFIG(self), "fwupd", "ReleasePriority"); |
| return fu_release_priority_from_string(tmp); |
| } |
| |
| FuP2pPolicy |
| fu_engine_config_get_p2p_policy(FuEngineConfig *self) |
| { |
| FuP2pPolicy p2p_policy = FU_P2P_POLICY_NOTHING; |
| g_autofree gchar *tmp = fu_config_get_value(FU_CONFIG(self), "fwupd", "P2pPolicy"); |
| g_auto(GStrv) split = g_strsplit(tmp, ",", -1); |
| for (guint i = 0; split[i] != NULL; i++) |
| p2p_policy |= fu_p2p_policy_from_string(split[i]); |
| return p2p_policy; |
| } |
| |
| gboolean |
| fu_engine_config_get_enumerate_all_devices(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "EnumerateAllDevices"); |
| } |
| |
| gboolean |
| fu_engine_config_get_require_immutable_enumeration(FuEngineConfig *self) |
| { |
| return fu_config_get_value_bool(FU_CONFIG(self), "fwupd", "RequireImmutableEnumeration"); |
| } |
| |
| const gchar * |
| fu_engine_config_get_host_bkc(FuEngineConfig *self) |
| { |
| g_return_val_if_fail(FU_IS_ENGINE_CONFIG(self), NULL); |
| return self->host_bkc; |
| } |
| |
| const gchar * |
| fu_engine_config_get_esp_location(FuEngineConfig *self) |
| { |
| g_return_val_if_fail(FU_IS_ENGINE_CONFIG(self), NULL); |
| return self->esp_location; |
| } |
| |
| static gchar * |
| fu_engine_config_archive_size_max_default(void) |
| { |
| guint64 memory_size = fu_common_get_memory_size(); |
| guint64 archive_size_max = memory_size > 0 ? MIN(memory_size / 4, G_MAXUINT32) |
| : 512 * 0x100000; |
| return g_strdup_printf("%" G_GUINT64_FORMAT, archive_size_max); |
| } |
| |
| static void |
| fu_engine_config_set_default(FuEngineConfig *self, const gchar *key, const gchar *value) |
| { |
| fu_config_set_default(FU_CONFIG(self), "fwupd", key, value); |
| } |
| |
| static void |
| fu_engine_config_init(FuEngineConfig *self) |
| { |
| g_autofree gchar *archive_size_max_default = fu_engine_config_archive_size_max_default(); |
| self->disabled_devices = g_ptr_array_new_with_free_func(g_free); |
| 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->trusted_uids = g_array_new(FALSE, FALSE, sizeof(guint64)); |
| self->trusted_reports = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); |
| self->uri_schemes = g_ptr_array_new_with_free_func(g_free); |
| g_signal_connect(self, "loaded", G_CALLBACK(fu_engine_config_changed_cb), NULL); |
| g_signal_connect(self, "changed", G_CALLBACK(fu_engine_config_changed_cb), NULL); |
| |
| /* defaults changed here will also be reflected in the fwupd.conf man page */ |
| fu_engine_config_set_default(self, "ApprovedFirmware", NULL); |
| fu_engine_config_set_default(self, "ArchiveSizeMax", archive_size_max_default); |
| fu_engine_config_set_default(self, "BlockedFirmware", NULL); |
| fu_engine_config_set_default(self, "DisabledDevices", NULL); |
| fu_engine_config_set_default(self, "DisabledPlugins", ""); |
| fu_engine_config_set_default(self, "EnumerateAllDevices", "false"); |
| fu_engine_config_set_default(self, "EspLocation", NULL); |
| fu_engine_config_set_default(self, "HostBkc", NULL); |
| fu_engine_config_set_default(self, "IdleTimeout", "300"); /* s */ |
| fu_engine_config_set_default(self, "IdleInhibitStartupThreshold", "500"); /* ms */ |
| fu_engine_config_set_default(self, "IgnoreEfivarsFreeSpace", "false"); |
| fu_engine_config_set_default(self, "IgnorePower", "false"); |
| fu_engine_config_set_default(self, "IgnoreRequirements", "false"); |
| fu_engine_config_set_default(self, "OnlyTrusted", "true"); |
| fu_engine_config_set_default(self, "P2pPolicy", FU_DEFAULT_P2P_POLICY); |
| fu_engine_config_set_default(self, "ReleaseDedupe", "true"); |
| fu_engine_config_set_default(self, "ReleasePriority", "local"); |
| fu_engine_config_set_default(self, "RequireImmutableEnumeration", "false"); |
| fu_engine_config_set_default(self, "OnlyTrustPostQuantumSignatures", "false"); |
| fu_engine_config_set_default(self, "ShowDevicePrivate", "true"); |
| fu_engine_config_set_default(self, "TestDevices", "false"); |
| fu_engine_config_set_default(self, "TrustedReports", "VendorId=$OEM"); |
| fu_engine_config_set_default(self, "TrustedUids", NULL); |
| fu_engine_config_set_default(self, "UpdateMotd", "true"); |
| fu_engine_config_set_default(self, "UriSchemes", "file;https;http;ipfs"); |
| fu_engine_config_set_default(self, "VerboseDomains", NULL); |
| } |
| |
| static void |
| fu_engine_config_finalize(GObject *obj) |
| { |
| FuEngineConfig *self = FU_ENGINE_CONFIG(obj); |
| |
| g_ptr_array_unref(self->disabled_devices); |
| 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_ptr_array_unref(self->trusted_reports); |
| g_array_unref(self->trusted_uids); |
| g_free(self->host_bkc); |
| g_free(self->esp_location); |
| |
| G_OBJECT_CLASS(fu_engine_config_parent_class)->finalize(obj); |
| } |
| |
| static void |
| fu_engine_config_class_init(FuEngineConfigClass *klass) |
| { |
| GObjectClass *object_class = G_OBJECT_CLASS(klass); |
| object_class->finalize = fu_engine_config_finalize; |
| } |
| |
| FuEngineConfig * |
| fu_engine_config_new(void) |
| { |
| return FU_ENGINE_CONFIG(g_object_new(FU_TYPE_ENGINE_CONFIG, NULL)); |
| } |