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->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  
38  static struct kobj_attribute po_is_pass_set = __ATTR_RO(is_enabled);
39  
current_password_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)40  static 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  
69  static struct kobj_attribute po_current_password = __ATTR_WO(current_password);
70  
new_password_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)71  static 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  
92  out:
93  	kfree(buf_cp);
94  	return ret ? ret : count;
95  }
96  
97  static struct kobj_attribute po_new_password = __ATTR_WO(new_password);
98  
99  attribute_n_property_show(min_password_length, po);
100  static struct kobj_attribute po_min_pass_length = __ATTR_RO(min_password_length);
101  
102  attribute_n_property_show(max_password_length, po);
103  static struct kobj_attribute po_max_pass_length = __ATTR_RO(max_password_length);
104  
mechanism_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)105  static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
106  			 char *buf)
107  {
108  	return sprintf(buf, "password\n");
109  }
110  
111  static struct kobj_attribute po_mechanism = __ATTR_RO(mechanism);
112  
role_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)113  static 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  
123  static struct kobj_attribute po_role = __ATTR_RO(role);
124  
125  static 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  
136  static const struct attribute_group po_attr_group = {
137  	.attrs = po_attrs,
138  };
139  
alloc_po_data(void)140  int 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   */
populate_po_data(union acpi_object * po_obj,int instance_id,struct kobject * attr_name_kobj)159  int 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   */
exit_po_attributes(void)183  void 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