redfish: Change an expired password when required

This commit is contained in:
Richard Hughes 2021-12-20 19:28:09 +00:00
parent 0264c29bda
commit 3917714dd1
5 changed files with 74 additions and 18 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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))

View File

@ -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");

View File

@ -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'],