162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Functions corresponding to password object type attributes under BIOS Password Object GUID for 462306a36Sopenharmony_ci * use with dell-wmi-sysman 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (c) 2020 Dell Inc. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "dell-wmi-sysman.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cienum po_properties {IS_PASS_SET = 1, MIN_PASS_LEN, MAX_PASS_LEN}; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ciget_instance_id(po); 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr, 1662306a36Sopenharmony_ci char *buf) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci int instance_id = get_po_instance_id(kobj); 1962306a36Sopenharmony_ci union acpi_object *obj; 2062306a36Sopenharmony_ci ssize_t ret; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci if (instance_id < 0) 2362306a36Sopenharmony_ci return instance_id; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci /* need to use specific instance_id and guid combination to get right data */ 2662306a36Sopenharmony_ci obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID); 2762306a36Sopenharmony_ci if (!obj) 2862306a36Sopenharmony_ci return -EIO; 2962306a36Sopenharmony_ci if (obj->package.elements[IS_PASS_SET].type != ACPI_TYPE_INTEGER) { 3062306a36Sopenharmony_ci kfree(obj); 3162306a36Sopenharmony_ci return -EINVAL; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[IS_PASS_SET].integer.value); 3462306a36Sopenharmony_ci kfree(obj); 3562306a36Sopenharmony_ci return ret; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic struct kobj_attribute po_is_pass_set = __ATTR_RO(is_enabled); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic ssize_t current_password_store(struct kobject *kobj, 4162306a36Sopenharmony_ci struct kobj_attribute *attr, 4262306a36Sopenharmony_ci const char *buf, size_t count) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci char *target = NULL; 4562306a36Sopenharmony_ci int length; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci length = strlen(buf); 4862306a36Sopenharmony_ci if (buf[length-1] == '\n') 4962306a36Sopenharmony_ci length--; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* firmware does verifiation of min/max password length, 5262306a36Sopenharmony_ci * hence only check for not exceeding MAX_BUFF here. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci if (length >= MAX_BUFF) 5562306a36Sopenharmony_ci return -EINVAL; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (strcmp(kobj->name, "Admin") == 0) 5862306a36Sopenharmony_ci target = wmi_priv.current_admin_password; 5962306a36Sopenharmony_ci else if (strcmp(kobj->name, "System") == 0) 6062306a36Sopenharmony_ci target = wmi_priv.current_system_password; 6162306a36Sopenharmony_ci if (!target) 6262306a36Sopenharmony_ci return -EIO; 6362306a36Sopenharmony_ci memcpy(target, buf, length); 6462306a36Sopenharmony_ci target[length] = '\0'; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci return count; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic struct kobj_attribute po_current_password = __ATTR_WO(current_password); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic ssize_t new_password_store(struct kobject *kobj, 7262306a36Sopenharmony_ci struct kobj_attribute *attr, 7362306a36Sopenharmony_ci const char *buf, size_t count) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci char *p, *buf_cp; 7662306a36Sopenharmony_ci int ret; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci buf_cp = kstrdup(buf, GFP_KERNEL); 7962306a36Sopenharmony_ci if (!buf_cp) 8062306a36Sopenharmony_ci return -ENOMEM; 8162306a36Sopenharmony_ci p = memchr(buf_cp, '\n', count); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (p != NULL) 8462306a36Sopenharmony_ci *p = '\0'; 8562306a36Sopenharmony_ci if (strlen(buf_cp) > MAX_BUFF) { 8662306a36Sopenharmony_ci ret = -EINVAL; 8762306a36Sopenharmony_ci goto out; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci ret = set_new_password(kobj->name, buf_cp); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ciout: 9362306a36Sopenharmony_ci kfree(buf_cp); 9462306a36Sopenharmony_ci return ret ? ret : count; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic struct kobj_attribute po_new_password = __ATTR_WO(new_password); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciattribute_n_property_show(min_password_length, po); 10062306a36Sopenharmony_cistatic struct kobj_attribute po_min_pass_length = __ATTR_RO(min_password_length); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ciattribute_n_property_show(max_password_length, po); 10362306a36Sopenharmony_cistatic struct kobj_attribute po_max_pass_length = __ATTR_RO(max_password_length); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr, 10662306a36Sopenharmony_ci char *buf) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci return sprintf(buf, "password\n"); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct kobj_attribute po_mechanism = __ATTR_RO(mechanism); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr, 11462306a36Sopenharmony_ci char *buf) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci if (strcmp(kobj->name, "Admin") == 0) 11762306a36Sopenharmony_ci return sprintf(buf, "bios-admin\n"); 11862306a36Sopenharmony_ci else if (strcmp(kobj->name, "System") == 0) 11962306a36Sopenharmony_ci return sprintf(buf, "power-on\n"); 12062306a36Sopenharmony_ci return -EIO; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic struct kobj_attribute po_role = __ATTR_RO(role); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic struct attribute *po_attrs[] = { 12662306a36Sopenharmony_ci &po_is_pass_set.attr, 12762306a36Sopenharmony_ci &po_min_pass_length.attr, 12862306a36Sopenharmony_ci &po_max_pass_length.attr, 12962306a36Sopenharmony_ci &po_current_password.attr, 13062306a36Sopenharmony_ci &po_new_password.attr, 13162306a36Sopenharmony_ci &po_role.attr, 13262306a36Sopenharmony_ci &po_mechanism.attr, 13362306a36Sopenharmony_ci NULL, 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic const struct attribute_group po_attr_group = { 13762306a36Sopenharmony_ci .attrs = po_attrs, 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciint alloc_po_data(void) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci int ret = 0; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci wmi_priv.po_instances_count = get_instance_count(DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID); 14562306a36Sopenharmony_ci wmi_priv.po_data = kcalloc(wmi_priv.po_instances_count, sizeof(struct po_data), GFP_KERNEL); 14662306a36Sopenharmony_ci if (!wmi_priv.po_data) { 14762306a36Sopenharmony_ci wmi_priv.po_instances_count = 0; 14862306a36Sopenharmony_ci ret = -ENOMEM; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci return ret; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/** 15462306a36Sopenharmony_ci * populate_po_data() - Populate all properties of an instance under password object attribute 15562306a36Sopenharmony_ci * @po_obj: ACPI object with password object data 15662306a36Sopenharmony_ci * @instance_id: The instance to enumerate 15762306a36Sopenharmony_ci * @attr_name_kobj: The parent kernel object 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ciint populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject *attr_name_kobj) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci wmi_priv.po_data[instance_id].attr_name_kobj = attr_name_kobj; 16262306a36Sopenharmony_ci if (check_property_type(po, ATTR_NAME, ACPI_TYPE_STRING)) 16362306a36Sopenharmony_ci return -EINVAL; 16462306a36Sopenharmony_ci strlcpy_attr(wmi_priv.po_data[instance_id].attribute_name, 16562306a36Sopenharmony_ci po_obj[ATTR_NAME].string.pointer); 16662306a36Sopenharmony_ci if (check_property_type(po, MIN_PASS_LEN, ACPI_TYPE_INTEGER)) 16762306a36Sopenharmony_ci return -EINVAL; 16862306a36Sopenharmony_ci wmi_priv.po_data[instance_id].min_password_length = 16962306a36Sopenharmony_ci (uintptr_t)po_obj[MIN_PASS_LEN].string.pointer; 17062306a36Sopenharmony_ci if (check_property_type(po, MAX_PASS_LEN, ACPI_TYPE_INTEGER)) 17162306a36Sopenharmony_ci return -EINVAL; 17262306a36Sopenharmony_ci wmi_priv.po_data[instance_id].max_password_length = 17362306a36Sopenharmony_ci (uintptr_t) po_obj[MAX_PASS_LEN].string.pointer; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return sysfs_create_group(attr_name_kobj, &po_attr_group); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/** 17962306a36Sopenharmony_ci * exit_po_attributes() - Clear all attribute data 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * Clears all data allocated for this group of attributes 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_civoid exit_po_attributes(void) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci int instance_id; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci for (instance_id = 0; instance_id < wmi_priv.po_instances_count; instance_id++) { 18862306a36Sopenharmony_ci if (wmi_priv.po_data[instance_id].attr_name_kobj) 18962306a36Sopenharmony_ci sysfs_remove_group(wmi_priv.po_data[instance_id].attr_name_kobj, 19062306a36Sopenharmony_ci &po_attr_group); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci wmi_priv.po_instances_count = 0; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci kfree(wmi_priv.po_data); 19562306a36Sopenharmony_ci wmi_priv.po_data = NULL; 19662306a36Sopenharmony_ci} 197