153 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Functions corresponding to SET password methods under BIOS attributes interface GUID4 *5 * Copyright (c) 2020 Dell Inc.6 */7 8#include <linux/wmi.h>9#include "dell-wmi-sysman.h"10 11static int call_password_interface(struct wmi_device *wdev, char *in_args, size_t size)12{13 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};14 struct acpi_buffer input;15 union acpi_object *obj;16 acpi_status status;17 int ret = -EIO;18 19 input.length = (acpi_size) size;20 input.pointer = in_args;21 status = wmidev_evaluate_method(wdev, 0, 1, &input, &output);22 if (ACPI_FAILURE(status))23 return -EIO;24 obj = (union acpi_object *)output.pointer;25 if (obj->type == ACPI_TYPE_INTEGER)26 ret = obj->integer.value;27 28 kfree(output.pointer);29 /* let userland know it may need to check is_password_set again */30 kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE);31 return map_wmi_error(ret);32}33 34/**35 * set_new_password() - Sets a system admin password36 * @password_type: The type of password to set37 * @new: The new password38 *39 * Sets the password using plaintext interface40 */41int set_new_password(const char *password_type, const char *new)42{43 size_t password_type_size, current_password_size, new_size;44 size_t security_area_size, buffer_size;45 char *buffer = NULL, *start;46 char *current_password;47 int ret;48 49 mutex_lock(&wmi_priv.mutex);50 if (!wmi_priv.password_attr_wdev) {51 ret = -ENODEV;52 goto out;53 }54 if (strcmp(password_type, "Admin") == 0) {55 current_password = wmi_priv.current_admin_password;56 } else if (strcmp(password_type, "System") == 0) {57 current_password = wmi_priv.current_system_password;58 } else {59 ret = -EINVAL;60 dev_err(&wmi_priv.password_attr_wdev->dev, "unknown password type %s\n",61 password_type);62 goto out;63 }64 65 /* build/calculate buffer */66 security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);67 password_type_size = calculate_string_buffer(password_type);68 current_password_size = calculate_string_buffer(current_password);69 new_size = calculate_string_buffer(new);70 buffer_size = security_area_size + password_type_size + current_password_size + new_size;71 buffer = kzalloc(buffer_size, GFP_KERNEL);72 if (!buffer) {73 ret = -ENOMEM;74 goto out;75 }76 77 /* build security area */78 populate_security_buffer(buffer, wmi_priv.current_admin_password);79 80 /* build variables to set */81 start = buffer + security_area_size;82 ret = populate_string_buffer(start, password_type_size, password_type);83 if (ret < 0)84 goto out;85 86 start += ret;87 ret = populate_string_buffer(start, current_password_size, current_password);88 if (ret < 0)89 goto out;90 91 start += ret;92 ret = populate_string_buffer(start, new_size, new);93 if (ret < 0)94 goto out;95 96 print_hex_dump_bytes("set new password data: ", DUMP_PREFIX_NONE, buffer, buffer_size);97 ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, buffer_size);98 /* on success copy the new password to current password */99 if (!ret)100 strscpy(current_password, new, MAX_BUFF);101 /* explain to user the detailed failure reason */102 else if (ret == -EOPNOTSUPP)103 dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");104 else if (ret == -EACCES)105 dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");106 107out:108 kfree(buffer);109 mutex_unlock(&wmi_priv.mutex);110 111 return ret;112}113 114static int bios_attr_pass_interface_probe(struct wmi_device *wdev, const void *context)115{116 mutex_lock(&wmi_priv.mutex);117 wmi_priv.password_attr_wdev = wdev;118 mutex_unlock(&wmi_priv.mutex);119 return 0;120}121 122static void bios_attr_pass_interface_remove(struct wmi_device *wdev)123{124 mutex_lock(&wmi_priv.mutex);125 wmi_priv.password_attr_wdev = NULL;126 mutex_unlock(&wmi_priv.mutex);127}128 129static const struct wmi_device_id bios_attr_pass_interface_id_table[] = {130 { .guid_string = DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID },131 { },132};133static struct wmi_driver bios_attr_pass_interface_driver = {134 .driver = {135 .name = DRIVER_NAME"-password"136 },137 .probe = bios_attr_pass_interface_probe,138 .remove = bios_attr_pass_interface_remove,139 .id_table = bios_attr_pass_interface_id_table,140};141 142int init_bios_attr_pass_interface(void)143{144 return wmi_driver_register(&bios_attr_pass_interface_driver);145}146 147void exit_bios_attr_pass_interface(void)148{149 wmi_driver_unregister(&bios_attr_pass_interface_driver);150}151 152MODULE_DEVICE_TABLE(wmi, bios_attr_pass_interface_id_table);153