xref: /linux/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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