1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Functions corresponding to password object type attributes under BIOS Password Object GUID for
4 * use with dell-wmi-sysman
5 *
6 *  Copyright (c) 2020 Dell Inc.
7 */
8
9#include "dell-wmi-sysman.h"
10
11enum po_properties {IS_PASS_SET = 1, MIN_PASS_LEN, MAX_PASS_LEN};
12
13get_instance_id(po);
14
15static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr,
16					  char *buf)
17{
18	int instance_id = get_po_instance_id(kobj);
19	union acpi_object *obj;
20	ssize_t ret;
21
22	if (instance_id < 0)
23		return instance_id;
24
25	/* need to use specific instance_id and guid combination to get right data */
26	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
27	if (!obj)
28		return -EIO;
29	if (obj->package.elements[IS_PASS_SET].type != ACPI_TYPE_INTEGER) {
30		kfree(obj);
31		return -EINVAL;
32	}
33	ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[IS_PASS_SET].integer.value);
34	kfree(obj);
35	return ret;
36}
37
38static struct kobj_attribute po_is_pass_set = __ATTR_RO(is_enabled);
39
40static ssize_t current_password_store(struct kobject *kobj,
41				      struct kobj_attribute *attr,
42				      const char *buf, size_t count)
43{
44	char *target = NULL;
45	int length;
46
47	length = strlen(buf);
48	if (buf[length-1] == '\n')
49		length--;
50
51	/* firmware does verifiation of min/max password length,
52	 * hence only check for not exceeding MAX_BUFF here.
53	 */
54	if (length >= MAX_BUFF)
55		return -EINVAL;
56
57	if (strcmp(kobj->name, "Admin") == 0)
58		target = wmi_priv.current_admin_password;
59	else if (strcmp(kobj->name, "System") == 0)
60		target = wmi_priv.current_system_password;
61	if (!target)
62		return -EIO;
63	memcpy(target, buf, length);
64	target[length] = '\0';
65
66	return count;
67}
68
69static struct kobj_attribute po_current_password = __ATTR_WO(current_password);
70
71static ssize_t new_password_store(struct kobject *kobj,
72				  struct kobj_attribute *attr,
73				  const char *buf, size_t count)
74{
75	char *p, *buf_cp;
76	int ret;
77
78	buf_cp = kstrdup(buf, GFP_KERNEL);
79	if (!buf_cp)
80		return -ENOMEM;
81	p = memchr(buf_cp, '\n', count);
82
83	if (p != NULL)
84		*p = '\0';
85	if (strlen(buf_cp) > MAX_BUFF) {
86		ret = -EINVAL;
87		goto out;
88	}
89
90	ret = set_new_password(kobj->name, buf_cp);
91
92out:
93	kfree(buf_cp);
94	return ret ? ret : count;
95}
96
97static struct kobj_attribute po_new_password = __ATTR_WO(new_password);
98
99attribute_n_property_show(min_password_length, po);
100static struct kobj_attribute po_min_pass_length = __ATTR_RO(min_password_length);
101
102attribute_n_property_show(max_password_length, po);
103static struct kobj_attribute po_max_pass_length = __ATTR_RO(max_password_length);
104
105static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
106			 char *buf)
107{
108	return sprintf(buf, "password\n");
109}
110
111static struct kobj_attribute po_mechanism = __ATTR_RO(mechanism);
112
113static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr,
114			 char *buf)
115{
116	if (strcmp(kobj->name, "Admin") == 0)
117		return sprintf(buf, "bios-admin\n");
118	else if (strcmp(kobj->name, "System") == 0)
119		return sprintf(buf, "power-on\n");
120	return -EIO;
121}
122
123static struct kobj_attribute po_role = __ATTR_RO(role);
124
125static struct attribute *po_attrs[] = {
126	&po_is_pass_set.attr,
127	&po_min_pass_length.attr,
128	&po_max_pass_length.attr,
129	&po_current_password.attr,
130	&po_new_password.attr,
131	&po_role.attr,
132	&po_mechanism.attr,
133	NULL,
134};
135
136static const struct attribute_group po_attr_group = {
137	.attrs = po_attrs,
138};
139
140int alloc_po_data(void)
141{
142	int ret = 0;
143
144	wmi_priv.po_instances_count = get_instance_count(DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
145	wmi_priv.po_data = kcalloc(wmi_priv.po_instances_count, sizeof(struct po_data), GFP_KERNEL);
146	if (!wmi_priv.po_data) {
147		wmi_priv.po_instances_count = 0;
148		ret = -ENOMEM;
149	}
150	return ret;
151}
152
153/**
154 * populate_po_data() - Populate all properties of an instance under password object attribute
155 * @po_obj: ACPI object with password object data
156 * @instance_id: The instance to enumerate
157 * @attr_name_kobj: The parent kernel object
158 */
159int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj)
160{
161	wmi_priv.po_data[instance_id].attr_name_kobj = attr_name_kobj;
162	if (check_property_type(po, ATTR_NAME, ACPI_TYPE_STRING))
163		return -EINVAL;
164	strlcpy_attr(wmi_priv.po_data[instance_id].attribute_name,
165		     po_obj[ATTR_NAME].string.pointer);
166	if (check_property_type(po, MIN_PASS_LEN, ACPI_TYPE_INTEGER))
167		return -EINVAL;
168	wmi_priv.po_data[instance_id].min_password_length =
169		(uintptr_t)po_obj[MIN_PASS_LEN].string.pointer;
170	if (check_property_type(po, MAX_PASS_LEN, ACPI_TYPE_INTEGER))
171		return -EINVAL;
172	wmi_priv.po_data[instance_id].max_password_length =
173		(uintptr_t) po_obj[MAX_PASS_LEN].string.pointer;
174
175	return sysfs_create_group(attr_name_kobj, &po_attr_group);
176}
177
178/**
179 * exit_po_attributes() - Clear all attribute data
180 *
181 * Clears all data allocated for this group of attributes
182 */
183void exit_po_attributes(void)
184{
185	int instance_id;
186
187	for (instance_id = 0; instance_id < wmi_priv.po_instances_count; instance_id++) {
188		if (wmi_priv.po_data[instance_id].attr_name_kobj)
189			sysfs_remove_group(wmi_priv.po_data[instance_id].attr_name_kobj,
190								&po_attr_group);
191	}
192	wmi_priv.po_instances_count = 0;
193
194	kfree(wmi_priv.po_data);
195	wmi_priv.po_data = NULL;
196}
197