18646a3b5SJorge Lopez // SPDX-License-Identifier: GPL-2.0
28646a3b5SJorge Lopez /*
38646a3b5SJorge Lopez * Functions corresponding to password object type attributes under
48646a3b5SJorge Lopez * BIOS PASSWORD for use with hp-bioscfg driver.
58646a3b5SJorge Lopez *
68646a3b5SJorge Lopez * Copyright (c) 2022 HP Development Company, L.P.
78646a3b5SJorge Lopez */
88646a3b5SJorge Lopez
98646a3b5SJorge Lopez #include "bioscfg.h"
108646a3b5SJorge Lopez #include <asm-generic/posix_types.h>
118646a3b5SJorge Lopez
128646a3b5SJorge Lopez GET_INSTANCE_ID(password);
138646a3b5SJorge Lopez /*
148646a3b5SJorge Lopez * Clear all passwords copied to memory for a particular
158646a3b5SJorge Lopez * authentication instance
168646a3b5SJorge Lopez */
clear_passwords(const int instance)178646a3b5SJorge Lopez static int clear_passwords(const int instance)
188646a3b5SJorge Lopez {
198646a3b5SJorge Lopez struct password_data *password_data = &bioscfg_drv.password_data[instance];
208646a3b5SJorge Lopez
218646a3b5SJorge Lopez if (!password_data->is_enabled)
228646a3b5SJorge Lopez return 0;
238646a3b5SJorge Lopez
248646a3b5SJorge Lopez memset(password_data->current_password,
258646a3b5SJorge Lopez 0, sizeof(password_data->current_password));
268646a3b5SJorge Lopez memset(password_data->new_password,
278646a3b5SJorge Lopez 0, sizeof(password_data->new_password));
288646a3b5SJorge Lopez
298646a3b5SJorge Lopez return 0;
308646a3b5SJorge Lopez }
318646a3b5SJorge Lopez
328646a3b5SJorge Lopez /*
338646a3b5SJorge Lopez * Clear all credentials copied to memory for both Power-ON and Setup
348646a3b5SJorge Lopez * BIOS instances
358646a3b5SJorge Lopez */
hp_clear_all_credentials(void)368646a3b5SJorge Lopez int hp_clear_all_credentials(void)
378646a3b5SJorge Lopez {
388646a3b5SJorge Lopez int count = bioscfg_drv.password_instances_count;
398646a3b5SJorge Lopez int instance;
408646a3b5SJorge Lopez
418646a3b5SJorge Lopez /* clear all passwords */
428646a3b5SJorge Lopez for (instance = 0; instance < count; instance++)
438646a3b5SJorge Lopez clear_passwords(instance);
448646a3b5SJorge Lopez
458646a3b5SJorge Lopez /* clear auth_token */
468646a3b5SJorge Lopez kfree(bioscfg_drv.spm_data.auth_token);
478646a3b5SJorge Lopez bioscfg_drv.spm_data.auth_token = NULL;
488646a3b5SJorge Lopez
498646a3b5SJorge Lopez return 0;
508646a3b5SJorge Lopez }
518646a3b5SJorge Lopez
hp_get_password_instance_for_type(const char * name)528646a3b5SJorge Lopez int hp_get_password_instance_for_type(const char *name)
538646a3b5SJorge Lopez {
548646a3b5SJorge Lopez int count = bioscfg_drv.password_instances_count;
558646a3b5SJorge Lopez int instance;
568646a3b5SJorge Lopez
578646a3b5SJorge Lopez for (instance = 0; instance < count; instance++)
588646a3b5SJorge Lopez if (!strcmp(bioscfg_drv.password_data[instance].common.display_name, name))
598646a3b5SJorge Lopez return instance;
608646a3b5SJorge Lopez
618646a3b5SJorge Lopez return -EINVAL;
628646a3b5SJorge Lopez }
638646a3b5SJorge Lopez
validate_password_input(int instance_id,const char * buf)648646a3b5SJorge Lopez static int validate_password_input(int instance_id, const char *buf)
658646a3b5SJorge Lopez {
668646a3b5SJorge Lopez int length;
678646a3b5SJorge Lopez struct password_data *password_data = &bioscfg_drv.password_data[instance_id];
688646a3b5SJorge Lopez
698646a3b5SJorge Lopez length = strlen(buf);
708646a3b5SJorge Lopez if (buf[length - 1] == '\n')
718646a3b5SJorge Lopez length--;
728646a3b5SJorge Lopez
738646a3b5SJorge Lopez if (length > MAX_PASSWD_SIZE)
748646a3b5SJorge Lopez return INVALID_BIOS_AUTH;
758646a3b5SJorge Lopez
768646a3b5SJorge Lopez if (password_data->min_password_length > length ||
778646a3b5SJorge Lopez password_data->max_password_length < length)
788646a3b5SJorge Lopez return INVALID_BIOS_AUTH;
798646a3b5SJorge Lopez return SUCCESS;
808646a3b5SJorge Lopez }
818646a3b5SJorge Lopez
828646a3b5SJorge Lopez ATTRIBUTE_N_PROPERTY_SHOW(is_enabled, password);
838646a3b5SJorge Lopez static struct kobj_attribute password_is_password_set = __ATTR_RO(is_enabled);
848646a3b5SJorge Lopez
store_password_instance(struct kobject * kobj,const char * buf,size_t count,bool is_current)858646a3b5SJorge Lopez static int store_password_instance(struct kobject *kobj, const char *buf,
868646a3b5SJorge Lopez size_t count, bool is_current)
878646a3b5SJorge Lopez {
888646a3b5SJorge Lopez char *buf_cp;
898646a3b5SJorge Lopez int id, ret = 0;
908646a3b5SJorge Lopez
918646a3b5SJorge Lopez buf_cp = kstrdup(buf, GFP_KERNEL);
928646a3b5SJorge Lopez if (!buf_cp)
938646a3b5SJorge Lopez return -ENOMEM;
948646a3b5SJorge Lopez
958646a3b5SJorge Lopez ret = hp_enforce_single_line_input(buf_cp, count);
968646a3b5SJorge Lopez if (!ret) {
978646a3b5SJorge Lopez id = get_password_instance_id(kobj);
988646a3b5SJorge Lopez
998646a3b5SJorge Lopez if (id >= 0)
1008646a3b5SJorge Lopez ret = validate_password_input(id, buf_cp);
1018646a3b5SJorge Lopez }
1028646a3b5SJorge Lopez
1038646a3b5SJorge Lopez if (!ret) {
1048646a3b5SJorge Lopez if (is_current)
1058646a3b5SJorge Lopez strscpy(bioscfg_drv.password_data[id].current_password,
1068646a3b5SJorge Lopez buf_cp,
1078646a3b5SJorge Lopez sizeof(bioscfg_drv.password_data[id].current_password));
1088646a3b5SJorge Lopez else
1098646a3b5SJorge Lopez strscpy(bioscfg_drv.password_data[id].new_password,
1108646a3b5SJorge Lopez buf_cp,
1118646a3b5SJorge Lopez sizeof(bioscfg_drv.password_data[id].new_password));
1128646a3b5SJorge Lopez }
1138646a3b5SJorge Lopez
1148646a3b5SJorge Lopez kfree(buf_cp);
1158646a3b5SJorge Lopez return ret < 0 ? ret : count;
1168646a3b5SJorge Lopez }
1178646a3b5SJorge Lopez
current_password_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)1188646a3b5SJorge Lopez static ssize_t current_password_store(struct kobject *kobj,
1198646a3b5SJorge Lopez struct kobj_attribute *attr,
1208646a3b5SJorge Lopez const char *buf, size_t count)
1218646a3b5SJorge Lopez {
1228646a3b5SJorge Lopez return store_password_instance(kobj, buf, count, true);
1238646a3b5SJorge Lopez }
1248646a3b5SJorge Lopez
1258646a3b5SJorge Lopez static struct kobj_attribute password_current_password = __ATTR_WO(current_password);
1268646a3b5SJorge Lopez
new_password_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)1278646a3b5SJorge Lopez static ssize_t new_password_store(struct kobject *kobj,
1288646a3b5SJorge Lopez struct kobj_attribute *attr,
1298646a3b5SJorge Lopez const char *buf, size_t count)
1308646a3b5SJorge Lopez {
1318646a3b5SJorge Lopez return store_password_instance(kobj, buf, count, true);
1328646a3b5SJorge Lopez }
1338646a3b5SJorge Lopez
1348646a3b5SJorge Lopez static struct kobj_attribute password_new_password = __ATTR_WO(new_password);
1358646a3b5SJorge Lopez
1368646a3b5SJorge Lopez ATTRIBUTE_N_PROPERTY_SHOW(min_password_length, password);
1378646a3b5SJorge Lopez static struct kobj_attribute password_min_password_length = __ATTR_RO(min_password_length);
1388646a3b5SJorge Lopez
1398646a3b5SJorge Lopez ATTRIBUTE_N_PROPERTY_SHOW(max_password_length, password);
1408646a3b5SJorge Lopez static struct kobj_attribute password_max_password_length = __ATTR_RO(max_password_length);
1418646a3b5SJorge Lopez
role_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1428646a3b5SJorge Lopez static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1438646a3b5SJorge Lopez {
1448646a3b5SJorge Lopez if (!strcmp(kobj->name, SETUP_PASSWD))
1458646a3b5SJorge Lopez return sysfs_emit(buf, "%s\n", BIOS_ADMIN);
1468646a3b5SJorge Lopez
1478646a3b5SJorge Lopez if (!strcmp(kobj->name, POWER_ON_PASSWD))
1488646a3b5SJorge Lopez return sysfs_emit(buf, "%s\n", POWER_ON);
1498646a3b5SJorge Lopez
1508646a3b5SJorge Lopez return -EIO;
1518646a3b5SJorge Lopez }
1528646a3b5SJorge Lopez
1538646a3b5SJorge Lopez static struct kobj_attribute password_role = __ATTR_RO(role);
1548646a3b5SJorge Lopez
mechanism_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)1558646a3b5SJorge Lopez static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
1568646a3b5SJorge Lopez char *buf)
1578646a3b5SJorge Lopez {
1588646a3b5SJorge Lopez int i = get_password_instance_id(kobj);
1598646a3b5SJorge Lopez
1608646a3b5SJorge Lopez if (i < 0)
1618646a3b5SJorge Lopez return i;
1628646a3b5SJorge Lopez
1638646a3b5SJorge Lopez if (bioscfg_drv.password_data[i].mechanism != PASSWORD)
1648646a3b5SJorge Lopez return -EINVAL;
1658646a3b5SJorge Lopez
1668646a3b5SJorge Lopez return sysfs_emit(buf, "%s\n", PASSWD_MECHANISM_TYPES);
1678646a3b5SJorge Lopez }
1688646a3b5SJorge Lopez
1698646a3b5SJorge Lopez static struct kobj_attribute password_mechanism = __ATTR_RO(mechanism);
1708646a3b5SJorge Lopez
1718646a3b5SJorge Lopez ATTRIBUTE_VALUES_PROPERTY_SHOW(encodings, password, SEMICOLON_SEP);
1728646a3b5SJorge Lopez static struct kobj_attribute password_encodings_val = __ATTR_RO(encodings);
1738646a3b5SJorge Lopez
1748646a3b5SJorge Lopez static struct attribute *password_attrs[] = {
1758646a3b5SJorge Lopez &password_is_password_set.attr,
1768646a3b5SJorge Lopez &password_min_password_length.attr,
1778646a3b5SJorge Lopez &password_max_password_length.attr,
1788646a3b5SJorge Lopez &password_current_password.attr,
1798646a3b5SJorge Lopez &password_new_password.attr,
1808646a3b5SJorge Lopez &password_role.attr,
1818646a3b5SJorge Lopez &password_mechanism.attr,
1828646a3b5SJorge Lopez &password_encodings_val.attr,
1838646a3b5SJorge Lopez NULL
1848646a3b5SJorge Lopez };
1858646a3b5SJorge Lopez
1868646a3b5SJorge Lopez static const struct attribute_group password_attr_group = {
1878646a3b5SJorge Lopez .attrs = password_attrs
1888646a3b5SJorge Lopez };
1898646a3b5SJorge Lopez
hp_alloc_password_data(void)1908646a3b5SJorge Lopez int hp_alloc_password_data(void)
1918646a3b5SJorge Lopez {
1928646a3b5SJorge Lopez bioscfg_drv.password_instances_count = hp_get_instance_count(HP_WMI_BIOS_PASSWORD_GUID);
1938646a3b5SJorge Lopez bioscfg_drv.password_data = kcalloc(bioscfg_drv.password_instances_count,
1948646a3b5SJorge Lopez sizeof(*bioscfg_drv.password_data), GFP_KERNEL);
1958646a3b5SJorge Lopez if (!bioscfg_drv.password_data) {
1968646a3b5SJorge Lopez bioscfg_drv.password_instances_count = 0;
1978646a3b5SJorge Lopez return -ENOMEM;
1988646a3b5SJorge Lopez }
1998646a3b5SJorge Lopez
2008646a3b5SJorge Lopez return 0;
2018646a3b5SJorge Lopez }
2028646a3b5SJorge Lopez
2038646a3b5SJorge Lopez /* Expected Values types associated with each element */
2048646a3b5SJorge Lopez static const acpi_object_type expected_password_types[] = {
2058646a3b5SJorge Lopez [NAME] = ACPI_TYPE_STRING,
2068646a3b5SJorge Lopez [VALUE] = ACPI_TYPE_STRING,
2078646a3b5SJorge Lopez [PATH] = ACPI_TYPE_STRING,
2088646a3b5SJorge Lopez [IS_READONLY] = ACPI_TYPE_INTEGER,
2098646a3b5SJorge Lopez [DISPLAY_IN_UI] = ACPI_TYPE_INTEGER,
2108646a3b5SJorge Lopez [REQUIRES_PHYSICAL_PRESENCE] = ACPI_TYPE_INTEGER,
2118646a3b5SJorge Lopez [SEQUENCE] = ACPI_TYPE_INTEGER,
2128646a3b5SJorge Lopez [PREREQUISITES_SIZE] = ACPI_TYPE_INTEGER,
2138646a3b5SJorge Lopez [PREREQUISITES] = ACPI_TYPE_STRING,
2148646a3b5SJorge Lopez [SECURITY_LEVEL] = ACPI_TYPE_INTEGER,
2158646a3b5SJorge Lopez [PSWD_MIN_LENGTH] = ACPI_TYPE_INTEGER,
2168646a3b5SJorge Lopez [PSWD_MAX_LENGTH] = ACPI_TYPE_INTEGER,
2178646a3b5SJorge Lopez [PSWD_SIZE] = ACPI_TYPE_INTEGER,
2188646a3b5SJorge Lopez [PSWD_ENCODINGS] = ACPI_TYPE_STRING,
2198646a3b5SJorge Lopez [PSWD_IS_SET] = ACPI_TYPE_INTEGER,
2208646a3b5SJorge Lopez };
2218646a3b5SJorge Lopez
hp_populate_password_elements_from_package(union acpi_object * password_obj,int password_obj_count,int instance_id)2228646a3b5SJorge Lopez static int hp_populate_password_elements_from_package(union acpi_object *password_obj,
2238646a3b5SJorge Lopez int password_obj_count,
2248646a3b5SJorge Lopez int instance_id)
2258646a3b5SJorge Lopez {
2268646a3b5SJorge Lopez char *str_value = NULL;
2278646a3b5SJorge Lopez int value_len;
2288646a3b5SJorge Lopez int ret;
2298646a3b5SJorge Lopez u32 size;
23080d7ba30SJorge Lopez u32 int_value = 0;
2318646a3b5SJorge Lopez int elem;
2328646a3b5SJorge Lopez int reqs;
2338646a3b5SJorge Lopez int eloc;
2348646a3b5SJorge Lopez int pos_values;
2358646a3b5SJorge Lopez struct password_data *password_data = &bioscfg_drv.password_data[instance_id];
2368646a3b5SJorge Lopez
2378646a3b5SJorge Lopez if (!password_obj)
2388646a3b5SJorge Lopez return -EINVAL;
2398646a3b5SJorge Lopez
2408646a3b5SJorge Lopez for (elem = 1, eloc = 1; elem < password_obj_count; elem++, eloc++) {
2418646a3b5SJorge Lopez /* ONLY look at the first PASSWORD_ELEM_CNT elements */
2428646a3b5SJorge Lopez if (eloc == PSWD_ELEM_CNT)
2438646a3b5SJorge Lopez goto exit_package;
2448646a3b5SJorge Lopez
2458646a3b5SJorge Lopez switch (password_obj[elem].type) {
2468646a3b5SJorge Lopez case ACPI_TYPE_STRING:
2478646a3b5SJorge Lopez if (PREREQUISITES != elem && PSWD_ENCODINGS != elem) {
2488646a3b5SJorge Lopez ret = hp_convert_hexstr_to_str(password_obj[elem].string.pointer,
2498646a3b5SJorge Lopez password_obj[elem].string.length,
2508646a3b5SJorge Lopez &str_value, &value_len);
2518646a3b5SJorge Lopez if (ret)
2528646a3b5SJorge Lopez continue;
2538646a3b5SJorge Lopez }
2548646a3b5SJorge Lopez break;
2558646a3b5SJorge Lopez case ACPI_TYPE_INTEGER:
2568646a3b5SJorge Lopez int_value = (u32)password_obj[elem].integer.value;
2578646a3b5SJorge Lopez break;
2588646a3b5SJorge Lopez default:
2598646a3b5SJorge Lopez pr_warn("Unsupported object type [%d]\n", password_obj[elem].type);
2608646a3b5SJorge Lopez continue;
2618646a3b5SJorge Lopez }
2628646a3b5SJorge Lopez
2638646a3b5SJorge Lopez /* Check that both expected and read object type match */
2648646a3b5SJorge Lopez if (expected_password_types[eloc] != password_obj[elem].type) {
2658646a3b5SJorge Lopez pr_err("Error expected type %d for elem %d, but got type %d instead\n",
2668646a3b5SJorge Lopez expected_password_types[eloc], elem, password_obj[elem].type);
267467d4163SJorge Lopez kfree(str_value);
2688646a3b5SJorge Lopez return -EIO;
2698646a3b5SJorge Lopez }
2708646a3b5SJorge Lopez
2718646a3b5SJorge Lopez /* Assign appropriate element value to corresponding field*/
2728646a3b5SJorge Lopez switch (eloc) {
2738646a3b5SJorge Lopez case VALUE:
2748646a3b5SJorge Lopez break;
2758646a3b5SJorge Lopez case PATH:
2768646a3b5SJorge Lopez strscpy(password_data->common.path, str_value,
2778646a3b5SJorge Lopez sizeof(password_data->common.path));
2788646a3b5SJorge Lopez break;
2798646a3b5SJorge Lopez case IS_READONLY:
2808646a3b5SJorge Lopez password_data->common.is_readonly = int_value;
2818646a3b5SJorge Lopez break;
2828646a3b5SJorge Lopez case DISPLAY_IN_UI:
2838646a3b5SJorge Lopez password_data->common.display_in_ui = int_value;
2848646a3b5SJorge Lopez break;
2858646a3b5SJorge Lopez case REQUIRES_PHYSICAL_PRESENCE:
2868646a3b5SJorge Lopez password_data->common.requires_physical_presence = int_value;
2878646a3b5SJorge Lopez break;
2888646a3b5SJorge Lopez case SEQUENCE:
2898646a3b5SJorge Lopez password_data->common.sequence = int_value;
2908646a3b5SJorge Lopez break;
2918646a3b5SJorge Lopez case PREREQUISITES_SIZE:
29208f1f212SJorge Lopez if (int_value > MAX_PREREQUISITES_SIZE) {
2938646a3b5SJorge Lopez pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");
29408f1f212SJorge Lopez int_value = MAX_PREREQUISITES_SIZE;
29508f1f212SJorge Lopez }
29608f1f212SJorge Lopez password_data->common.prerequisites_size = int_value;
2978646a3b5SJorge Lopez
298a585400bSJorge Lopez /* This step is needed to keep the expected
2998646a3b5SJorge Lopez * element list pointing to the right obj[elem].type
3008646a3b5SJorge Lopez * when the size is zero. PREREQUISITES
3018646a3b5SJorge Lopez * object is omitted by BIOS when the size is
3028646a3b5SJorge Lopez * zero.
3038646a3b5SJorge Lopez */
3048646a3b5SJorge Lopez if (int_value == 0)
3058646a3b5SJorge Lopez eloc++;
3068646a3b5SJorge Lopez break;
3078646a3b5SJorge Lopez case PREREQUISITES:
3088646a3b5SJorge Lopez size = min_t(u32, password_data->common.prerequisites_size,
3098646a3b5SJorge Lopez MAX_PREREQUISITES_SIZE);
3108646a3b5SJorge Lopez
3118646a3b5SJorge Lopez for (reqs = 0; reqs < size; reqs++) {
3128646a3b5SJorge Lopez ret = hp_convert_hexstr_to_str(password_obj[elem + reqs].string.pointer,
3138646a3b5SJorge Lopez password_obj[elem + reqs].string.length,
3148646a3b5SJorge Lopez &str_value, &value_len);
3158646a3b5SJorge Lopez
3168646a3b5SJorge Lopez if (ret)
3178646a3b5SJorge Lopez break;
3188646a3b5SJorge Lopez
3198646a3b5SJorge Lopez strscpy(password_data->common.prerequisites[reqs],
3208646a3b5SJorge Lopez str_value,
3218646a3b5SJorge Lopez sizeof(password_data->common.prerequisites[reqs]));
3228646a3b5SJorge Lopez
3238646a3b5SJorge Lopez kfree(str_value);
324467d4163SJorge Lopez str_value = NULL;
325467d4163SJorge Lopez
3268646a3b5SJorge Lopez }
3278646a3b5SJorge Lopez break;
3288646a3b5SJorge Lopez case SECURITY_LEVEL:
3298646a3b5SJorge Lopez password_data->common.security_level = int_value;
3308646a3b5SJorge Lopez break;
3318646a3b5SJorge Lopez case PSWD_MIN_LENGTH:
3328646a3b5SJorge Lopez password_data->min_password_length = int_value;
3338646a3b5SJorge Lopez break;
3348646a3b5SJorge Lopez case PSWD_MAX_LENGTH:
3358646a3b5SJorge Lopez password_data->max_password_length = int_value;
3368646a3b5SJorge Lopez break;
3378646a3b5SJorge Lopez case PSWD_SIZE:
338*efd4211eSJorge Lopez
339*efd4211eSJorge Lopez if (int_value > MAX_ENCODINGS_SIZE) {
3408646a3b5SJorge Lopez pr_warn("Password Encoding size value exceeded the maximum number of elements supported or data may be malformed\n");
341*efd4211eSJorge Lopez int_value = MAX_ENCODINGS_SIZE;
342*efd4211eSJorge Lopez }
343*efd4211eSJorge Lopez password_data->encodings_size = int_value;
3448646a3b5SJorge Lopez
345a585400bSJorge Lopez /* This step is needed to keep the expected
3468646a3b5SJorge Lopez * element list pointing to the right obj[elem].type
3478646a3b5SJorge Lopez * when the size is zero. PSWD_ENCODINGS
3488646a3b5SJorge Lopez * object is omitted by BIOS when the size is
3498646a3b5SJorge Lopez * zero.
3508646a3b5SJorge Lopez */
3518646a3b5SJorge Lopez if (int_value == 0)
3528646a3b5SJorge Lopez eloc++;
3538646a3b5SJorge Lopez break;
3548646a3b5SJorge Lopez case PSWD_ENCODINGS:
3558646a3b5SJorge Lopez size = min_t(u32, password_data->encodings_size, MAX_ENCODINGS_SIZE);
3568646a3b5SJorge Lopez for (pos_values = 0; pos_values < size; pos_values++) {
3578646a3b5SJorge Lopez ret = hp_convert_hexstr_to_str(password_obj[elem + pos_values].string.pointer,
3588646a3b5SJorge Lopez password_obj[elem + pos_values].string.length,
3598646a3b5SJorge Lopez &str_value, &value_len);
3608646a3b5SJorge Lopez if (ret)
3618646a3b5SJorge Lopez break;
3628646a3b5SJorge Lopez
3638646a3b5SJorge Lopez strscpy(password_data->encodings[pos_values],
3648646a3b5SJorge Lopez str_value,
3658646a3b5SJorge Lopez sizeof(password_data->encodings[pos_values]));
3668646a3b5SJorge Lopez kfree(str_value);
367467d4163SJorge Lopez str_value = NULL;
368467d4163SJorge Lopez
3698646a3b5SJorge Lopez }
3708646a3b5SJorge Lopez break;
3718646a3b5SJorge Lopez case PSWD_IS_SET:
3728646a3b5SJorge Lopez password_data->is_enabled = int_value;
3738646a3b5SJorge Lopez break;
3748646a3b5SJorge Lopez default:
3758646a3b5SJorge Lopez pr_warn("Invalid element: %d found in Password attribute or data may be malformed\n", elem);
3768646a3b5SJorge Lopez break;
3778646a3b5SJorge Lopez }
378467d4163SJorge Lopez
379467d4163SJorge Lopez kfree(str_value);
380467d4163SJorge Lopez str_value = NULL;
3818646a3b5SJorge Lopez }
3828646a3b5SJorge Lopez
3838646a3b5SJorge Lopez exit_package:
3848646a3b5SJorge Lopez kfree(str_value);
3858646a3b5SJorge Lopez return 0;
3868646a3b5SJorge Lopez }
3878646a3b5SJorge Lopez
3888646a3b5SJorge Lopez /**
3898646a3b5SJorge Lopez * hp_populate_password_package_data()
3908646a3b5SJorge Lopez * Populate all properties for an instance under password attribute
3918646a3b5SJorge Lopez *
3928646a3b5SJorge Lopez * @password_obj: ACPI object with password data
3938646a3b5SJorge Lopez * @instance_id: The instance to enumerate
3948646a3b5SJorge Lopez * @attr_name_kobj: The parent kernel object
3958646a3b5SJorge Lopez */
hp_populate_password_package_data(union acpi_object * password_obj,int instance_id,struct kobject * attr_name_kobj)3968646a3b5SJorge Lopez int hp_populate_password_package_data(union acpi_object *password_obj, int instance_id,
3978646a3b5SJorge Lopez struct kobject *attr_name_kobj)
3988646a3b5SJorge Lopez {
3998646a3b5SJorge Lopez struct password_data *password_data = &bioscfg_drv.password_data[instance_id];
4008646a3b5SJorge Lopez
4018646a3b5SJorge Lopez password_data->attr_name_kobj = attr_name_kobj;
4028646a3b5SJorge Lopez
4038646a3b5SJorge Lopez hp_populate_password_elements_from_package(password_obj,
4048646a3b5SJorge Lopez password_obj->package.count,
4058646a3b5SJorge Lopez instance_id);
4068646a3b5SJorge Lopez
4078646a3b5SJorge Lopez hp_friendly_user_name_update(password_data->common.path,
4088646a3b5SJorge Lopez attr_name_kobj->name,
4098646a3b5SJorge Lopez password_data->common.display_name,
4108646a3b5SJorge Lopez sizeof(password_data->common.display_name));
4118646a3b5SJorge Lopez
4128646a3b5SJorge Lopez if (!strcmp(attr_name_kobj->name, SETUP_PASSWD))
4138646a3b5SJorge Lopez return sysfs_create_group(attr_name_kobj, &password_attr_group);
4148646a3b5SJorge Lopez
4158646a3b5SJorge Lopez return sysfs_create_group(attr_name_kobj, &password_attr_group);
4168646a3b5SJorge Lopez }
4178646a3b5SJorge Lopez
hp_populate_password_elements_from_buffer(u8 * buffer_ptr,u32 * buffer_size,int instance_id)4188646a3b5SJorge Lopez static int hp_populate_password_elements_from_buffer(u8 *buffer_ptr, u32 *buffer_size,
4198646a3b5SJorge Lopez int instance_id)
4208646a3b5SJorge Lopez {
4218646a3b5SJorge Lopez int values;
4228646a3b5SJorge Lopez int isreadonly;
4238646a3b5SJorge Lopez struct password_data *password_data = &bioscfg_drv.password_data[instance_id];
4248646a3b5SJorge Lopez int ret = 0;
4258646a3b5SJorge Lopez
4268646a3b5SJorge Lopez /*
4278646a3b5SJorge Lopez * Only data relevant to this driver and its functionality is
4288646a3b5SJorge Lopez * read. BIOS defines the order in which each * element is
4298646a3b5SJorge Lopez * read. Element 0 data is not relevant to this
4308646a3b5SJorge Lopez * driver hence it is ignored. For clarity, all element names
4318646a3b5SJorge Lopez * (DISPLAY_IN_UI) which defines the order in which is read
4328646a3b5SJorge Lopez * and the name matches the variable where the data is stored.
4338646a3b5SJorge Lopez *
4348646a3b5SJorge Lopez * In earlier implementation, reported errors were ignored
4358646a3b5SJorge Lopez * causing the data to remain uninitialized. It is not
4368646a3b5SJorge Lopez * possible to determine if data read from BIOS is valid or
4378646a3b5SJorge Lopez * not. It is for this reason functions may return a error
4388646a3b5SJorge Lopez * without validating the data itself.
4398646a3b5SJorge Lopez */
4408646a3b5SJorge Lopez
4418646a3b5SJorge Lopez // VALUE:
4428646a3b5SJorge Lopez ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, password_data->current_password,
4438646a3b5SJorge Lopez sizeof(password_data->current_password));
4448646a3b5SJorge Lopez if (ret < 0)
4458646a3b5SJorge Lopez goto buffer_exit;
4468646a3b5SJorge Lopez
4478646a3b5SJorge Lopez // COMMON:
4488646a3b5SJorge Lopez ret = hp_get_common_data_from_buffer(&buffer_ptr, buffer_size,
4498646a3b5SJorge Lopez &password_data->common);
4508646a3b5SJorge Lopez if (ret < 0)
4518646a3b5SJorge Lopez goto buffer_exit;
4528646a3b5SJorge Lopez
4538646a3b5SJorge Lopez // PSWD_MIN_LENGTH:
4548646a3b5SJorge Lopez ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size,
4558646a3b5SJorge Lopez &password_data->min_password_length);
4568646a3b5SJorge Lopez if (ret < 0)
4578646a3b5SJorge Lopez goto buffer_exit;
4588646a3b5SJorge Lopez
4598646a3b5SJorge Lopez // PSWD_MAX_LENGTH:
4608646a3b5SJorge Lopez ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size,
4618646a3b5SJorge Lopez &password_data->max_password_length);
4628646a3b5SJorge Lopez if (ret < 0)
4638646a3b5SJorge Lopez goto buffer_exit;
4648646a3b5SJorge Lopez
4658646a3b5SJorge Lopez // PSWD_SIZE:
4668646a3b5SJorge Lopez ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size,
4678646a3b5SJorge Lopez &password_data->encodings_size);
4688646a3b5SJorge Lopez if (ret < 0)
4698646a3b5SJorge Lopez goto buffer_exit;
4708646a3b5SJorge Lopez
4718646a3b5SJorge Lopez if (password_data->encodings_size > MAX_ENCODINGS_SIZE) {
4728646a3b5SJorge Lopez /* Report a message and limit possible values size to maximum value */
4738646a3b5SJorge Lopez pr_warn("Password Encoding size value exceeded the maximum number of elements supported or data may be malformed\n");
4748646a3b5SJorge Lopez password_data->encodings_size = MAX_ENCODINGS_SIZE;
4758646a3b5SJorge Lopez }
4768646a3b5SJorge Lopez
4778646a3b5SJorge Lopez // PSWD_ENCODINGS:
4788646a3b5SJorge Lopez for (values = 0; values < password_data->encodings_size; values++) {
4798646a3b5SJorge Lopez ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size,
4808646a3b5SJorge Lopez password_data->encodings[values],
4818646a3b5SJorge Lopez sizeof(password_data->encodings[values]));
4828646a3b5SJorge Lopez if (ret < 0)
4838646a3b5SJorge Lopez break;
4848646a3b5SJorge Lopez }
4858646a3b5SJorge Lopez
4868646a3b5SJorge Lopez // PSWD_IS_SET:
4878646a3b5SJorge Lopez ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size, &isreadonly);
4888646a3b5SJorge Lopez if (ret < 0)
4898646a3b5SJorge Lopez goto buffer_exit;
4908646a3b5SJorge Lopez
4918646a3b5SJorge Lopez password_data->is_enabled = isreadonly ? true : false;
4928646a3b5SJorge Lopez
4938646a3b5SJorge Lopez buffer_exit:
4948646a3b5SJorge Lopez return ret;
4958646a3b5SJorge Lopez }
4968646a3b5SJorge Lopez
4978646a3b5SJorge Lopez /**
4988646a3b5SJorge Lopez * hp_populate_password_buffer_data()
4998646a3b5SJorge Lopez * Populate all properties for an instance under password object attribute
5008646a3b5SJorge Lopez *
5018646a3b5SJorge Lopez * @buffer_ptr: Buffer pointer
5028646a3b5SJorge Lopez * @buffer_size: Buffer size
5038646a3b5SJorge Lopez * @instance_id: The instance to enumerate
5048646a3b5SJorge Lopez * @attr_name_kobj: The parent kernel object
5058646a3b5SJorge Lopez */
hp_populate_password_buffer_data(u8 * buffer_ptr,u32 * buffer_size,int instance_id,struct kobject * attr_name_kobj)5068646a3b5SJorge Lopez int hp_populate_password_buffer_data(u8 *buffer_ptr, u32 *buffer_size, int instance_id,
5078646a3b5SJorge Lopez struct kobject *attr_name_kobj)
5088646a3b5SJorge Lopez {
5098646a3b5SJorge Lopez struct password_data *password_data = &bioscfg_drv.password_data[instance_id];
5108646a3b5SJorge Lopez int ret = 0;
5118646a3b5SJorge Lopez
5128646a3b5SJorge Lopez password_data->attr_name_kobj = attr_name_kobj;
5138646a3b5SJorge Lopez
5148646a3b5SJorge Lopez /* Populate Password attributes */
5158646a3b5SJorge Lopez ret = hp_populate_password_elements_from_buffer(buffer_ptr, buffer_size,
5168646a3b5SJorge Lopez instance_id);
5178646a3b5SJorge Lopez if (ret < 0)
5188646a3b5SJorge Lopez return ret;
5198646a3b5SJorge Lopez
5208646a3b5SJorge Lopez hp_friendly_user_name_update(password_data->common.path,
5218646a3b5SJorge Lopez attr_name_kobj->name,
5228646a3b5SJorge Lopez password_data->common.display_name,
5238646a3b5SJorge Lopez sizeof(password_data->common.display_name));
5248646a3b5SJorge Lopez if (!strcmp(attr_name_kobj->name, SETUP_PASSWD))
5258646a3b5SJorge Lopez return sysfs_create_group(attr_name_kobj, &password_attr_group);
5268646a3b5SJorge Lopez
5278646a3b5SJorge Lopez return sysfs_create_group(attr_name_kobj, &password_attr_group);
5288646a3b5SJorge Lopez }
5298646a3b5SJorge Lopez
5308646a3b5SJorge Lopez /**
5318646a3b5SJorge Lopez * hp_exit_password_attributes() - Clear all attribute data
5328646a3b5SJorge Lopez *
5338646a3b5SJorge Lopez * Clears all data allocated for this group of attributes
5348646a3b5SJorge Lopez */
hp_exit_password_attributes(void)5358646a3b5SJorge Lopez void hp_exit_password_attributes(void)
5368646a3b5SJorge Lopez {
5378646a3b5SJorge Lopez int instance_id;
5388646a3b5SJorge Lopez
5398646a3b5SJorge Lopez for (instance_id = 0; instance_id < bioscfg_drv.password_instances_count;
5408646a3b5SJorge Lopez instance_id++) {
5418646a3b5SJorge Lopez struct kobject *attr_name_kobj =
5428646a3b5SJorge Lopez bioscfg_drv.password_data[instance_id].attr_name_kobj;
5438646a3b5SJorge Lopez
5448646a3b5SJorge Lopez if (attr_name_kobj) {
5458646a3b5SJorge Lopez if (!strcmp(attr_name_kobj->name, SETUP_PASSWD))
5468646a3b5SJorge Lopez sysfs_remove_group(attr_name_kobj,
5478646a3b5SJorge Lopez &password_attr_group);
5488646a3b5SJorge Lopez else
5498646a3b5SJorge Lopez sysfs_remove_group(attr_name_kobj,
5508646a3b5SJorge Lopez &password_attr_group);
5518646a3b5SJorge Lopez }
5528646a3b5SJorge Lopez }
5538646a3b5SJorge Lopez bioscfg_drv.password_instances_count = 0;
5548646a3b5SJorge Lopez kfree(bioscfg_drv.password_data);
5558646a3b5SJorge Lopez bioscfg_drv.password_data = NULL;
5568646a3b5SJorge Lopez }
557