├── .shellcheck-ignore ├── .gitignore ├── .upstream-base-commit ├── include ├── config.hpp ├── manager_serialize.hpp ├── rfutility.hpp ├── boot_option.hpp ├── asio_connection.hpp ├── bootvalidflag.hpp ├── password.hpp ├── secureboot.hpp └── manager.hpp ├── subprojects ├── sdbusplus.wrap ├── nlohmann-json.wrap ├── phosphor-logging.wrap ├── phosphor-dbus-interfaces.wrap ├── packagefiles │ └── boost │ │ └── meson.build ├── boost.wrap ├── cereal.wrap └── openssl.wrap ├── service_files └── xyz.openbmc_project.biosconfig_manager.service ├── meson.options ├── LICENSE ├── OWNERS ├── src ├── boot_option.cpp ├── rfutility.cpp ├── secureboot.cpp ├── main.cpp ├── manager_serialize.cpp ├── password.cpp ├── bootvalidflag.cpp └── manager.cpp ├── meson.build ├── .clang-format-pending ├── .clang-format └── README.md /.shellcheck-ignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | subprojects/* 3 | !subprojects/*.wrap 4 | -------------------------------------------------------------------------------- /.upstream-base-commit: -------------------------------------------------------------------------------- 1 | 20de6de8a8fb01032dc90d698559259af4245a87 2023-10-20 11:19:48 -0500 2 | -------------------------------------------------------------------------------- /include/config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static constexpr auto BIOS_PERSIST_PATH = "/var/lib/bios-settings-manager"; 4 | -------------------------------------------------------------------------------- /subprojects/sdbusplus.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/openbmc/sdbusplus.git 3 | revision = HEAD 4 | 5 | [provide] 6 | sdbusplus = sdbusplus_dep 7 | 8 | -------------------------------------------------------------------------------- /subprojects/nlohmann-json.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/nlohmann/json.git 3 | revision = HEAD 4 | 5 | [provide] 6 | nlohmann_json = nlohmann_json_dep 7 | 8 | -------------------------------------------------------------------------------- /subprojects/phosphor-logging.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/openbmc/phosphor-logging.git 3 | revision = HEAD 4 | 5 | [provide] 6 | phosphor-logging = phosphor_logging_dep 7 | -------------------------------------------------------------------------------- /subprojects/phosphor-dbus-interfaces.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/openbmc/phosphor-dbus-interfaces.git 3 | revision = HEAD 4 | 5 | [provide] 6 | phosphor-dbus-interfaces = phosphor_dbus_interfaces_dep 7 | 8 | -------------------------------------------------------------------------------- /subprojects/packagefiles/boost/meson.build: -------------------------------------------------------------------------------- 1 | project('boost', 'cpp', version: '1.84.0', license: 'Boost') 2 | 3 | boost_dep = declare_dependency(include_directories: include_directories('.')) 4 | 5 | meson.override_dependency('boost', boost_dep) 6 | -------------------------------------------------------------------------------- /subprojects/boost.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = boost_1_84_0 3 | 4 | source_url = https://boostorg.jfrog.io/artifactory/main/release/1.84.0/source/boost_1_84_0.tar.bz2 5 | source_hash = cc4b893acf645c9d4b698e9a0f08ca8846aa5d6c68275c14c3e7949c24109454 6 | source_filename = 1_84_0.tar.bz2 7 | 8 | patch_directory = boost 9 | 10 | [provide] 11 | boost = boost_dep 12 | -------------------------------------------------------------------------------- /service_files/xyz.openbmc_project.biosconfig_manager.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description= BIOS Config Manager - For Remote BIOS configuration update 3 | 4 | [Service] 5 | Restart=always 6 | ExecStart=/usr/bin/biosconfig-manager 7 | SyslogIdentifier=biosconfig-manager 8 | Type=dbus 9 | BusName=xyz.openbmc_project.BIOSConfigManager 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /meson.options: -------------------------------------------------------------------------------- 1 | option( 2 | 'clear-pending-bootorder-on-update', 3 | type: 'feature', 4 | value: 'disabled', 5 | description: 'Enable/disable remove bootOrder pending list on setting active bootorder.', 6 | ) 7 | option( 8 | 'enable-bios-secureboot', 9 | type: 'feature', 10 | value: 'disabled', 11 | description: 'Enable BIOS SecureBoot configuration. The UEFI Secureboot information is obtained via Redfish Host Interface', 12 | ) 13 | -------------------------------------------------------------------------------- /subprojects/cereal.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = cereal-1.3.2 3 | source_url = https://github.com/USCiLab/cereal/archive/v1.3.2.tar.gz 4 | source_filename = cereal-1.3.2.tar.gz 5 | source_hash = 16a7ad9b31ba5880dac55d62b5d6f243c3ebc8d46a3514149e56b5e7ea81f85f 6 | patch_filename = cereal_1.3.2-1_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/cereal_1.3.2-1/get_patch 8 | patch_hash = fd2f047a40a0d291c643fdafe4ce743f0eadbef667b6afe43a332e1ba0862603 9 | 10 | [provide] 11 | cereal = cereal_dep 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Intel Corporation 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /subprojects/openssl.wrap: -------------------------------------------------------------------------------- 1 | [wrap-file] 2 | directory = openssl-3.0.8 3 | source_url = https://www.openssl.org/source/openssl-3.0.8.tar.gz 4 | source_filename = openssl-3.0.8.tar.gz 5 | source_hash = 6c13d2bf38fdf31eac3ce2a347073673f5d63263398f1f69d0df4a41253e4b3e 6 | patch_filename = openssl_3.0.8-2_patch.zip 7 | patch_url = https://wrapdb.mesonbuild.com/v2/openssl_3.0.8-2/get_patch 8 | patch_hash = e84b5fe469e681e3318184157a0c7c43d4cbacd078bb88f506e31569f8f75072 9 | source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/openssl_3.0.8-2/openssl-3.0.8.tar.gz 10 | wrapdb_version = 3.0.8-2 11 | 12 | [provide] 13 | libcrypto = libcrypto_dep 14 | libssl = libssl_dep 15 | openssl = openssl_dep 16 | 17 | -------------------------------------------------------------------------------- /include/manager_serialize.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "boot_option.hpp" 4 | #include "manager.hpp" 5 | 6 | #include 7 | 8 | namespace bios_config 9 | { 10 | 11 | /** @brief Serialize and persist the bios manager object 12 | * 13 | * @param[in] obj - bios manager object 14 | * @param[in] path - path to the file where the bios manager object 15 | * is to be serialized 16 | */ 17 | void serialize(const Manager& obj, const fs::path& path); 18 | 19 | /** @brief Deserialize the persisted data and populate the bios manager object 20 | * 21 | * @param[in] path - path to the persisted file 22 | * @param[in/out] entry - reference to the bios manager object which is the 23 | * target of deserialization. 24 | * 25 | * @return bool - true if the deserialization was successful, false otherwise. 26 | */ 27 | bool deserialize(const fs::path& path, Manager& entry); 28 | 29 | } // namespace bios_config 30 | -------------------------------------------------------------------------------- /include/rfutility.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #pragma once 18 | #include 19 | namespace bios_config 20 | { 21 | 22 | void parsePropertyValueAndSendEvent(const std::string propertyName, 23 | const std::string dbusPropertyValue, 24 | const std::string objectPath); 25 | void sendRedfishEvent(const std::string propertyName, 26 | const std::string propertyValue, 27 | const std::string objectPath); 28 | } // namespace bios_config 29 | -------------------------------------------------------------------------------- /include/boot_option.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | namespace bios_config 11 | { 12 | using BootOptionDbusBase = sdbusplus::server::object_t< 13 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::BootOption, 14 | sdbusplus::xyz::openbmc_project::Object::server::Delete>; 15 | 16 | class Manager; 17 | 18 | class BootOptionDbus : public BootOptionDbusBase 19 | { 20 | public: 21 | /** @brief Constructs BootOptionDbus object. 22 | * 23 | * @param[in] bus - Bus to attach to. 24 | * @param[in] path - Path to attach at. 25 | * @param[in] parent - Reference of parent. 26 | * @param[in] key - Key of this object. 27 | */ 28 | BootOptionDbus(sdbusplus::bus_t& bus, const char* path, Manager& parent, 29 | const std::string key); 30 | 31 | bool enabled(bool value) override; 32 | bool pendingEnabled(bool value) override; 33 | std::string description(std::string value) override; 34 | std::string displayName(std::string value) override; 35 | std::string uefiDevicePath(std::string value) override; 36 | 37 | void delete_() override; 38 | 39 | private: 40 | Manager& parent; 41 | const std::string key; 42 | }; 43 | } // namespace bios_config 44 | -------------------------------------------------------------------------------- /include/asio_connection.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #pragma once 18 | #include 19 | #include 20 | 21 | namespace phosphor 22 | { 23 | namespace logging 24 | { 25 | class AsioConnection 26 | { 27 | public: 28 | AsioConnection() = delete; 29 | AsioConnection(const AsioConnection&) = delete; 30 | AsioConnection& operator=(const AsioConnection&) = delete; 31 | AsioConnection(AsioConnection&&) = delete; 32 | AsioConnection& operator=(AsioConnection&&) = delete; 33 | ~AsioConnection() = delete; 34 | 35 | /** @brief Get the asio connection. */ 36 | static auto& getAsioConnection() 37 | { 38 | static boost::asio::io_context io; 39 | static auto conn = std::make_shared(io); 40 | return conn; 41 | } 42 | }; 43 | } // namespace logging 44 | } // namespace phosphor 45 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # OWNERS 2 | # ------ 3 | # 4 | # The OWNERS file maintains the list of individuals responsible for various 5 | # parts of this repository, including code review and approval. We use the 6 | # Gerrit 'owners' plugin, which consumes this file, along with some extra 7 | # keywords for our own purposes and tooling. 8 | # 9 | # For details on the configuration used by 'owners' see: 10 | # https://gerrit.googlesource.com/plugins/owners/+/refs/heads/master/owners/src/main/resources/Documentation/config.md 11 | # 12 | # An OWNERS file must be in the root of a repository but may also be present 13 | # in any subdirectory. The contents of the subdirectory OWNERS file are 14 | # combined with parent directories unless 'inherit: false' is set. 15 | # 16 | # The owners file is YAML and has [up to] 4 top-level keywords. 17 | # * owners: A list of individuals who have approval authority on the 18 | # repository. 19 | # 20 | # * reviewers: A list of individuals who have requested review notification 21 | # on the repository. 22 | # 23 | # * matchers: A list of specific file/path matchers for granular 'owners' and 24 | # 'reviewers'. See 'owners' plugin documentation. 25 | # 26 | # * openbmc: A list of openbmc-specific meta-data about owners and reviewers. 27 | # - name: preferred name of the individual. 28 | # - email: preferred email address of the individual. 29 | # - discord: Discord nickname of the individual. 30 | # 31 | # It is expected that these 4 sections will be listed in the order above and 32 | # data within them will be kept sorted. 33 | 34 | owners: 35 | - wangkuiying.wky@alibaba-inc.com 36 | - manojkiran.eda@gmail.com 37 | 38 | reviewers: 39 | 40 | matchers: 41 | 42 | openbmc: 43 | - name: Kuiying Wang 44 | email: wangkuiying.wky@alibaba-inc.com 45 | discord: Kwin 46 | - name: Manojkiran Eda 47 | email: manojkiran.eda@gmail.com 48 | discord: manojkiran 49 | -------------------------------------------------------------------------------- /src/boot_option.cpp: -------------------------------------------------------------------------------- 1 | #include "boot_option.hpp" 2 | 3 | #include "manager.hpp" 4 | #include "manager_serialize.hpp" 5 | 6 | namespace bios_config 7 | { 8 | 9 | BootOptionDbus::BootOptionDbus(sdbusplus::bus_t& bus, const char* path, 10 | Manager& parent, const std::string key) : 11 | BootOptionDbusBase(bus, path), parent(parent), key(key) 12 | {} 13 | 14 | bool BootOptionDbus::enabled(bool value) 15 | { 16 | auto enabled = BootOptionDbusBase::enabled(value, false); 17 | parent.bootOptionValues[key]["Enabled"] = enabled; 18 | auto pendingEnabled = BootOptionDbusBase::pendingEnabled(value, false); 19 | parent.bootOptionValues[key]["PendingEnabled"] = pendingEnabled; 20 | serialize(parent, parent.biosFile); 21 | return enabled; 22 | } 23 | 24 | bool BootOptionDbus::pendingEnabled(bool value) 25 | { 26 | auto v = BootOptionDbusBase::pendingEnabled(value, false); 27 | parent.bootOptionValues[key]["PendingEnabled"] = v; 28 | serialize(parent, parent.biosFile); 29 | return v; 30 | } 31 | 32 | std::string BootOptionDbus::description(std::string value) 33 | { 34 | auto v = BootOptionDbusBase::description(value, false); 35 | parent.bootOptionValues[key]["Description"] = v; 36 | serialize(parent, parent.biosFile); 37 | return v; 38 | } 39 | 40 | std::string BootOptionDbus::displayName(std::string value) 41 | { 42 | auto v = BootOptionDbusBase::displayName(value, false); 43 | parent.bootOptionValues[key]["DisplayName"] = v; 44 | serialize(parent, parent.biosFile); 45 | return v; 46 | } 47 | 48 | std::string BootOptionDbus::uefiDevicePath(std::string value) 49 | { 50 | auto v = BootOptionDbusBase::uefiDevicePath(value, false); 51 | parent.bootOptionValues[key]["UefiDevicePath"] = v; 52 | serialize(parent, parent.biosFile); 53 | return v; 54 | } 55 | 56 | void BootOptionDbus::delete_() 57 | { 58 | parent.deleteBootOption(key); 59 | } 60 | } // namespace bios_config 61 | -------------------------------------------------------------------------------- /src/rfutility.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #include "rfutility.hpp" 18 | 19 | #include "asio_connection.hpp" 20 | 21 | #include 22 | 23 | namespace bios_config 24 | { 25 | 26 | void parsePropertyValueAndSendEvent(const std::string propertyName, 27 | const std::string dbusPropertyValue, 28 | const std::string objectPath) 29 | { 30 | // Find the position of the last dot 31 | size_t lastDotPos = dbusPropertyValue.rfind('.'); 32 | 33 | // Check if a dot was found 34 | if (lastDotPos != std::string::npos) 35 | { 36 | // Extract the substring after the last dot 37 | std::string propertyValue = dbusPropertyValue.substr(lastDotPos + 1); 38 | // Send the redfish event 39 | sendRedfishEvent(propertyName, propertyValue, objectPath); 40 | } 41 | } 42 | 43 | void sendRedfishEvent(const std::string propertyName, 44 | const std::string propertyValue, 45 | const std::string objectPath) 46 | { 47 | using namespace phosphor::logging; 48 | // send event. 49 | std::vector messageArgs = {propertyName, propertyValue}; 50 | auto& conn = AsioConnection::getAsioConnection(); 51 | sendEvent(conn, MESSAGE_TYPE::PROPERTY_VALUE_MODIFIED, 52 | Entry::Level::Informational, messageArgs, objectPath); 53 | } 54 | 55 | } // namespace bios_config 56 | -------------------------------------------------------------------------------- /src/secureboot.cpp: -------------------------------------------------------------------------------- 1 | #include "secureboot.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | // Register class version with Cereal 8 | CEREAL_CLASS_VERSION(bios_config::SecureBoot, 0) 9 | 10 | namespace bios_config 11 | { 12 | 13 | SecureBoot::SecureBoot(sdbusplus::asio::object_server& objectServer, 14 | std::shared_ptr& systemBus, 15 | std::string persistPath) : 16 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot( 17 | *systemBus, secureBootObjectPath), 18 | objServer(objectServer), systemBus(systemBus) 19 | { 20 | fs::path secureBootDir(persistPath); 21 | fs::create_directories(secureBootDir); 22 | secureBootFile = secureBootDir / secureBootPersistFile; 23 | deserialize(); 24 | } 25 | 26 | SecureBootBase::CurrentBootType SecureBoot::currentBoot( 27 | SecureBootBase::CurrentBootType value) 28 | { 29 | auto ret = SecureBootBase::currentBoot(value); 30 | serialize(); 31 | return ret; 32 | } 33 | 34 | bool SecureBoot::pendingEnable(bool value) 35 | { 36 | auto ret = SecureBootBase::pendingEnable(value); 37 | serialize(); 38 | return ret; 39 | } 40 | 41 | SecureBootBase::ModeType SecureBoot::mode(SecureBootBase::ModeType value) 42 | { 43 | auto ret = SecureBootBase::mode(value); 44 | serialize(); 45 | return ret; 46 | } 47 | 48 | void SecureBoot::serialize() 49 | { 50 | try 51 | { 52 | std::filesystem::create_directories(secureBootFile.parent_path()); 53 | std::ofstream os(secureBootFile.c_str(), 54 | std::ios::out | std::ios::binary); 55 | cereal::BinaryOutputArchive oarchive(os); 56 | oarchive(*this); 57 | } 58 | catch (const std::exception& e) 59 | { 60 | lg2::error("Failed to serialize SecureBoot: {ERROR}", "ERROR", e); 61 | } 62 | } 63 | 64 | bool SecureBoot::deserialize() 65 | { 66 | try 67 | { 68 | if (std::filesystem::exists(secureBootFile)) 69 | { 70 | std::ifstream is(secureBootFile.c_str(), 71 | std::ios::in | std::ios::binary); 72 | cereal::BinaryInputArchive iarchive(is); 73 | iarchive(*this); 74 | return true; 75 | } 76 | return false; 77 | } 78 | catch (const std::exception& e) 79 | { 80 | lg2::error("Failed to deserialize SecureBoot: {ERROR}", "ERROR", e); 81 | return false; 82 | } 83 | } 84 | } // namespace bios_config 85 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Intel Corporation 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http:www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | #include "configuration.h" 17 | 18 | #include "bootvalidflag.hpp" 19 | #include "config.hpp" 20 | #include "manager.hpp" 21 | #include "password.hpp" 22 | #include "secureboot.hpp" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | PHOSPHOR_LOG2_USING; 31 | 32 | int main(int argc, char** argv) 33 | { 34 | std::string persistPath = BIOS_PERSIST_PATH; 35 | if (argc >= 2) 36 | { 37 | persistPath = argv[1]; 38 | info("Using temporary path {PATH}", "PATH", persistPath); 39 | } 40 | 41 | boost::asio::io_context io; 42 | auto systemBus = std::make_shared(io); 43 | 44 | systemBus->request_name(bios_config::service); 45 | sdbusplus::asio::object_server objectServer(systemBus); 46 | 47 | /** 48 | * Manager class is responsible for handling methods and signals under 49 | * the following object path and interface. 50 | * 51 | * Object path : /xyz/openbmc_project/bios_config/manager 52 | * Interface : xyz.openbmc_project.BIOSConfig.Manager 53 | */ 54 | bios_config::Manager manager(objectServer, systemBus, persistPath); 55 | 56 | /** 57 | * Password class is responsible for handling methods and signals under 58 | * the following object path and interface. 59 | * 60 | * Object path : /xyz/openbmc_project/bios_config/password 61 | * Interface : xyz.openbmc_project.BIOSConfig.Password 62 | */ 63 | bios_config_pwd::Password password(objectServer, systemBus, persistPath); 64 | 65 | bios_config_valid::BootValidFlag bootValifFlag(systemBus, io); 66 | #ifdef ENABLE_BIOS_SECUREBOOT 67 | /** 68 | * SecureBoot class is responsible for handling methods and signals under 69 | * the following object path and interface. 70 | * 71 | * Object path : /xyz/openbmc_project/bios_config/secure_boot 72 | * Interface : xyz.openbmc_project.BIOSConfig.SecureBoot 73 | */ 74 | bios_config_sec::SecureBoot secureboot(objectServer, systemBus, 75 | persistPath); 76 | #endif 77 | 78 | io.run(); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'biosconfig-manager', 3 | 'cpp', 4 | meson_version: '>=1.1.1', 5 | default_options: [ 6 | 'warning_level=3', 7 | 'werror=true', 8 | 'cpp_std=c++23', 9 | 'buildtype=debugoptimized', 10 | ], 11 | license: 'Apache-2.0', 12 | version: '1.0', 13 | ) 14 | 15 | # Wno-psabi reduces the number of "Note:" messages when cross-compiling some STL 16 | # stuff for ARM. See https://stackoverflow.com/questions/48149323/strange-gcc-warning-when-compiling-qt-project 17 | # Basically, gcc 6 and gcc 7 are not ABI compatible, but since the whole OpenBMC 18 | # project uses the same compiler, we can safely ignmore these info notes. 19 | add_project_arguments('-Wno-psabi', language: 'cpp') 20 | 21 | conf_data = configuration_data() 22 | conf_data.set( 23 | 'CLEAR_PENDING_BOOTORDER_ON_UPDATE', 24 | get_option('clear-pending-bootorder-on-update').enabled(), 25 | ) 26 | 27 | if (get_option('enable-bios-secureboot').allowed()) 28 | add_project_arguments('-DENABLE_BIOS_SECUREBOOT', language: 'cpp') 29 | endif 30 | configure_file(output: 'configuration.h', configuration: conf_data) 31 | 32 | boost_args = [ 33 | '-DBOOST_ALL_NO_LIB', 34 | '-DBOOST_ASIO_DISABLE_THREADS', 35 | '-DBOOST_ERROR_CODE_HEADER_ONLY', 36 | '-DBOOST_NO_RTTI', 37 | '-DBOOST_NO_TYPEID', 38 | '-DBOOST_SYSTEM_NO_DEPRECATED', 39 | ] 40 | 41 | deps = [ 42 | dependency('boost'), 43 | dependency('phosphor-dbus-interfaces'), 44 | dependency('phosphor-logging'), 45 | dependency('sdbusplus'), 46 | dependency('libsystemd'), 47 | dependency('openssl'), 48 | dependency('nlohmann_json', include_type: 'system'), 49 | ] 50 | 51 | cereal = dependency('cereal', required: false) 52 | cpp = meson.get_compiler('cpp') 53 | has_cereal = cpp.has_header_symbol( 54 | 'cereal/cereal.hpp', 55 | 'cereal::specialize', 56 | dependencies: cereal, 57 | required: false, 58 | ) 59 | if not has_cereal 60 | cereal_opts = import('cmake').subproject_options() 61 | cereal_opts.add_cmake_defines( 62 | {'BUILD_TESTS': 'OFF', 'SKIP_PERFORMANCE_COMPARISON': 'ON'}, 63 | ) 64 | cereal_proj = import('cmake').subproject( 65 | 'cereal', 66 | options: cereal_opts, 67 | required: false, 68 | ) 69 | assert(cereal_proj.found(), 'cereal is required') 70 | cereal = cereal_proj.dependency('cereal') 71 | endif 72 | deps += cereal 73 | 74 | src_files = [ 75 | 'src/main.cpp', 76 | 'src/manager.cpp', 77 | 'src/manager_serialize.cpp', 78 | 'src/password.cpp', 79 | 'src/rfutility.cpp', 80 | 'src/boot_option.cpp', 81 | 'src/bootvalidflag.cpp', 82 | 'src/secureboot.cpp', 83 | ] 84 | 85 | executable( 86 | 'biosconfig-manager', 87 | src_files, 88 | implicit_include_directories: true, 89 | include_directories: ['include'], 90 | dependencies: deps, 91 | cpp_args: boost_args, 92 | install: true, 93 | install_dir: get_option('bindir'), 94 | ) 95 | 96 | systemd = dependency('systemd') 97 | systemd_system_unit_dir = systemd.get_variable( 98 | 'systemd_system_unit_dir', 99 | pkgconfig_define: ['prefix', get_option('prefix')], 100 | ) 101 | 102 | fs = import('fs') 103 | fs.copyfile( 104 | 'service_files/xyz.openbmc_project.biosconfig_manager.service', 105 | install: true, 106 | install_dir: systemd_system_unit_dir, 107 | ) 108 | -------------------------------------------------------------------------------- /include/bootvalidflag.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. 3 | * All rights reserved. SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #pragma once 18 | #include "asio_connection.hpp" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | namespace bios_config_valid 31 | { 32 | using Value = std::variant; 34 | 35 | /* 36 | The Boot Valid Flag is a Boolean indicator that determines whether the boot 37 | settings under the “/xyz/openbmc_project/control/host0/boot” path are valid for 38 | the next host boot. This flag is represented by the 39 | "xyz.openbmc_project.Object.Enable" interface within this path. This class 40 | implements the behavior of this flag according to IPMI specification V2.0, 41 | section 28.12. 42 | */ 43 | class BootValidFlag 44 | { 45 | public: 46 | BootValidFlag(std::shared_ptr systemBusPtr, 47 | boost::asio::io_context& io); 48 | 49 | private: 50 | std::unique_ptr validUpdatedMatch; 51 | std::unique_ptr softResetMatch; 52 | std::unique_ptr timer_60; 53 | std::shared_ptr dbusConnectionPtr; 54 | 55 | /** 56 | * @brief The function creates a match to signal property 57 | changes on the xyz.openbmc_project.Object.Enable interface 58 | located at the path "/xyz/openbmc_project/control/host0/boot". 59 | */ 60 | void setupMatches(sdbusplus::bus_t& systemBus); 61 | 62 | /** @brief Sets the property value of the given object. 63 | * @param[in] bus - DBUS Bus Object. 64 | * @param[in] service - Dbus service name. 65 | * @param[in] objPath - Dbus object path. 66 | * @param[in] interface - Dbus interface. 67 | * @param[in] property - name of the property. 68 | * @param[in] value - value which needs to be set. 69 | */ 70 | void setDbusProperty(const std::string& service, const std::string& objPath, 71 | const std::string& interface, 72 | const std::string& property, 73 | bios_config_valid::Value& value); 74 | 75 | /** 76 | @brief check the values of the persistent flag and timeout override flag, 77 | then change the boot valid flag accordingly. . 78 | **/ 79 | void setBootValidFlag(); 80 | 81 | /** @brief Set a timer for 60 seconds each time a property 82 | * change signal with the value "true" is received. 83 | * @param[in] msg - DBUS Bus Object. 84 | */ 85 | void setTimer(sdbusplus::message::message& msg); 86 | 87 | /** @brief Cancel the timer if the property 88 | * we get property change signal of last boot time.. 89 | * @param[in] msg - DBUS Bus Object. 90 | */ 91 | void cancelTimer(sdbusplus::message::message& msg); 92 | }; 93 | 94 | } // namespace bios_config_valid 95 | -------------------------------------------------------------------------------- /include/password.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Intel Corporation 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http:www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | namespace bios_config_pwd 31 | { 32 | static constexpr auto objectPathPwd = 33 | "/xyz/openbmc_project/bios_config/password"; 34 | constexpr auto biosSeedFile = "seedData"; 35 | constexpr uint8_t maxHashSize = 64; 36 | constexpr uint8_t maxSeedSize = 32; 37 | constexpr uint8_t maxPasswordLen = 32; 38 | constexpr int iterValue = 1000; 39 | 40 | using Base = sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password; 41 | namespace fs = std::filesystem; 42 | 43 | /** @class Password 44 | * 45 | * @brief Implements the BIOS Password 46 | */ 47 | class Password : public Base 48 | { 49 | public: 50 | Password() = delete; 51 | ~Password() = default; 52 | Password(const Password&) = delete; 53 | Password& operator=(const Password&) = delete; 54 | Password(Password&&) = delete; 55 | Password& operator=(Password&&) = delete; 56 | 57 | /** @brief Constructs Password object. 58 | * 59 | * @param[in] objectServer - object server 60 | * @param[in] systemBus - bus connection 61 | */ 62 | Password(sdbusplus::asio::object_server& objectServer, 63 | std::shared_ptr& systemBus, 64 | std::string persistPath); 65 | 66 | /** @brief Set the BIOS attribute with a new value, the new value is added 67 | * to the PendingAttribute. 68 | * 69 | * @param[in] userName - User name - user / admin. 70 | * @param[in] currentPassword - Current user/ admin Password. 71 | * @param[in] newPassword - New user/ admin Password. 72 | */ 73 | void changePassword(std::string userName, std::string currentPassword, 74 | std::string newPassword) override; 75 | 76 | private: 77 | void verifyPassword(std::string userName, std::string currentPassword, 78 | std::string newPassword); 79 | bool compareDigest(const EVP_MD* digestFunc, size_t digestLen, 80 | const std::array& expected, 81 | const std::array& seed, 82 | const std::string& rawData); 83 | bool isMatch(const std::array& expected, 84 | const std::array& seed, 85 | const std::string& rawData, const std::string& algo); 86 | bool getParam(std::array& orgUsrPwdHash, 87 | std::array& orgAdminPwdHash, 88 | std::array& seed, 89 | std::string& hashAlgo); 90 | bool verifyIntegrityCheck(std::string& newPassword, 91 | std::array& seed, 92 | unsigned int mdLen, const EVP_MD* digestFunc); 93 | sdbusplus::asio::object_server& objServer; 94 | std::shared_ptr& systemBus; 95 | std::filesystem::path seedFile; 96 | std::array mNewPwdHash; 97 | }; 98 | 99 | } // namespace bios_config_pwd 100 | -------------------------------------------------------------------------------- /.clang-format-pending: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: Align 10 | AlignTrailingComments: 11 | Kind: Always 12 | OverEmptyLines: 1 13 | AllowAllParametersOfDeclarationOnNextLine: true 14 | AllowShortBlocksOnASingleLine: Empty 15 | AllowShortCaseLabelsOnASingleLine: false 16 | AllowShortFunctionsOnASingleLine: Empty 17 | AllowShortIfStatementsOnASingleLine: Never 18 | AllowShortLambdasOnASingleLine: true 19 | AllowShortLoopsOnASingleLine: false 20 | AlwaysBreakAfterReturnType: None 21 | AlwaysBreakBeforeMultilineStrings: false 22 | AlwaysBreakTemplateDeclarations: Yes 23 | BinPackArguments: true 24 | BinPackParameters: true 25 | BitFieldColonSpacing: None 26 | BraceWrapping: 27 | AfterCaseLabel: true 28 | AfterClass: true 29 | AfterControlStatement: true 30 | AfterEnum: true 31 | AfterExternBlock: true 32 | AfterFunction: true 33 | AfterNamespace: true 34 | AfterObjCDeclaration: true 35 | AfterStruct: true 36 | AfterUnion: true 37 | BeforeCatch: true 38 | BeforeElse: true 39 | BeforeLambdaBody: false 40 | BeforeWhile: false 41 | IndentBraces: false 42 | SplitEmptyFunction: false 43 | SplitEmptyRecord: false 44 | SplitEmptyNamespace: false 45 | BreakAfterAttributes: Never 46 | BreakBeforeBinaryOperators: None 47 | BreakBeforeBraces: Custom 48 | BreakBeforeTernaryOperators: true 49 | BreakConstructorInitializers: AfterColon 50 | BreakInheritanceList: AfterColon 51 | BreakStringLiterals: false 52 | ColumnLimit: 80 53 | CommentPragmas: '^ IWYU pragma:' 54 | CompactNamespaces: false 55 | ConstructorInitializerIndentWidth: 4 56 | ContinuationIndentWidth: 4 57 | Cpp11BracedListStyle: true 58 | DerivePointerAlignment: false 59 | DisableFormat: false 60 | FixNamespaceComments: true 61 | ForEachMacros: 62 | - foreach 63 | - Q_FOREACH 64 | - BOOST_FOREACH 65 | IncludeBlocks: Regroup 66 | IncludeCategories: 67 | - Regex: '^[<"](gtest|gmock)' 68 | Priority: 7 69 | - Regex: '^"config.h"' 70 | Priority: -1 71 | - Regex: '^".*\.h"' 72 | Priority: 1 73 | - Regex: '^".*\.hpp"' 74 | Priority: 2 75 | - Regex: '^<.*\.h>' 76 | Priority: 3 77 | - Regex: '^<.*\.hpp>' 78 | Priority: 4 79 | - Regex: '^<.*' 80 | Priority: 5 81 | - Regex: '.*' 82 | Priority: 6 83 | IndentCaseLabels: true 84 | IndentExternBlock: NoIndent 85 | IndentRequiresClause: true 86 | IndentWidth: 4 87 | IndentWrappedFunctionNames: true 88 | InsertNewlineAtEOF: true 89 | KeepEmptyLinesAtTheStartOfBlocks: false 90 | LambdaBodyIndentation: OuterScope 91 | LineEnding: LF 92 | MacroBlockBegin: '' 93 | MacroBlockEnd: '' 94 | MaxEmptyLinesToKeep: 1 95 | NamespaceIndentation: None 96 | ObjCBlockIndentWidth: 2 97 | ObjCSpaceAfterProperty: false 98 | ObjCSpaceBeforeProtocolList: true 99 | PackConstructorInitializers: BinPack 100 | PenaltyBreakAssignment: 25 101 | PenaltyBreakBeforeFirstCallParameter: 19 102 | PenaltyBreakComment: 300 103 | PenaltyBreakFirstLessLess: 120 104 | PenaltyBreakString: 1000 105 | PenaltyExcessCharacter: 1000000 106 | PenaltyReturnTypeOnItsOwnLine: 60 107 | PenaltyIndentedWhitespace: 0 108 | PointerAlignment: Left 109 | QualifierAlignment: Left 110 | ReferenceAlignment: Left 111 | ReflowComments: true 112 | RequiresClausePosition: OwnLine 113 | RequiresExpressionIndentation: Keyword 114 | SortIncludes: CaseSensitive 115 | SortUsingDeclarations: true 116 | SpaceAfterCStyleCast: false 117 | SpaceAfterTemplateKeyword: true 118 | SpaceBeforeAssignmentOperators: true 119 | SpaceBeforeCpp11BracedList: false 120 | SpaceBeforeCtorInitializerColon: true 121 | SpaceBeforeInheritanceColon: true 122 | SpaceBeforeParens: ControlStatements 123 | SpaceBeforeRangeBasedForLoopColon: true 124 | SpaceInEmptyParentheses: false 125 | SpacesBeforeTrailingComments: 1 126 | SpacesInAngles: Never 127 | SpacesInContainerLiterals: true 128 | SpacesInCStyleCastParentheses: false 129 | SpacesInParentheses: false 130 | SpacesInSquareBrackets: false 131 | Standard: Latest 132 | TabWidth: 4 133 | UseTab: Never 134 | ... 135 | 136 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: Align 10 | AlignTrailingComments: 11 | Kind: Always 12 | OverEmptyLines: 1 13 | AllowAllParametersOfDeclarationOnNextLine: true 14 | AllowShortBlocksOnASingleLine: Empty 15 | AllowShortCaseLabelsOnASingleLine: false 16 | AllowShortFunctionsOnASingleLine: Empty 17 | AllowShortIfStatementsOnASingleLine: Never 18 | AllowShortLambdasOnASingleLine: true 19 | AllowShortLoopsOnASingleLine: false 20 | AlwaysBreakBeforeMultilineStrings: false 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BitFieldColonSpacing: None 24 | BraceWrapping: 25 | AfterCaseLabel: true 26 | AfterClass: true 27 | AfterControlStatement: true 28 | AfterEnum: true 29 | AfterExternBlock: true 30 | AfterFunction: true 31 | AfterNamespace: true 32 | AfterObjCDeclaration: true 33 | AfterStruct: true 34 | AfterUnion: true 35 | BeforeCatch: true 36 | BeforeElse: true 37 | BeforeLambdaBody: false 38 | BeforeWhile: false 39 | IndentBraces: false 40 | SplitEmptyFunction: false 41 | SplitEmptyRecord: false 42 | SplitEmptyNamespace: false 43 | BreakAfterAttributes: Never 44 | BreakAfterReturnType: Automatic 45 | BreakBeforeBinaryOperators: None 46 | BreakBeforeBraces: Custom 47 | BreakBeforeTernaryOperators: true 48 | BreakConstructorInitializers: AfterColon 49 | BreakInheritanceList: AfterColon 50 | BreakStringLiterals: false 51 | BreakTemplateDeclarations: Yes 52 | ColumnLimit: 80 53 | CommentPragmas: '^ IWYU pragma:' 54 | CompactNamespaces: false 55 | ConstructorInitializerIndentWidth: 4 56 | ContinuationIndentWidth: 4 57 | Cpp11BracedListStyle: true 58 | DerivePointerAlignment: false 59 | DisableFormat: false 60 | FixNamespaceComments: true 61 | ForEachMacros: 62 | - foreach 63 | - Q_FOREACH 64 | - BOOST_FOREACH 65 | IncludeBlocks: Regroup 66 | IncludeCategories: 67 | - Regex: '^[<"](gtest|gmock)' 68 | Priority: 7 69 | - Regex: '^"config.h"' 70 | Priority: -1 71 | - Regex: '^".*\.h"' 72 | Priority: 1 73 | - Regex: '^".*\.hpp"' 74 | Priority: 2 75 | - Regex: '^<.*\.h>' 76 | Priority: 3 77 | - Regex: '^<.*\.hpp>' 78 | Priority: 4 79 | - Regex: '^<.*' 80 | Priority: 5 81 | - Regex: '.*' 82 | Priority: 6 83 | IndentCaseLabels: true 84 | IndentExternBlock: NoIndent 85 | IndentRequiresClause: true 86 | IndentWidth: 4 87 | IndentWrappedFunctionNames: true 88 | InsertNewlineAtEOF: true 89 | KeepEmptyLinesAtTheStartOfBlocks: false 90 | LambdaBodyIndentation: Signature 91 | LineEnding: LF 92 | MacroBlockBegin: '' 93 | MacroBlockEnd: '' 94 | MaxEmptyLinesToKeep: 1 95 | NamespaceIndentation: None 96 | ObjCBlockIndentWidth: 2 97 | ObjCSpaceAfterProperty: false 98 | ObjCSpaceBeforeProtocolList: true 99 | PackConstructorInitializers: BinPack 100 | PenaltyBreakAssignment: 25 101 | PenaltyBreakBeforeFirstCallParameter: 50 102 | PenaltyBreakComment: 300 103 | PenaltyBreakFirstLessLess: 120 104 | PenaltyBreakString: 1000 105 | PenaltyBreakTemplateDeclaration: 10 106 | PenaltyExcessCharacter: 1000000 107 | PenaltyReturnTypeOnItsOwnLine: 150 108 | PenaltyIndentedWhitespace: 1 109 | PointerAlignment: Left 110 | QualifierAlignment: Left 111 | ReferenceAlignment: Left 112 | ReflowComments: true 113 | RequiresClausePosition: OwnLine 114 | RequiresExpressionIndentation: Keyword 115 | SortIncludes: CaseSensitive 116 | SortUsingDeclarations: true 117 | SpaceAfterCStyleCast: false 118 | SpaceAfterTemplateKeyword: true 119 | SpaceBeforeAssignmentOperators: true 120 | SpaceBeforeCpp11BracedList: false 121 | SpaceBeforeCtorInitializerColon: true 122 | SpaceBeforeInheritanceColon: true 123 | SpaceBeforeParens: ControlStatements 124 | SpaceBeforeRangeBasedForLoopColon: true 125 | SpaceInEmptyParentheses: false 126 | SpacesBeforeTrailingComments: 1 127 | SpacesInAngles: Never 128 | SpacesInContainerLiterals: true 129 | SpacesInCStyleCastParentheses: false 130 | SpacesInParentheses: false 131 | SpacesInSquareBrackets: false 132 | Standard: Latest 133 | TabWidth: 4 134 | UseTab: Never 135 | ... 136 | -------------------------------------------------------------------------------- /include/secureboot.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace fs = std::filesystem; 14 | 15 | namespace bios_config 16 | { 17 | static constexpr auto secureBootObjectPath = 18 | "/xyz/openbmc_project/bios_config/secure_boot"; 19 | static constexpr auto secureBootPersistFile = "securebootData"; 20 | 21 | using SecureBootBase = 22 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot; 23 | 24 | class SecureBoot : public SecureBootBase 25 | { 26 | public: 27 | SecureBoot() = delete; 28 | ~SecureBoot() = default; 29 | SecureBoot(const SecureBoot&) = delete; 30 | SecureBoot& operator=(const SecureBoot&) = delete; 31 | SecureBoot(SecureBoot&&) = delete; 32 | SecureBoot& operator=(SecureBoot&&) = delete; 33 | 34 | /** @brief Constructs SecureBoot object. 35 | * 36 | * @param[in] objectServer - object server 37 | * @param[in] systemBus - bus connection 38 | * @param[in] persistPath - path to the secureboot data file 39 | */ 40 | SecureBoot(sdbusplus::asio::object_server& objectServer, 41 | std::shared_ptr& systemBus, 42 | std::string persistPath); 43 | 44 | /** @brief Indicates the UEFI Secure Boot state during the current boot 45 | * cycle 46 | * 47 | * @param[in] value - Boot Type during the current cycle 48 | * 49 | * @return On success, return the CurrentBootType 50 | */ 51 | CurrentBootType currentBoot(CurrentBootType value) override; 52 | 53 | /** @brief Indicates whether the UEFI Secure Boot takes effect on next boot 54 | * 55 | * @param[in] value - new value for the attribute 56 | * 57 | * @return On succes, return the new attribute 58 | */ 59 | bool pendingEnable(bool value) override; 60 | 61 | /** @brief Indicates the current UEFI Secure Boot Mode 62 | * 63 | * @param[in] value - new value for the attribute 64 | * 65 | * @return On success, return the new attribute 66 | */ 67 | ModeType mode(ModeType value) override; 68 | 69 | private: 70 | sdbusplus::asio::object_server& objServer; 71 | std::shared_ptr& systemBus; 72 | std::filesystem::path secureBootFile; 73 | 74 | friend class cereal::access; 75 | 76 | /** @brief Save the SecureBoot object to the persistent storage 77 | * 78 | * @param[in] archive - archive 79 | * @param[in] version - version 80 | */ 81 | template 82 | void save(Archive& archive, const std::uint32_t version) const 83 | { 84 | // version is not used currently 85 | lg2::error("Save is called with version {VER}", "VER", version); 86 | archive(sdbusplus::xyz::openbmc_project::BIOSConfig::server:: 87 | SecureBoot::currentBoot(), 88 | sdbusplus::xyz::openbmc_project::BIOSConfig::server:: 89 | SecureBoot::pendingEnable(), 90 | sdbusplus::xyz::openbmc_project::BIOSConfig::server:: 91 | SecureBoot::mode()); 92 | } 93 | 94 | /** @brief Load the SecureBoot object from the persistent storage 95 | * 96 | * @param[in] archive - archive 97 | * @param[in] version - version 98 | */ 99 | template 100 | void load(Archive& archive, const std::uint32_t version) 101 | { 102 | (void)(version); 103 | SecureBoot::CurrentBootType currentBootValue = 104 | SecureBoot::CurrentBootType::Unknown; 105 | bool enableValue = false; 106 | SecureBoot::ModeType modeValue = SecureBoot::ModeType::Unknown; 107 | 108 | archive(currentBootValue, enableValue, modeValue); 109 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot:: 110 | currentBoot(currentBootValue, true); 111 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot:: 112 | pendingEnable(enableValue, true); 113 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot::mode( 114 | modeValue, true); 115 | } 116 | 117 | /** @brief Serialize the SecureBoot object to the persistent storage 118 | */ 119 | void serialize(); 120 | 121 | /** @brief Deserialize the SecureBoot object from the persistent storage 122 | * 123 | * @return On success, return true 124 | * @return On failure, return false 125 | */ 126 | bool deserialize(); 127 | }; 128 | } // namespace bios_config 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Remote BIOS Configuration 2 | 3 | [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) 4 | 5 | ## Overview 6 | 7 | The **biosconfig_manager** service enables users to view and modify the BIOS 8 | setup configuration parameters remotely through the Baseboard Management 9 | Controller (BMC) at any host state. Changes to these parameters will take effect 10 | upon the next system reboot or immediately, depending on the host firmware. 11 | 12 | For more details, please refer to [design document][rbmc-design-document]. 13 | 14 | ## Features 15 | 16 | - **Remote management** of BIOS settings. 17 | - **Immediate updates** or scheduled changes upon reboot. 18 | - **Reset BIOS Settings** support through the dbus. 19 | - **ChangePassword** support to change the BIOS setup password. 20 | 21 | ## RBC Manager Interface 22 | 23 | The Manager interface exposes methods and properties to Get & Set BIOS 24 | attributes via [dbus][pdi-manager-bios]. 25 | 26 | ### Service Name 27 | 28 | ```txt 29 | xyz.openbmc_project.BIOSConfigManager 30 | ``` 31 | 32 | ### Object Path 33 | 34 | ```txt 35 | /xyz/openbmc_project/bios_config/manager 36 | ``` 37 | 38 | ### Interface Name 39 | 40 | ```txt 41 | xyz.openbmc_project.BIOSConfig.Manager 42 | ``` 43 | 44 | ### Methods 45 | 46 | - **SetAttribute** Sets a specific BIOS attribute to a new value. 47 | - **GetAttribute** Retrieves the current and pending values of a BIOS attribute. 48 | 49 | ### Properties 50 | 51 | - **ResetBIOSSettings** To reset the BIOS settings based on the Reset Flag. 52 | - **BaseBIOSTable** Captures the entire BIOS table (collective information of 53 | all the BIOS attributes and their properties) 54 | 55 | ## Signature of `BaseBIOSTable` 56 | 57 | The `BaseBIOSTable` property in the RBC Manager Interface is a complex 58 | dictionary that defines the structure of BIOS attributes. Its type signature is 59 | as follows: 60 | 61 | ```plaintext 62 | dict[string, struct[ 63 | enum[self.AttributeType], 64 | boolean, 65 | string, 66 | string, 67 | string, 68 | variant[int64, string], 69 | variant[int64, string], 70 | array[struct[enum[self.BoundType], variant[int64, string], string]] 71 | ]] 72 | ``` 73 | 74 | This structure consists of: 75 | 76 | - **Attribute Name (string)**: The name of the BIOS attribute. 77 | - **Attribute Type (enum)**: The type of the BIOS attribute (e.g., String, 78 | Integer). 79 | - **Read-only Status (boolean)**: Whether the attribute is read-only. 80 | - **Display Name (string)**: The human-readable name of the attribute. 81 | - **Description (string)**: A description of what the attribute does. 82 | - **Menu Path (string)**: The BIOS menu path where this attribute can be found. 83 | - **Current Value (variant[int64, string])**: The current value of the 84 | attribute. 85 | - **Default Value (variant[int64, string])**: The default value of the 86 | attribute. 87 | - **Options (array of structs)**: The available options or bounds for this 88 | attribute. 89 | 90 | ### Examples 91 | 92 | Here is an example json structure of a `String` attribute with `attributeName` 93 | `DrdFreqLimit` & its various properties in BaseBIOSTable signature. 94 | 95 | ```json 96 | { 97 | "DdrFreqLimit": { 98 | "attributeType": "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String", 99 | "readonlyStatus": false, 100 | "displayname": "Memory Operating Speed Selection", 101 | "description": "Force specific Memory Operating Speed or use Auto setting.", 102 | "menuPath": "Advanced/Memory Configuration/Memory Operating Speed Selection", 103 | "current": "0x00", 104 | "default": "0x0B", 105 | "options": [ 106 | { "optionstring": "auto", "optionvalue": "enum0" }, 107 | { "optionstring": "2133", "optionvalue": "enum1" }, 108 | { "optionstring": "2400", "optionvalue": "enum2" }, 109 | { "optionstring": "2664", "optionvalue": "enum3" }, 110 | { "optionstring": "2933", "optionvalue": "enum4" } 111 | ] 112 | } 113 | } 114 | ``` 115 | 116 | Here is another example json structure of a `Integer` attribute with attribute 117 | with name `BIOSSerialDebugLevel` & its various properties in BaseBIOSTable 118 | signature. 119 | 120 | ```json 121 | { 122 | "BIOSSerialDebugLevel": { 123 | "attributeType": "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.Integer", 124 | "readonlyStatus": false, 125 | "displayname": "BIOS Serial Debug level", 126 | "description": "BIOS Serial Debug level during system boot.", 127 | "menuPath": "Advanced/Debug Feature Selection", 128 | "current": "0x00", 129 | "default": "0x01", 130 | "options": [ 131 | { "optionstring": "MinBound", "optionvalue": 0 }, 132 | { "optionstring": "MaxBound", "optionvalue": 4 }, 133 | { "optionstring": "ScalarIncrement", "optionvalue": 1 } 134 | ] 135 | } 136 | } 137 | ``` 138 | 139 | ## Initialization of `BaseBIOSTable` 140 | 141 | When the `bios-settings-mgr` daemon starts, it initializes with an empty 142 | `BaseBIOSTable`. It is the responsibility of provider daemons, such as **PLDM** 143 | or **IPMI**, to populate this table by fetching or defining the BIOS settings. 144 | These provider daemons are expected to gather the necessary BIOS attributes and 145 | values from their respective sources (ex: bmc, system firmware) and then 146 | initialize the `BaseBIOSTable` property with those settings. 147 | 148 | ### BIOS with PLDM as Communication Protocol 149 | 150 | For systems that use the **PLDM (Platform Level Data Model)** protocol between 151 | BMC & Host, OEM vendors can define their own BIOS attributes in the form of 152 | [JSON files][pldm-bios-json]. The PLDM daemon parses these files and initializes 153 | the `BaseBIOSTable` property accordingly. This allows for flexible and custom 154 | BIOS configuration options based on the vendor's specifications. 155 | 156 | For more details , refer to the [BIOS Support in PLDM][pldm-bios]. 157 | 158 | ### BIOS with IPMI as Communication Protocol 159 | 160 | For systems that use the **Intelligent Platform Management Interface** protocol 161 | between BMC & Host, BIOS attributes are gathered from BIOS as an `xml file` & 162 | `BaseBIOSTable` would then be initialized with the attributes data from the 163 | parsed xml file. 164 | 165 | For more details, refer to the code [BIOS Support in IPMI][ipmi-intel-bios]. 166 | 167 | ## RBC Password Interface 168 | 169 | ### Service Name 170 | 171 | ```txt 172 | xyz.openbmc_project.BIOSConfigManager 173 | ``` 174 | 175 | ### Object Path 176 | 177 | ```txt 178 | /xyz/openbmc_project/bios_config/password 179 | ``` 180 | 181 | ### Interface Name 182 | 183 | ```txt 184 | xyz.openbmc_project.BIOSConfig.Password 185 | ``` 186 | 187 | ### Methods 188 | 189 | - **ChangePassword** Used to change the BIOS setup password. 190 | 191 | ### Properties 192 | 193 | - **PasswordInitialized** Used to indicate whether the BIOS password-related 194 | details have been received. 195 | 196 | ## RBC SecureBoot Interface 197 | 198 | The SecureBoot interface exposes methods and properties to Get & Set UEFI 199 | SecureBoot settings via [dbus][pdi-secureboot-bios]. 200 | 201 | ### Object Path 202 | 203 | ```txt 204 | xyz.openbmc_project.BIOSConfig.SecureBoot 205 | ``` 206 | 207 | ### Properties 208 | 209 | - **CurrentBoot** Used to indicate UEFI Secure Boot state during current boot 210 | cycle 211 | - **PendingEnable** An indication of whether the UEFI Secure Boot takes effect 212 | on next boot 213 | - **Mode** The current UEFI Secure Boot Mode 214 | 215 | ### SecureBoot with Redfish Host Interface as Communication Protocol 216 | 217 | For systems that use the **Redfish Host Interface** protocol between BMC & Host, 218 | UEFI SecureBoot configuration is gathered by BMC via redfish. The settings are 219 | transformed to native dbus format and properties are set accordingly. 220 | 221 | [rbmc-design-document]: 222 | https://github.com/openbmc/docs/blob/master/designs/remote-bios-configuration.md 223 | [pldm-bios-json]: 224 | https://github.com/openbmc/pldm/blob/master/oem/ibm/configurations/bios/com.ibm.Hardware.Chassis.Model.Rainier2U/bios_attrs.json 225 | [pldm-bios]: https://github.com/openbmc/pldm?tab=readme-ov-file#bios-support 226 | [ipmi-intel-bios]: 227 | https://github.com/openbmc/intel-ipmi-oem/blob/master/src/biosconfigcommands.cpp 228 | [pdi-manager-bios]: 229 | https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/BIOSConfig/Manager.interface.yaml 230 | [pdi-secureboot-bios]: 231 | https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/BIOSConfig/SecureBoot.interface.yaml 232 | -------------------------------------------------------------------------------- /src/manager_serialize.cpp: -------------------------------------------------------------------------------- 1 | #include "manager_serialize.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace bios_config 18 | { 19 | 20 | // BIOS_CONFIG_VERSION is introduced to manage backward compatibility with 21 | // old BaseTableV1 where had not added the support version flag in the archived 22 | // data itself. To manage this the deserialize will try to decode with 23 | // BaseTableV1 when there is exception to read the version itself. If the 24 | // version in the archive is been read correctly then next version checks will 25 | // be handled. 26 | // BaseTable - Maps to Version 2 27 | // BaseTableV1 - Maps to version 1 28 | 29 | static std::uint32_t currentVersion = BIOS_CONFIG_VERSION; 30 | 31 | /** @brief Function required by Cereal to perform serialization. 32 | * 33 | * @tparam Archive - Cereal archive type (binary in this case). 34 | * @param[in] archive - reference to cereal archive. 35 | * @param[in] entry- const reference to bios manager object 36 | * @param[in] version - Class version that enables handling a serialized data 37 | * across code levels 38 | */ 39 | template 40 | void save(Archive& archive, const Manager& entry, 41 | const std::uint32_t /*version*/) 42 | { 43 | std::uint32_t version = BIOS_CONFIG_VERSION; 44 | archive(version); 45 | archive(entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager:: 46 | baseBIOSTable(), 47 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager:: 48 | pendingAttributes(), 49 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager:: 50 | enableAfterReset(), 51 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager:: 52 | credentialBootstrap()); 53 | archive(entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server:: 54 | BootOrder::bootOrder()); 55 | archive(entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server:: 56 | BootOrder::pendingBootOrder()); 57 | archive(entry.getBootOptionValues()); 58 | archive(entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server:: 59 | SecureBoot::currentBoot()); 60 | archive(entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server:: 61 | SecureBoot::pendingEnable()); 62 | archive(entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server:: 63 | SecureBoot::mode()); 64 | } 65 | 66 | /** @brief Function required by Cereal to perform deserialization. 67 | * 68 | * @tparam Archive - Cereal archive type (binary in our case). 69 | * @param[in] archive - reference to cereal archive. 70 | * @param[out] entry - reference to bios manager object 71 | * @param[in] version - Class version that enables handling a serialized data 72 | * across code levels 73 | */ 74 | template 75 | void load(Archive& archive, Manager& entry, const std::uint32_t /*version*/) 76 | { 77 | Manager::BaseTable baseTable; 78 | Manager::oldBaseTable baseTableV1; 79 | 80 | Manager::PendingAttributes pendingAttrs; 81 | bool enableAfterResetFlag; 82 | bool credentialBootstrapFlag; 83 | 84 | lg2::info("Load Bios Config Version: {VERSION}", "VERSION", currentVersion); 85 | if (currentVersion == BIOS_CONFIG_VERSION) 86 | { 87 | archive(currentVersion); 88 | archive(baseTable, pendingAttrs, enableAfterResetFlag, 89 | credentialBootstrapFlag); 90 | } 91 | else if (currentVersion == BIOS_CONFIG_VERSION_2) 92 | { 93 | archive(currentVersion); 94 | archive(baseTable, pendingAttrs, enableAfterResetFlag); 95 | credentialBootstrapFlag = true; 96 | } 97 | else 98 | { 99 | archive(baseTableV1, pendingAttrs, enableAfterResetFlag); 100 | entry.convertBiosDataToVersion1(baseTableV1, baseTable); 101 | credentialBootstrapFlag = true; 102 | } 103 | 104 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager:: 105 | baseBIOSTable(baseTable, true); 106 | 107 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager:: 108 | pendingAttributes(pendingAttrs, true); 109 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager:: 110 | enableAfterReset(enableAfterResetFlag, true); 111 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager:: 112 | credentialBootstrap(credentialBootstrapFlag, true); 113 | 114 | Manager::BootOrderType bootOrderValue; 115 | archive(bootOrderValue); 116 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::BootOrder:: 117 | bootOrder(bootOrderValue, true); 118 | 119 | Manager::BootOrderType pendingBootOrderValue; 120 | archive(pendingBootOrderValue); 121 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::BootOrder:: 122 | pendingBootOrder(pendingBootOrderValue, true); 123 | 124 | Manager::BootOptionsType bootOptionsValues; 125 | archive(bootOptionsValues); 126 | entry.setBootOptionValues(bootOptionsValues); 127 | 128 | Manager::CurrentBootType currentBootValue; 129 | archive(currentBootValue); 130 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot:: 131 | currentBoot(currentBootValue, true); 132 | 133 | bool enableValue; 134 | archive(enableValue); 135 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot:: 136 | pendingEnable(enableValue, true); 137 | 138 | Manager::ModeType modeValue; 139 | archive(modeValue); 140 | entry.sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot::mode( 141 | modeValue, true); 142 | } 143 | 144 | void serialize(const Manager& obj, const fs::path& path) 145 | { 146 | try 147 | { 148 | std::ofstream os(path, std::ios::out | std::ios::binary); 149 | 150 | if (!os.is_open()) 151 | { 152 | lg2::error("Failed to open file for serialization: {FILE}", "FILE", 153 | path); 154 | return; 155 | } 156 | 157 | cereal::BinaryOutputArchive oarchive(os); 158 | oarchive(obj); 159 | } 160 | catch (const std::exception& e) 161 | { 162 | lg2::error("Failed to Serialize : {ERROR} ", "ERROR", e); 163 | } 164 | } 165 | 166 | bool deserialize(const fs::path& path, Manager& entry) 167 | { 168 | try 169 | { 170 | if (fs::exists(path)) 171 | { 172 | try 173 | { 174 | std::ifstream is(path.c_str(), std::ios::in | std::ios::binary); 175 | if (!is.is_open()) 176 | { 177 | lg2::error( 178 | "Failed to open file for deserialization: {FILE}", 179 | "FILE", path); 180 | return false; 181 | } 182 | cereal::BinaryInputArchive iarchive(is); 183 | iarchive(entry); 184 | } 185 | catch (...) 186 | { 187 | try 188 | { 189 | lg2::error("Trying with old Bios Config Version: {VERSION}", 190 | "VERSION", 2); 191 | std::ifstream is(path.c_str(), 192 | std::ios::in | std::ios::binary); 193 | cereal::BinaryInputArchive iarchive(is); 194 | currentVersion = BIOS_CONFIG_VERSION_2; 195 | iarchive(entry); 196 | } 197 | catch (...) 198 | { 199 | lg2::error("Trying with old Bios Config Version: {VERSION}", 200 | "VERSION", 1); 201 | std::ifstream is(path.c_str(), 202 | std::ios::in | std::ios::binary); 203 | cereal::BinaryInputArchive iarchive(is); 204 | currentVersion = BIOS_CONFIG_VERSION_1; 205 | iarchive(entry); 206 | } 207 | } 208 | return true; 209 | } 210 | return false; 211 | } 212 | catch (cereal::Exception& e) 213 | { 214 | lg2::error("Cereal failed to serialize: {ERROR}", "ERROR", e); 215 | fs::remove(path); 216 | return false; 217 | } 218 | catch (const std::exception& e) 219 | { 220 | lg2::error("Failed to serialize: {ERROR}", "ERROR", e); 221 | fs::remove(path); 222 | return false; 223 | } 224 | } 225 | 226 | } // namespace bios_config 227 | -------------------------------------------------------------------------------- /src/password.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Intel Corporation 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http:www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | #include "password.hpp" 17 | 18 | #include "config.hpp" 19 | #include "rfutility.hpp" 20 | #include "xyz/openbmc_project/BIOSConfig/Common/error.hpp" 21 | #include "xyz/openbmc_project/Common/error.hpp" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | namespace bios_config_pwd 34 | { 35 | using namespace sdbusplus::xyz::openbmc_project::Common::Error; 36 | using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error; 37 | 38 | bool Password::compareDigest(const EVP_MD* digestFunc, size_t digestLen, 39 | const std::array& expected, 40 | const std::array& seed, 41 | const std::string& rawData) 42 | { 43 | std::vector output(digestLen); 44 | unsigned int hashLen = digestLen; 45 | 46 | if (!PKCS5_PBKDF2_HMAC(reinterpret_cast(rawData.c_str()), 47 | rawData.length() + 1, 48 | reinterpret_cast(seed.data()), 49 | seed.size(), iterValue, digestFunc, hashLen, 50 | output.data())) 51 | { 52 | lg2::error("Generate PKCS5_PBKDF2_HMAC Integrity Check Value failed"); 53 | throw InternalFailure(); 54 | } 55 | 56 | if (std::memcmp(output.data(), expected.data(), 57 | output.size() * sizeof(uint8_t)) == 0) 58 | { 59 | return true; 60 | } 61 | 62 | return false; 63 | } 64 | 65 | bool Password::isMatch(const std::array& expected, 66 | const std::array& seed, 67 | const std::string& rawData, const std::string& algo) 68 | { 69 | lg2::error("isMatch"); 70 | 71 | if (algo == "SHA256") 72 | { 73 | return compareDigest(EVP_sha256(), SHA256_DIGEST_LENGTH, expected, seed, 74 | rawData); 75 | } 76 | 77 | if (algo == "SHA384") 78 | { 79 | return compareDigest(EVP_sha384(), SHA384_DIGEST_LENGTH, expected, seed, 80 | rawData); 81 | } 82 | 83 | return false; 84 | } 85 | 86 | bool Password::getParam(std::array& orgUsrPwdHash, 87 | std::array& orgAdminPwdHash, 88 | std::array& seed, 89 | std::string& hashAlgo) 90 | { 91 | try 92 | { 93 | nlohmann::json json = nullptr; 94 | std::ifstream ifs(seedFile.c_str()); 95 | if (ifs.is_open()) 96 | { 97 | try 98 | { 99 | json = nlohmann::json::parse(ifs, nullptr, false); 100 | } 101 | catch (const nlohmann::json::parse_error& e) 102 | { 103 | lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e); 104 | return false; 105 | } 106 | 107 | if (!json.is_discarded()) 108 | { 109 | orgUsrPwdHash = json["UserPwdHash"]; 110 | orgAdminPwdHash = json["AdminPwdHash"]; 111 | seed = json["Seed"]; 112 | hashAlgo = json["HashAlgo"]; 113 | } 114 | } 115 | } 116 | catch (nlohmann::detail::exception& e) 117 | { 118 | lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e); 119 | return false; 120 | } 121 | 122 | return true; 123 | } 124 | 125 | bool Password::verifyIntegrityCheck( 126 | std::string& newPassword, std::array& seed, 127 | unsigned int mdLen, const EVP_MD* digestFunc) 128 | { 129 | mNewPwdHash.fill(0); 130 | 131 | if (!PKCS5_PBKDF2_HMAC(reinterpret_cast(newPassword.c_str()), 132 | newPassword.length() + 1, 133 | reinterpret_cast(seed.data()), 134 | seed.size(), iterValue, digestFunc, mdLen, 135 | mNewPwdHash.data())) 136 | { 137 | lg2::error("Verify PKCS5_PBKDF2_HMAC Integrity Check failed"); 138 | return false; 139 | } 140 | 141 | return true; 142 | } 143 | 144 | void Password::verifyPassword(std::string userName, std::string currentPassword, 145 | std::string newPassword) 146 | { 147 | if (fs::exists(seedFile.c_str())) 148 | { 149 | std::array orgUsrPwdHash; 150 | std::array orgAdminPwdHash; 151 | std::array seed; 152 | std::string hashAlgo = ""; 153 | 154 | if (getParam(orgUsrPwdHash, orgAdminPwdHash, seed, hashAlgo)) 155 | { 156 | if (orgUsrPwdHash.empty() || orgAdminPwdHash.empty() || 157 | seed.empty() || hashAlgo.empty()) 158 | { 159 | return; 160 | } 161 | } 162 | else 163 | { 164 | throw InternalFailure(); 165 | } 166 | 167 | if (userName == "AdminPassword") 168 | { 169 | if (!isMatch(orgAdminPwdHash, seed, currentPassword, hashAlgo)) 170 | { 171 | throw InvalidCurrentPassword(); 172 | } 173 | } 174 | else 175 | { 176 | if (!isMatch(orgUsrPwdHash, seed, currentPassword, hashAlgo)) 177 | { 178 | throw InvalidCurrentPassword(); 179 | } 180 | } 181 | if (hashAlgo == "SHA256") 182 | { 183 | if (!verifyIntegrityCheck(newPassword, seed, 32, EVP_sha256())) 184 | { 185 | throw InternalFailure(); 186 | } 187 | } 188 | if (hashAlgo == "SHA384") 189 | { 190 | if (!verifyIntegrityCheck(newPassword, seed, 48, EVP_sha384())) 191 | { 192 | throw InternalFailure(); 193 | } 194 | } 195 | return; 196 | } 197 | throw InternalFailure(); 198 | } 199 | void Password::changePassword(std::string userName, std::string currentPassword, 200 | std::string newPassword) 201 | { 202 | lg2::debug("BIOS config changePassword"); 203 | verifyPassword(userName, currentPassword, newPassword); 204 | 205 | std::ifstream fs(seedFile.c_str()); 206 | nlohmann::json json = nullptr; 207 | 208 | if (fs.is_open()) 209 | { 210 | try 211 | { 212 | json = nlohmann::json::parse(fs, nullptr, false); 213 | } 214 | catch (const nlohmann::json::parse_error& e) 215 | { 216 | lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e); 217 | throw InternalFailure(); 218 | } 219 | 220 | if (json.is_discarded()) 221 | { 222 | throw InternalFailure(); 223 | } 224 | json["AdminPwdHash"] = mNewPwdHash; 225 | json["IsAdminPwdChanged"] = true; 226 | 227 | std::ofstream ofs(seedFile.c_str(), std::ios::out); 228 | const auto& writeData = json.dump(); 229 | ofs << writeData; 230 | ofs.close(); 231 | // send redfish event 232 | bios_config::sendRedfishEvent("BiosPassword", "****", objectPathPwd); 233 | } 234 | else 235 | { 236 | lg2::debug("Cannot open file stream"); 237 | throw InternalFailure(); 238 | } 239 | } 240 | Password::Password(sdbusplus::asio::object_server& objectServer, 241 | std::shared_ptr& systemBus, 242 | std::string persistPath) : 243 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::Password( 244 | *systemBus, objectPathPwd), 245 | objServer(objectServer), systemBus(systemBus) 246 | { 247 | lg2::debug("BIOS config password is running"); 248 | try 249 | { 250 | fs::path biosDir(persistPath); 251 | fs::create_directories(biosDir); 252 | seedFile = biosDir / biosSeedFile; 253 | } 254 | catch (const fs::filesystem_error& e) 255 | { 256 | lg2::error("Failed to parse JSON file: {ERROR}", "ERROR", e); 257 | throw InternalFailure(); 258 | } 259 | } 260 | 261 | } // namespace bios_config_pwd 262 | -------------------------------------------------------------------------------- /include/manager.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Intel Corporation 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http:www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "boot_option.hpp" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #define BIOS_CONFIG_VERSION_1 1 31 | // Version 1: Bios table type 1 32 | #define BIOS_CONFIG_VERSION_2 2 33 | // Version 2: Bios table type 2 + version + 34 | // pendingBootEnable - The type remain map of variant (bool and string), but 35 | // additional bool was added. Version 3: Bios table type 2 + version + 36 | // credentialBootstrapFlag 37 | #define BIOS_CONFIG_VERSION 3 38 | 39 | namespace bios_config 40 | { 41 | 42 | static constexpr auto service = "xyz.openbmc_project.BIOSConfigManager"; 43 | static constexpr auto objectPath = "/xyz/openbmc_project/bios_config/manager"; 44 | constexpr auto biosPersistFile = "biosData"; 45 | static constexpr auto bootOptionsPath = 46 | "/xyz/openbmc_project/bios_config/bootOptions"; 47 | using Base = sdbusplus::server::object_t< 48 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::Manager, 49 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::BootOrder, 50 | sdbusplus::xyz::openbmc_project::BIOSConfig::server::SecureBoot>; 51 | namespace fs = std::filesystem; 52 | 53 | /** @class Manager 54 | * 55 | * @brief Implements the BIOS Manager 56 | */ 57 | class Manager : public Base 58 | { 59 | public: 60 | using BaseTable = std::map< 61 | std::string, 62 | std::tuple< 63 | AttributeType, bool, std::string, std::string, std::string, 64 | std::variant, 65 | std::variant, 66 | std::vector, std::string>>>>; 68 | 69 | using oldBaseTable = std::map< 70 | std::string, 71 | std::tuple, 73 | std::variant, 74 | std::vector>>>>; 76 | 77 | using PendingAttributes = 78 | std::map>>; 80 | 81 | using PendingAttribute = 82 | std::tuple>; 83 | 84 | using AttributeName = std::string; 85 | using AttributeValue = std::variant; 86 | using CurrentValue = std::variant; 87 | using PendingValue = std::variant; 88 | using AttributeDetails = 89 | std::tuple; 90 | using BootOrderType = std::vector; 91 | using BootOptionDataType = 92 | std::map; 93 | using BootOptionsType = std::map; 94 | 95 | Manager() = delete; 96 | ~Manager() = default; 97 | Manager(const Manager&) = delete; 98 | Manager& operator=(const Manager&) = delete; 99 | Manager(Manager&&) = delete; 100 | Manager& operator=(Manager&&) = delete; 101 | 102 | /** @brief Constructs Manager object. 103 | * 104 | * @param[in] objectServer - object server 105 | * @param[in] systemBus - bus connection 106 | */ 107 | Manager(sdbusplus::asio::object_server& objectServer, 108 | std::shared_ptr& systemBus, 109 | std::string persistPath); 110 | 111 | /** @brief Set the BIOS attribute with a new value, the new value is added 112 | * to the PendingAttribute. 113 | * 114 | * @param[in] attribute - attribute name 115 | * @param[in] value - new value for the attribute 116 | * 117 | * @return On error, throw exception 118 | */ 119 | void setAttribute(AttributeName attribute, AttributeValue value) override; 120 | 121 | /** @brief Get the details of the BIOS attribute 122 | * 123 | * @param[in] attribute - attribute name 124 | * 125 | * @return On success, return the attribute details: attribute type, 126 | * current value, pending value. On error, throw exception 127 | */ 128 | AttributeDetails getAttribute(AttributeName attribute) override; 129 | 130 | /** @brief Set the BaseBIOSTable property and clears the PendingAttributes 131 | * property 132 | * 133 | * @param[in] value - new BaseBIOSTable 134 | * 135 | * @return The new BaseBIOSTable that is applied. 136 | */ 137 | BaseTable baseBIOSTable(BaseTable value) override; 138 | 139 | bool enableAfterReset(bool value) override; 140 | 141 | bool credentialBootstrap(bool value) override; 142 | 143 | ResetFlag resetBIOSSettings(ResetFlag value) override; 144 | 145 | /** @brief Set the PendingAttributes property, additionally checks if the 146 | * attributes are in the BaseBIOSTable, whether the attributes are 147 | * read only and validate the attribute value based on the 148 | * attribute type. PendingAttributes is cleared if value is empty. 149 | * 150 | * @param[in] value - new PendingAttributes to append to the 151 | * PendingAttributes property 152 | * 153 | * @return On success, return the new PendingAttributes property that is 154 | * set.Throw exception if the validation fails. 155 | */ 156 | PendingAttributes pendingAttributes(PendingAttributes value) override; 157 | 158 | /** @brief Implementation for CreateBootOption To create a new DBus object 159 | * with BootOption DBus interface and using the Id as the object name. 160 | * 161 | * @param[in] id - The unique boot option ID. 162 | * 163 | * @return On error, throw exception 164 | */ 165 | void createBootOption(std::string id) override; 166 | 167 | void deleteBootOption(const std::string& key); 168 | BootOptionsType getBootOptionValues() const; 169 | void setBootOptionValues(const BootOptionsType& loaded); 170 | 171 | /** @brief Set the BootOrder property, additionally set it to the 172 | * PendingBootOrder property. The PendingBootOrder is the future settings 173 | * of BootOrder, reset PendingBootOrder as BootOrder when the BootOrder is 174 | * updated. 175 | * 176 | * @param[in] value - new BootOrder value 177 | * 178 | * @return On success, return the new BootOrder 179 | */ 180 | BootOrderType bootOrder(BootOrderType value) override; 181 | 182 | /** @brief serialize to file after changing value 183 | * 184 | * @param[in] value - new value 185 | * 186 | * @return On success, return the new value 187 | */ 188 | BootOrderType pendingBootOrder(BootOrderType value) override; 189 | CurrentBootType currentBoot(CurrentBootType value) override; 190 | bool pendingEnable(bool value) override; 191 | ModeType mode(ModeType value) override; 192 | 193 | friend class BootOptionDbus; 194 | 195 | /** @brief Convert the previosuly supported Base BIOS table to newly 196 | * supported Base BIOS table 197 | * 198 | * @param[in] biosTbl - Old Base BIOS table (without VDN) 199 | * @param[in] baseTable - Recently supported Base BIOS table (with VDN) 200 | * 201 | * @return void 202 | * 203 | */ 204 | void convertBiosDataToVersion1(Manager::oldBaseTable biosTbl, 205 | Manager::BaseTable& baseTable); 206 | 207 | /** @brief Convert the VDN supported Base BIOS table to old Base BIOS table 208 | * 209 | * @param[in] biosTbl - Old Base BIOS table (without VDN) 210 | * @param[in] baseTable - Recently supported Base BIOS table (with VDN) 211 | * 212 | * @return void 213 | */ 214 | void convertBiosDataToVersion0(Manager::oldBaseTable& baseTable, 215 | Manager::BaseTable& biosTbl); 216 | 217 | private: 218 | /** @enum Index into the fields in the BaseBIOSTable 219 | */ 220 | enum class Index : uint8_t 221 | { 222 | attributeType = 0, 223 | readOnly, 224 | displayName, 225 | description, 226 | menuPath, 227 | currentValue, 228 | defaultValue, 229 | options, 230 | }; 231 | 232 | bool validateEnumOption( 233 | const std::string& attrValue, 234 | const std::vector, std::string>>& 236 | options); 237 | 238 | bool validateStringOption( 239 | const std::string& attrValue, 240 | const std::vector, std::string>>& 242 | options); 243 | 244 | bool validateIntegerOption( 245 | const int64_t& attrValue, 246 | const std::vector, std::string>>& 248 | options); 249 | 250 | sdbusplus::asio::object_server& objServer; 251 | std::shared_ptr& systemBus; 252 | std::filesystem::path biosFile; 253 | BootOptionsType bootOptionValues; 254 | std::map> dbusBootOptions; 255 | }; 256 | 257 | } // namespace bios_config 258 | -------------------------------------------------------------------------------- /src/bootvalidflag.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. 3 | * All rights reserved. SPDX-License-Identifier: Apache-2.0 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #include "bootvalidflag.hpp" 18 | 19 | constexpr auto settingService = "xyz.openbmc_project.Settings"; 20 | constexpr auto bootSettingsPath = "/xyz/openbmc_project/control/host0/boot"; 21 | constexpr auto bootEnableIntf = "xyz.openbmc_project.Object.Enable"; 22 | constexpr auto bootFlagTimeoutDisIntf = 23 | "xyz.openbmc_project.Control.Boot.BootSettingsExpiryOverride"; 24 | constexpr auto bootSettingsOneTimePath = 25 | "/xyz/openbmc_project/control/host0/boot/one_time"; 26 | constexpr auto propIntf = "org.freedesktop.DBus.Properties"; 27 | constexpr auto methodeGet = "Get"; 28 | constexpr auto methodSet = "Set"; 29 | constexpr auto enalbeProperty = "Enabled"; 30 | constexpr auto bootFlagTimeoutDisProperty = "BootValidTimeoutOverride"; 31 | 32 | constexpr auto TIMER_TIME = 60; 33 | 34 | namespace bios_config_valid 35 | { 36 | 37 | void BootValidFlag::setDbusProperty( 38 | const std::string& service, const std::string& objPath, 39 | const std::string& interface, const std::string& property, 40 | bios_config_valid::Value& value) 41 | { 42 | dbusConnectionPtr->async_method_call( 43 | [property, objPath, interface](boost::system::error_code ec) { 44 | if (ec) 45 | { 46 | lg2::error( 47 | "Failed to set property {PROPERTY} on {PATH} for interface {INTERFACE} ERROR: {ERROR}", 48 | "PROPERTY", property, "PATH", objPath, "INTERFACE", 49 | interface, "ERROR", ec.what()); 50 | return; 51 | } 52 | }, 53 | service, objPath, propIntf, methodSet, interface, property, value); 54 | } 55 | 56 | void BootValidFlag::setBootValidFlag() 57 | { 58 | // check if persistentFlag Flag is set, 59 | dbusConnectionPtr->async_method_call( 60 | [this](boost::system::error_code ec, sdbusplus::message_t reply) { 61 | if (ec) 62 | { 63 | lg2::error( 64 | "Failed to get property {PROPERTY} on {PATH} for interface {INTERFACE} ERROR: {ERROR}", 65 | "PROPERTY", enalbeProperty, "PATH", bootSettingsOneTimePath, 66 | "INTERFACE", bootEnableIntf, "ERROR", ec.what()); 67 | return; 68 | } 69 | bios_config_valid::Value value; 70 | reply.read(value); 71 | // persistentFlag value is inverted to one_time property value 72 | bool persistentFlag = !std::get(value); 73 | if (!persistentFlag) 74 | { 75 | // check if bootFlagTimeoutDis Flag is set, 76 | this->dbusConnectionPtr->async_method_call( 77 | [this](boost::system::error_code ec, 78 | sdbusplus::message_t reply) { 79 | if (ec) 80 | { 81 | lg2::error( 82 | "Failed to get property {PROPERTY} on {PATH} for interface {INTERFACE} ERROR: {ERROR}", 83 | "PROPERTY", bootFlagTimeoutDisProperty, "PATH", 84 | bootSettingsPath, "INTERFACE", 85 | bootFlagTimeoutDisIntf, "ERROR", ec.what()); 86 | return; 87 | } 88 | bios_config_valid::Value value; 89 | reply.read(value); 90 | bool bootFlagTimeoutDis = std::get(value); 91 | if (!bootFlagTimeoutDis) 92 | { 93 | // If both the Persistent Flag and Timeout Override 94 | // Disable Flags are not set, then set the Boot 95 | // Valid Flag value to false. 96 | bool setToFalse = false; 97 | bios_config_valid::Value var(setToFalse); 98 | this->setDbusProperty( 99 | settingService, bootSettingsPath, 100 | bootEnableIntf, enalbeProperty, var); 101 | } 102 | }, 103 | settingService, bootSettingsPath, propIntf, methodeGet, 104 | bootFlagTimeoutDisIntf, bootFlagTimeoutDisProperty); 105 | } 106 | }, 107 | settingService, bootSettingsOneTimePath, propIntf, methodeGet, 108 | bootEnableIntf, enalbeProperty); 109 | return; 110 | } 111 | 112 | void BootValidFlag::cancelTimer(sdbusplus::message::message& msg) 113 | { 114 | std::string interfaceName; 115 | std::map> changedProperties; 116 | std::vector invalidatedProperties; 117 | msg.read(interfaceName, changedProperties, invalidatedProperties); 118 | // Verify if the property has been set to false, and if so, cancel the 119 | // timer. 120 | lg2::info("Check if need to cancel timer"); 121 | for (const auto& [property, value] : changedProperties) 122 | { 123 | if (property == "BootProgressLastUpdate") 124 | { 125 | if (timer_60->expiry() > std::chrono::steady_clock::now()) 126 | { 127 | lg2::info("Timer is active, so cancel it"); 128 | // Timer is active, so cancel it 129 | timer_60->cancel(); 130 | } 131 | return; 132 | } 133 | } 134 | } 135 | 136 | void BootValidFlag::setTimer(sdbusplus::message::message& msg) 137 | { 138 | std::string interfaceName; 139 | std::map> changedProperties; 140 | std::vector invalidatedProperties; 141 | msg.read(interfaceName, changedProperties, invalidatedProperties); 142 | // Verify if the property has been set to false, and if so, cancel the 143 | // timer. 144 | for (const auto& [property, value] : changedProperties) 145 | { 146 | if (property == bootFlagTimeoutDisProperty) 147 | { 148 | bool bootValidFlagValue = std::get(value); 149 | // if BootValidTimeoutOverride is true, the timer should be ignored 150 | // else start the timer 151 | if (bootValidFlagValue) 152 | { 153 | lg2::info( 154 | "BootValidTimeoutOverride is true, exit without setting timer"); 155 | return; 156 | } 157 | } 158 | else if (property == enalbeProperty) 159 | { 160 | bool bootValidFlagValue = std::get(value); 161 | if (!bootValidFlagValue) 162 | { 163 | lg2::info("enabled is false, exit without setting timer"); 164 | return; 165 | } 166 | } 167 | } 168 | lg2::info("Starting boot valid flag timer"); 169 | 170 | // Set new expiry time and start new asynchronous wait for 60 sec. 171 | timer_60->expires_after(std::chrono::seconds(TIMER_TIME)); 172 | timer_60->async_wait([this](const boost::system::error_code& error) { 173 | if (!error) 174 | { 175 | lg2::info("Timer expired, setting boot valid flag"); 176 | this->setBootValidFlag(); 177 | } 178 | else 179 | { 180 | lg2::error("Timer error: {ERROR}", "ERROR", error.message()); 181 | } 182 | }); 183 | } 184 | 185 | void BootValidFlag::setupMatches(sdbusplus::bus_t& dbusConnection) 186 | { 187 | validUpdatedMatch = std::make_unique( 188 | dbusConnection, 189 | sdbusplus::bus::match::rules::type::signal() + 190 | sdbusplus::bus::match::rules::member( 191 | std::string{"PropertiesChanged"}) + 192 | sdbusplus::bus::match::rules::interface( 193 | std::string{"org.freedesktop.DBus.Properties"}) + 194 | sdbusplus::bus::match::rules::argN(0, bootEnableIntf) + 195 | sdbusplus::bus::match::rules::path( 196 | std::string{"/xyz/openbmc_project/control/host0/boot"}), 197 | [this](sdbusplus::message::message& msg) { this->setTimer(msg); }); 198 | 199 | lg2::info("Setting up soft reset match"); 200 | softResetMatch = std::make_unique( 201 | dbusConnection, 202 | sdbusplus::bus::match::rules::type::signal() + 203 | sdbusplus::bus::match::rules::member( 204 | std::string{"PropertiesChanged"}) + 205 | sdbusplus::bus::match::rules::interface( 206 | std::string{"org.freedesktop.DBus.Properties"}) + 207 | sdbusplus::bus::match::rules::argN( 208 | 0, "xyz.openbmc_project.State.Boot.Progress") + 209 | sdbusplus::bus::match::rules::path( 210 | std::string{"/xyz/openbmc_project/state/host0"}), 211 | [this](sdbusplus::message::message& msg) { this->cancelTimer(msg); }); 212 | } 213 | 214 | BootValidFlag::BootValidFlag( 215 | std::shared_ptr systemBusPtr, 216 | boost::asio::io_context& io) 217 | { 218 | dbusConnectionPtr = systemBusPtr; 219 | // Verify if the BootValidTimeoutOverride property exists in the BMC. 220 | // If it does, create a change on the property signal match and 221 | // restart the boot valid flag. 222 | // If it does not exist, take no action. 223 | dbusConnectionPtr->async_method_call( 224 | [this, &io](boost::system::error_code ec) { 225 | if (ec) 226 | { 227 | lg2::info( 228 | "Failed to find BootValidTimeoutOverride property boot valid flag won't reset after 60 seconds.ERROR: {ERROR}", 229 | "ERROR", ec.what()); 230 | return; 231 | } 232 | timer_60 = std::make_unique(io); 233 | this->setBootValidFlag(); 234 | this->setupMatches(*dbusConnectionPtr); 235 | }, 236 | settingService, bootSettingsPath, propIntf, methodeGet, 237 | bootFlagTimeoutDisIntf, bootFlagTimeoutDisProperty); 238 | } 239 | } // namespace bios_config_valid 240 | -------------------------------------------------------------------------------- /src/manager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Intel Corporation 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http:www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include "manager.hpp" 18 | 19 | #include "manager_serialize.hpp" 20 | #include "rfutility.hpp" 21 | #include "xyz/openbmc_project/BIOSConfig/Common/error.hpp" 22 | #include "xyz/openbmc_project/Common/error.hpp" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | namespace bios_config 33 | { 34 | 35 | using namespace sdbusplus::xyz::openbmc_project::Common::Error; 36 | using namespace sdbusplus::xyz::openbmc_project::BIOSConfig::Common::Error; 37 | 38 | void Manager::setAttribute(AttributeName attribute, AttributeValue value) 39 | { 40 | auto pendingAttrs = Base::pendingAttributes(); 41 | auto iter = pendingAttrs.find(attribute); 42 | 43 | if (iter != pendingAttrs.end()) 44 | { 45 | std::get<1>(iter->second) = value; 46 | } 47 | else 48 | { 49 | Manager::PendingAttribute attributeValue; 50 | 51 | if (std::get_if(&value)) 52 | { 53 | std::get<0>(attributeValue) = AttributeType::Integer; 54 | } 55 | else 56 | { 57 | std::get<0>(attributeValue) = AttributeType::String; 58 | } 59 | 60 | std::get<1>(attributeValue) = value; 61 | pendingAttrs.emplace(attribute, attributeValue); 62 | } 63 | 64 | pendingAttributes(pendingAttrs); 65 | } 66 | 67 | Manager::AttributeDetails Manager::getAttribute(AttributeName attribute) 68 | { 69 | Manager::AttributeDetails value; 70 | 71 | auto table = Base::baseBIOSTable(); 72 | auto iter = table.find(attribute); 73 | 74 | if (iter != table.end()) 75 | { 76 | std::get<0>(value) = 77 | std::get(Index::attributeType)>(iter->second); 78 | std::get<1>(value) = 79 | std::get(Index::currentValue)>(iter->second); 80 | 81 | auto pending = Base::pendingAttributes(); 82 | auto pendingIter = pending.find(attribute); 83 | if (pendingIter != pending.end()) 84 | { 85 | std::get<2>(value) = std::get<1>(pendingIter->second); 86 | } 87 | else if (std::get_if(&std::get<1>(value))) 88 | { 89 | std::get<2>(value) = std::string(); 90 | } 91 | } 92 | else 93 | { 94 | throw AttributeNotFound(); 95 | } 96 | 97 | return value; 98 | } 99 | 100 | Manager::BaseTable Manager::baseBIOSTable(BaseTable value) 101 | { 102 | pendingAttributes({}); 103 | auto baseTable = Base::baseBIOSTable(value, false); 104 | serialize(*this, biosFile); 105 | Base::resetBIOSSettings(Base::ResetFlag::NoAction); 106 | return baseTable; 107 | } 108 | 109 | bool Manager::enableAfterReset(bool value) 110 | { 111 | auto enableAfterResetFlag = Base::enableAfterReset(value, false); 112 | serialize(*this, biosFile); 113 | return enableAfterResetFlag; 114 | } 115 | 116 | bool Manager::credentialBootstrap(bool value) 117 | { 118 | auto credentialBootstrapFlag = Base::credentialBootstrap(value, false); 119 | serialize(*this, biosFile); 120 | return credentialBootstrapFlag; 121 | } 122 | 123 | Manager::ResetFlag Manager::resetBIOSSettings(Manager::ResetFlag value) 124 | { 125 | auto resetFlag = Base::resetBIOSSettings(value, false); 126 | serialize(*this, biosFile); 127 | 128 | // Below block of code is to send event when ResetBIOSSettings property is 129 | // modified. 130 | std::string resetFlagString = convertResetFlagToString(resetFlag); 131 | std::string path = objectPath; 132 | path += "/bios/settings"; 133 | parsePropertyValueAndSendEvent("ResetBIOSSettings", resetFlagString, path); 134 | return resetFlag; 135 | } 136 | 137 | bool Manager::validateEnumOption( 138 | const std::string& attrValue, 139 | const std::vector, 140 | std::string>>& options) 141 | { 142 | for (const auto& enumOptions : options) 143 | { 144 | if ((BoundType::OneOf == std::get<0>(enumOptions)) && 145 | (attrValue == std::get(std::get<1>(enumOptions)))) 146 | { 147 | return true; 148 | } 149 | } 150 | 151 | lg2::error("No valid attribute"); 152 | return false; 153 | } 154 | 155 | bool Manager::validateStringOption( 156 | const std::string& attrValue, 157 | const std::vector, 158 | std::string>>& options) 159 | { 160 | size_t minStringLength = 0; 161 | size_t maxStringLength = 0; 162 | for (const auto& stringOptions : options) 163 | { 164 | if (BoundType::MinStringLength == std::get<0>(stringOptions)) 165 | { 166 | minStringLength = std::get(std::get<1>(stringOptions)); 167 | } 168 | else if (BoundType::MaxStringLength == std::get<0>(stringOptions)) 169 | { 170 | maxStringLength = std::get(std::get<1>(stringOptions)); 171 | } 172 | else 173 | { 174 | continue; 175 | } 176 | } 177 | 178 | if (attrValue.length() < minStringLength || 179 | attrValue.length() > maxStringLength) 180 | { 181 | lg2::error( 182 | "{ATTRVALUE} Length is out of range, bound is invalid, maxStringLength = {MAXLEN}, minStringLength = {MINLEN}", 183 | "ATTRVALUE", attrValue, "MAXLEN", maxStringLength, "MINLEN", 184 | minStringLength); 185 | return false; 186 | } 187 | 188 | return true; 189 | } 190 | 191 | bool Manager::validateIntegerOption( 192 | const int64_t& attrValue, 193 | const std::vector, 194 | std::string>>& options) 195 | { 196 | int64_t lowerBound = 0; 197 | int64_t upperBound = 0; 198 | int64_t scalarIncrement = 0; 199 | 200 | for (const auto& integerOptions : options) 201 | { 202 | if (BoundType::LowerBound == std::get<0>(integerOptions)) 203 | { 204 | lowerBound = std::get(std::get<1>(integerOptions)); 205 | } 206 | else if (BoundType::UpperBound == std::get<0>(integerOptions)) 207 | { 208 | upperBound = std::get(std::get<1>(integerOptions)); 209 | } 210 | else if (BoundType::ScalarIncrement == std::get<0>(integerOptions)) 211 | { 212 | scalarIncrement = std::get(std::get<1>(integerOptions)); 213 | } 214 | } 215 | 216 | if ((attrValue < lowerBound) || (attrValue > upperBound)) 217 | { 218 | lg2::error("Integer, bound is invalid"); 219 | return false; 220 | } 221 | 222 | if (scalarIncrement == 0 || 223 | ((std::abs(attrValue - lowerBound)) % scalarIncrement) != 0) 224 | { 225 | lg2::error( 226 | "((std::abs({ATTR_VALUE} - {LOWER_BOUND})) % {SCALAR_INCREMENT}) != 0", 227 | "ATTR_VALUE", attrValue, "LOWER_BOUND", lowerBound, 228 | "SCALAR_INCREMENT", scalarIncrement); 229 | return false; 230 | } 231 | 232 | return true; 233 | } 234 | 235 | Manager::PendingAttributes Manager::pendingAttributes(PendingAttributes value) 236 | { 237 | // Clear the pending attributes 238 | if (value.empty()) 239 | { 240 | auto pendingAttrs = Base::pendingAttributes({}, false); 241 | serialize(*this, biosFile); 242 | return pendingAttrs; 243 | } 244 | 245 | // Validate all the BIOS attributes before setting PendingAttributes 246 | BaseTable biosTable = Base::baseBIOSTable(); 247 | for (const auto& pair : value) 248 | { 249 | auto iter = biosTable.find(pair.first); 250 | // BIOS attribute not found in the BaseBIOSTable 251 | if (iter == biosTable.end()) 252 | { 253 | lg2::error("BIOS attribute not found in the BaseBIOSTable"); 254 | throw AttributeNotFound(); 255 | } 256 | 257 | auto attributeType = 258 | std::get(Index::attributeType)>(iter->second); 259 | if (attributeType != std::get<0>(pair.second)) 260 | { 261 | lg2::error("attributeType is not same with bios base table"); 262 | throw InvalidArgument(); 263 | } 264 | 265 | // Validate enumeration BIOS attributes 266 | if (attributeType == AttributeType::Enumeration) 267 | { 268 | // For enumeration the expected variant types is Enumeration 269 | if (std::get<1>(pair.second).index() == 0) 270 | { 271 | lg2::error("Enumeration property value is not enum"); 272 | throw InvalidArgument(); 273 | } 274 | 275 | const auto& attrValue = 276 | std::get(std::get<1>(pair.second)); 277 | const auto& options = 278 | std::get(Index::options)>(iter->second); 279 | 280 | if (!validateEnumOption(attrValue, options)) 281 | { 282 | throw InvalidArgument(); 283 | } 284 | } 285 | 286 | if (attributeType == AttributeType::String) 287 | { 288 | // For enumeration the expected variant types is std::string 289 | if (std::get<1>(pair.second).index() == 0) 290 | { 291 | lg2::error("String property value is not string"); 292 | throw InvalidArgument(); 293 | } 294 | 295 | const auto& attrValue = 296 | std::get(std::get<1>(pair.second)); 297 | const auto& options = 298 | std::get(Index::options)>(iter->second); 299 | 300 | if (!validateStringOption(attrValue, options)) 301 | { 302 | throw InvalidArgument(); 303 | } 304 | } 305 | 306 | if (attributeType == AttributeType::Integer) 307 | { 308 | // For enumeration the expected variant types is Integer 309 | if (std::get<1>(pair.second).index() == 1) 310 | { 311 | lg2::error("Integer property value is not int"); 312 | throw InvalidArgument(); 313 | } 314 | 315 | const auto& attrValue = std::get(std::get<1>(pair.second)); 316 | const auto& options = 317 | std::get(Index::options)>(iter->second); 318 | 319 | if (!validateIntegerOption(attrValue, options)) 320 | { 321 | throw InvalidArgument(); 322 | } 323 | } 324 | } 325 | 326 | PendingAttributes pendingAttribute = Base::pendingAttributes(); 327 | 328 | for (const auto& pair : value) 329 | { 330 | auto iter = pendingAttribute.find(pair.first); 331 | if (iter != pendingAttribute.end()) 332 | { 333 | iter = pendingAttribute.erase(iter); 334 | } 335 | 336 | pendingAttribute.emplace(std::make_pair(pair.first, pair.second)); 337 | } 338 | 339 | auto pendingAttrs = Base::pendingAttributes(pendingAttribute, false); 340 | serialize(*this, biosFile); 341 | 342 | return pendingAttrs; 343 | } 344 | 345 | void Manager::convertBiosDataToVersion1(Manager::oldBaseTable biosTbl, 346 | Manager::BaseTable& baseTable) 347 | { 348 | lg2::error("convertBiosDataToVersion1"); 349 | for (const auto& [key, baseTuple] : biosTbl) 350 | { 351 | const auto& vec = std::get<7>(baseTuple); 352 | std::vector, 353 | std::string>> 354 | dataVec; 355 | 356 | for (const auto& [value, variantVal] : vec) 357 | { 358 | dataVec.emplace_back(value, variantVal, 359 | ""); // Copy VDN as empty string 360 | } 361 | 362 | if (std::get<0>(baseTuple) == AttributeType::Integer) 363 | { 364 | baseTable[key] = std::make_tuple( 365 | std::get<0>(baseTuple), std::get<1>(baseTuple), 366 | std::get<2>(baseTuple), std::get<3>(baseTuple), 367 | std::get<4>(baseTuple), 368 | std::get(std::get<5>(baseTuple)), 369 | std::get(std::get<6>(baseTuple)), dataVec); 370 | } 371 | else 372 | { 373 | baseTable[key] = std::make_tuple( 374 | std::get<0>(baseTuple), std::get<1>(baseTuple), 375 | std::get<2>(baseTuple), std::get<3>(baseTuple), 376 | std::get<4>(baseTuple), 377 | std::get(std::get<5>(baseTuple)), 378 | std::get(std::get<6>(baseTuple)), dataVec); 379 | } 380 | } 381 | } 382 | 383 | void Manager::convertBiosDataToVersion0(Manager::oldBaseTable& baseTable, 384 | Manager::BaseTable& biosTbl) 385 | { 386 | lg2::error("convertBiosDataToVersion0"); 387 | for (const auto& [key, baseTuple] : biosTbl) 388 | { 389 | const auto& vec = std::get<7>(baseTuple); 390 | std::vector>> 391 | dataVec; 392 | 393 | for (const auto& [value, variantVal, vDisplayName] : vec) 394 | { 395 | dataVec.emplace_back(value, variantVal); // Remove VDN 396 | } 397 | 398 | if (std::get<0>(baseTuple) == AttributeType::Integer) 399 | { 400 | baseTable[key] = std::make_tuple( 401 | std::get<0>(baseTuple), std::get<1>(baseTuple), 402 | std::get<2>(baseTuple), std::get<3>(baseTuple), 403 | std::get<4>(baseTuple), 404 | std::get(std::get<5>(baseTuple)), 405 | std::get(std::get<6>(baseTuple)), dataVec); 406 | } 407 | else 408 | { 409 | baseTable[key] = std::make_tuple( 410 | std::get<0>(baseTuple), std::get<1>(baseTuple), 411 | std::get<2>(baseTuple), std::get<3>(baseTuple), 412 | std::get<4>(baseTuple), 413 | std::get(std::get<5>(baseTuple)), 414 | std::get(std::get<6>(baseTuple)), dataVec); 415 | } 416 | } 417 | } 418 | 419 | Manager::Manager(sdbusplus::asio::object_server& objectServer, 420 | std::shared_ptr& systemBus, 421 | std::string persistPath) : 422 | bios_config::Base(*systemBus, objectPath), objServer(objectServer), 423 | systemBus(systemBus) 424 | { 425 | fs::path biosDir(persistPath); 426 | fs::create_directories(biosDir); 427 | biosFile = biosDir / biosPersistFile; 428 | deserialize(biosFile, *this); 429 | } 430 | 431 | void Manager::createBootOption(std::string id) 432 | { 433 | const std::regex illegalDbusRegex("[^A-Za-z0-9_]"); 434 | const std::string key = std::regex_replace(id, illegalDbusRegex, "_"); 435 | if (bootOptionValues.contains(key)) 436 | { 437 | throw InvalidArgument(); 438 | } 439 | 440 | std::string path = std::string(bootOptionsPath) + "/" + key; 441 | bootOptionValues[key] = {{"Enabled", true}, 442 | {"Description", ""}, 443 | {"DisplayName", ""}, 444 | {"UefiDevicePath", ""}}; 445 | dbusBootOptions[key] = 446 | std::make_unique(*systemBus, path.c_str(), *this, key); 447 | for (const auto& v : bootOptionValues[key]) 448 | { 449 | dbusBootOptions[key]->BootOptionDbusBase::setPropertyByName( 450 | v.first, v.second); 451 | } 452 | 453 | serialize(*this, biosFile); 454 | } 455 | 456 | void Manager::deleteBootOption(const std::string& key) 457 | { 458 | bootOptionValues.erase(key); 459 | dbusBootOptions.erase(key); 460 | 461 | serialize(*this, biosFile); 462 | } 463 | 464 | Manager::BootOptionsType Manager::getBootOptionValues() const 465 | { 466 | return bootOptionValues; 467 | } 468 | 469 | void Manager::setBootOptionValues(const BootOptionsType& loaded) 470 | { 471 | bootOptionValues = loaded; 472 | dbusBootOptions.clear(); 473 | for (const auto& [key, values] : bootOptionValues) 474 | { 475 | std::string path = std::string(bootOptionsPath) + "/" + key; 476 | dbusBootOptions[key] = std::make_unique( 477 | *systemBus, path.c_str(), *this, key); 478 | for (const auto& v : values) 479 | { 480 | dbusBootOptions[key]->BootOptionDbusBase::setPropertyByName( 481 | v.first, v.second); 482 | } 483 | // In case of loading from a file with old version that doesn't 484 | // include the PendingEnabled property, set it to the same value as 485 | // Enabled 486 | auto enabledIt = values.find("Enabled"); 487 | auto pendingEnabledIt = values.find("PendingEnabled"); 488 | if (enabledIt != values.end() && pendingEnabledIt == values.end()) 489 | { 490 | dbusBootOptions[key]->pendingEnabled( 491 | std::get(enabledIt->second)); 492 | } 493 | } 494 | } 495 | 496 | Manager::BootOrderType Manager::bootOrder(Manager::BootOrderType value) 497 | { 498 | auto newValue = Base::bootOrder(value, false); 499 | #ifdef CLEAR_PENDING_BOOTORDER_ON_UPDATE 500 | Manager::pendingBootOrder(std::vector()); 501 | #else 502 | Manager::pendingBootOrder(value); 503 | #endif 504 | return newValue; 505 | } 506 | 507 | Manager::BootOrderType Manager::pendingBootOrder(Manager::BootOrderType value) 508 | { 509 | auto newValue = Base::pendingBootOrder(value, false); 510 | serialize(*this, biosFile); 511 | return newValue; 512 | } 513 | 514 | Manager::CurrentBootType Manager::currentBoot(Manager::CurrentBootType value) 515 | { 516 | auto newValue = Base::currentBoot(value, false); 517 | serialize(*this, biosFile); 518 | using namespace phosphor::logging; 519 | // Below block of code is to send event when CurrentBoot property is 520 | // modified. 521 | std::string bootType = convertCurrentBootTypeToString(value); 522 | parsePropertyValueAndSendEvent("SecureCurrentBoot", bootType, objectPath); 523 | 524 | return newValue; 525 | } 526 | 527 | bool Manager::pendingEnable(bool value) 528 | { 529 | auto newValue = Base::pendingEnable(value, false); 530 | serialize(*this, biosFile); 531 | sendRedfishEvent("SecureBootEnable", std::to_string(value), objectPath); 532 | return newValue; 533 | } 534 | 535 | Manager::ModeType Manager::mode(Manager::ModeType value) 536 | { 537 | auto newValue = Base::mode(value, false); 538 | serialize(*this, biosFile); 539 | using namespace phosphor::logging; 540 | // Below block of code is to send event when SecureBootMode property is 541 | // modified. 542 | std::string modeType = convertModeTypeToString(value); 543 | parsePropertyValueAndSendEvent("SecureBootMode", modeType, objectPath); 544 | return newValue; 545 | } 546 | 547 | } // namespace bios_config 548 | --------------------------------------------------------------------------------