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