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