1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Functions corresponding to SET password methods under BIOS attributes interface GUID 4 * 5 * Copyright (c) 2020 Dell Inc. 6 */ 7 8 #include <linux/wmi.h> 9 #include "dell-wmi-sysman.h" 10 11 static 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 password 36 * @password_type: The type of password to set 37 * @new: The new password 38 * 39 * Sets the password using plaintext interface 40 */ 41 int 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 107 out: 108 kfree(buffer); 109 mutex_unlock(&wmi_priv.mutex); 110 111 return ret; 112 } 113 114 static 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 122 static 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 129 static const struct wmi_device_id bios_attr_pass_interface_id_table[] = { 130 { .guid_string = DELL_WMI_BIOS_PASSWORD_INTERFACE_GUID }, 131 { }, 132 }; 133 static 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 142 int init_bios_attr_pass_interface(void) 143 { 144 return wmi_driver_register(&bios_attr_pass_interface_driver); 145 } 146 147 void exit_bios_attr_pass_interface(void) 148 { 149 wmi_driver_unregister(&bios_attr_pass_interface_driver); 150 } 151 152 MODULE_DEVICE_TABLE(wmi, bios_attr_pass_interface_id_table); 153