diff --git a/libfwupd/fwupd-error.c b/libfwupd/fwupd-error.c index 9f98b939e..f107e15f0 100644 --- a/libfwupd/fwupd-error.c +++ b/libfwupd/fwupd-error.c @@ -59,6 +59,8 @@ fwupd_error_to_string(FwupdError error) return FWUPD_DBUS_INTERFACE ".BatteryLevelTooLow"; if (error == FWUPD_ERROR_NEEDS_USER_ACTION) return FWUPD_DBUS_INTERFACE ".NeedsUserAction"; + if (error == FWUPD_ERROR_AUTH_EXPIRED) + return FWUPD_DBUS_INTERFACE ".AuthExpired"; return NULL; } @@ -109,6 +111,8 @@ fwupd_error_from_string(const gchar *error) return FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW; if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".NeedsUserAction") == 0) return FWUPD_ERROR_NEEDS_USER_ACTION; + if (g_strcmp0(error, FWUPD_DBUS_INTERFACE ".AuthExpired") == 0) + return FWUPD_ERROR_AUTH_EXPIRED; return FWUPD_ERROR_LAST; } diff --git a/libfwupd/fwupd-error.h b/libfwupd/fwupd-error.h index ee0846bcc..13271f84e 100644 --- a/libfwupd/fwupd-error.h +++ b/libfwupd/fwupd-error.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS * @FWUPD_ERROR_BROKEN_SYSTEM: User has configured their system in a broken way * @FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW: The system battery level is too low * @FWUPD_ERROR_NEEDS_USER_ACTION: User needs to do an action to complete the update + * @FWUPD_ERROR_AUTH_EXPIRED: Failed to get auth as credentials have expired * * The error code. **/ @@ -52,6 +53,7 @@ typedef enum { FWUPD_ERROR_BROKEN_SYSTEM, /* Since: 1.2.8 */ FWUPD_ERROR_BATTERY_LEVEL_TOO_LOW, /* Since: 1.2.10 */ FWUPD_ERROR_NEEDS_USER_ACTION, /* Since: 1.3.3 */ + FWUPD_ERROR_AUTH_EXPIRED, /* Since: 1.7.5 */ /*< private >*/ FWUPD_ERROR_LAST } FwupdError; diff --git a/plugins/redfish/fu-plugin-redfish.c b/plugins/redfish/fu-plugin-redfish.c index 327296a98..66c52c210 100644 --- a/plugins/redfish/fu-plugin-redfish.c +++ b/plugins/redfish/fu-plugin-redfish.c @@ -21,6 +21,55 @@ struct FuPluginData { FuRedfishBackend *backend; }; +static gchar * +fu_common_generate_password(guint length) +{ + GString *str = g_string_sized_new(length); + + /* get a random password string */ + while (str->len < length) { + gchar tmp = (gchar)g_random_int_range(0x0, 0xff); + if (g_ascii_isalnum(tmp)) + g_string_append_c(str, tmp); + } + return g_string_free(str, FALSE); +} + +static gboolean +fu_plugin_redfish_change_expired(FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data(plugin); + g_autofree gchar *password_new = fu_common_generate_password(15); + g_autofree gchar *uri = NULL; + g_autoptr(FuRedfishRequest) request = NULL; + g_autoptr(JsonBuilder) builder = json_builder_new(); + + /* select correct, falling back to default for old fwupd versions */ + uri = fu_plugin_get_config_value(plugin, "UserUri"); + if (uri == NULL) { + uri = g_strdup("/redfish/v1/AccountService/Accounts/2"); + if (!fu_plugin_set_secure_config_value(plugin, "UserUri", uri, error)) + return FALSE; + } + + /* now use Redfish to change the temporary password to the actual password */ + request = fu_redfish_backend_request_new(data->backend); + json_builder_begin_object(builder); + json_builder_set_member_name(builder, "Password"); + json_builder_add_string_value(builder, password_new); + json_builder_end_object(builder); + if (!fu_redfish_request_patch(request, + uri, + builder, + FU_REDFISH_REQUEST_PERFORM_FLAG_LOAD_JSON, + error)) + return FALSE; + fu_redfish_backend_set_password(data->backend, password_new); + + /* success */ + return fu_plugin_set_secure_config_value(plugin, "Password", password_new, error); +} + static gboolean fu_plugin_redfish_coldplug(FuPlugin *plugin, GError **error) { @@ -30,10 +79,18 @@ fu_plugin_redfish_coldplug(FuPlugin *plugin, GError **error) /* get the list of devices */ if (!fu_backend_coldplug(FU_BACKEND(data->backend), &error_local)) { - if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_AUTH_FAILED)) - fu_plugin_add_flag(plugin, FWUPD_PLUGIN_FLAG_AUTH_REQUIRED); - g_propagate_error(error, g_steal_pointer(&error_local)); - return FALSE; + /* did the user password expire? */ + if (g_error_matches(error_local, FWUPD_ERROR, FWUPD_ERROR_AUTH_EXPIRED)) { + if (!fu_plugin_redfish_change_expired(plugin, error)) + return FALSE; + if (!fu_backend_coldplug(FU_BACKEND(data->backend), error)) { + fu_plugin_add_flag(plugin, FWUPD_PLUGIN_FLAG_AUTH_REQUIRED); + return FALSE; + } + } else { + g_propagate_error(error, g_steal_pointer(&error_local)); + return FALSE; + } } devices = fu_backend_get_devices(FU_BACKEND(data->backend)); for (guint i = 0; i < devices->len; i++) { @@ -186,19 +243,6 @@ fu_redfish_plugin_discover_smbios_table(FuPlugin *plugin, GError **error) } #ifdef HAVE_LINUX_IPMI_H -static gchar * -fu_common_generate_password(guint length) -{ - GString *str = g_string_sized_new(length); - - /* get a random password string */ - while (str->len < length) { - gchar tmp = (gchar)g_random_int_range(0x0, 0xff); - if (g_ascii_isalnum(tmp)) - g_string_append_c(str, tmp); - } - return g_string_free(str, FALSE); -} static gboolean fu_redfish_plugin_ipmi_create_user(FuPlugin *plugin, GError **error) @@ -272,6 +316,8 @@ fu_redfish_plugin_ipmi_create_user(FuPlugin *plugin, GError **error) fu_redfish_backend_set_password(data->backend, password_new); /* success */ + if (!fu_plugin_set_secure_config_value(plugin, "UserUri", uri, error)) + return FALSE; if (!fu_plugin_set_secure_config_value(plugin, "Username", username_fwupd, error)) return FALSE; if (!fu_plugin_set_secure_config_value(plugin, "Password", password_new, error)) diff --git a/plugins/redfish/fu-redfish-request.c b/plugins/redfish/fu-redfish-request.c index 4fc2f8abf..32d511b70 100644 --- a/plugins/redfish/fu-redfish-request.c +++ b/plugins/redfish/fu-redfish-request.c @@ -138,6 +138,8 @@ fu_redfish_request_load_json(FuRedfishRequest *self, GByteArray *buf, GError **e } if (g_strcmp0(id, "Base.1.8.AccessDenied") == 0) error_code = FWUPD_ERROR_AUTH_FAILED; + else if (g_strcmp0(id, "Base.1.8.PasswordChangeRequired") == 0) + error_code = FWUPD_ERROR_AUTH_EXPIRED; g_set_error_literal(error, FWUPD_ERROR, error_code, msg); return FALSE; } @@ -244,7 +246,7 @@ fu_redfish_request_patch(FuRedfishRequest *self, json_generator_set_root(json_generator, json_root); json_generator_to_gstring(json_generator, str); if (g_getenv("FWUPD_REDFISH_VERBOSE") != NULL) - g_debug("request: %s", str->str); + g_debug("request to %s: %s", path, str->str); /* patch */ curl_easy_setopt(self->curl, CURLOPT_CUSTOMREQUEST, "PATCH"); diff --git a/plugins/redfish/meson.build b/plugins/redfish/meson.build index e4e4c023e..4a0a8664c 100644 --- a/plugins/redfish/meson.build +++ b/plugins/redfish/meson.build @@ -59,6 +59,8 @@ install_data(['redfish.conf'], if get_option('tests') install_data(['tests/redfish-smbios.bin'], install_dir: join_paths(installed_test_datadir, 'tests')) + install_data(['tests/redfish.conf'], + install_dir: join_paths(installed_test_datadir, 'tests')) install_data(['tests/efi/efivars/RedfishIndications-16faa37e-4b6a-4891-9028-242de65a3b70'], install_dir: join_paths(installed_test_datadir, 'tests', 'efi', 'efivars')) install_data(['tests/efi/efivars/RedfishOSCredentials-16faa37e-4b6a-4891-9028-242de65a3b70'],