|  | /* | 
|  | // Copyright (c) 2020 Intel Corporation | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include "biosxml.hpp" | 
|  |  | 
|  | #include <openssl/sha.h> | 
|  |  | 
|  | #include <biosconfigcommands.hpp> | 
|  | #include <boost/crc.hpp> | 
|  | #include <boost/process/child.hpp> | 
|  | #include <boost/process/io.hpp> | 
|  | #include <ipmid/api.hpp> | 
|  | #include <ipmid/message.hpp> | 
|  | #include <ipmid/message/types.hpp> | 
|  | #include <ipmid/types.hpp> | 
|  | #include <ipmid/utils.hpp> | 
|  | #include <nlohmann/json.hpp> | 
|  | #include <oemcommands.hpp> | 
|  | #include <sdbusplus/bus.hpp> | 
|  | #include <sdbusplus/message/types.hpp> | 
|  |  | 
|  | #include <filesystem> | 
|  | #include <string_view> | 
|  |  | 
|  | namespace ipmi | 
|  | { | 
|  | static bool flushNVOOBdata(); | 
|  | static void registerBIOSConfigFunctions() __attribute__((constructor)); | 
|  |  | 
|  | // Define BIOS config related Completion Code | 
|  | using Cc = uint8_t; | 
|  | static constexpr Cc ipmiCCPayloadPayloadPacketMissed = 0x80; | 
|  | static constexpr Cc ipmiCCBIOSPasswordInitNotDone = 0x80; | 
|  | static constexpr Cc ipmiCCPayloadChecksumFailed = 0x81; | 
|  | static constexpr Cc ipmiCCNotSupportedInCurrentState = 0x82; | 
|  | static constexpr Cc ipmiCCPayloadPayloadInComplete = 0x83; | 
|  | static constexpr Cc ipmiCCBIOSCapabilityInitNotDone = 0x85; | 
|  | static constexpr Cc ipmiCCPayloadLengthIllegal = 0x85; | 
|  |  | 
|  | static constexpr uint8_t userPasswordChanged = (1 << 5); | 
|  | static constexpr uint8_t adminPasswordChanged = (1 << 4); | 
|  |  | 
|  | static constexpr const char* biosConfigFolder = "/var/oob"; | 
|  | static constexpr const char* biosConfigNVPath = "/var/oob/nvoobdata.dat"; | 
|  | static constexpr const uint8_t algoSHA384 = 2; | 
|  | static constexpr const uint8_t algoSHA256 = 1; | 
|  | static constexpr const uint8_t biosCapOffsetBit = 0x3; | 
|  | static constexpr uint16_t maxGetPayloadDataSize = 4096; | 
|  | static constexpr const char* biosXMLFilePath = "/var/oob/bios.xml"; | 
|  | static constexpr const char* biosXMLFilePath1 = "/var/oob/tempbios.xml"; | 
|  |  | 
|  | static constexpr const char* biosConfigBaseMgrPath = | 
|  | "/xyz/openbmc_project/bios_config/manager"; | 
|  | static constexpr const char* biosConfigIntf = | 
|  | "xyz.openbmc_project.BIOSConfig.Manager"; | 
|  | static constexpr const char* resetBIOSSettingsProp = "ResetBIOSSettings"; | 
|  | /*baseBIOSTable | 
|  | map{attributeName,struct{attributeType,readonlyStatus,displayname, | 
|  | description,menuPath,current,default, | 
|  | array{struct{optionstring,optionvalue}}}} | 
|  | */ | 
|  |  | 
|  | bios::BiosBaseTableType attributesData; | 
|  |  | 
|  | NVOOBdata gNVOOBdata; | 
|  |  | 
|  | enum class PTState : uint8_t | 
|  | { | 
|  | StartTransfer = 0, | 
|  | InProgress = 1, | 
|  | EndTransfer = 2, | 
|  | UserAbort = 3 | 
|  | }; | 
|  | enum class PStatus : uint8_t | 
|  | { | 
|  | Unknown = 0, | 
|  | Valid = 1, | 
|  | Corrupted = 2 | 
|  | }; | 
|  | enum class PType : uint8_t | 
|  | { | 
|  | IntelXMLType0 = 0, | 
|  | IntelXMLType1 = 1, | 
|  | OTAPayload = 5, | 
|  | }; | 
|  |  | 
|  | // | 
|  | // GetPayload Payload status enumeration | 
|  | // | 
|  | enum class GetPayloadParameter : uint8_t | 
|  | { | 
|  | GetPayloadInfo = 0, // 0 | 
|  | GetPayloadData = 1, // 1 | 
|  | GetPayloadStatus = 2 | 
|  | }; | 
|  |  | 
|  | namespace payload1 | 
|  | { | 
|  |  | 
|  | enum class AttributesType : uint8_t | 
|  | { | 
|  | unknown = 0, | 
|  | string, | 
|  | integer, | 
|  | enumeration | 
|  | }; | 
|  |  | 
|  | using PendingAttributesType = | 
|  | std::map<std::string, | 
|  | std::tuple<std::string, std::variant<int64_t, std::string>>>; | 
|  |  | 
|  | AttributesType getAttrType(const std::string_view typeDbus) | 
|  | { | 
|  | if (typeDbus == "xyz.openbmc_project.BIOSConfig.Manager." | 
|  | "AttributeType.String") | 
|  | { | 
|  | return AttributesType::string; | 
|  | } | 
|  | else if (typeDbus == "xyz.openbmc_project.BIOSConfig." | 
|  | "Manager.AttributeType.Integer") | 
|  | { | 
|  | return AttributesType::integer; | 
|  | } | 
|  | else if (typeDbus == "xyz.openbmc_project.BIOSConfig." | 
|  | "Manager.AttributeType.Enumeration") | 
|  | { | 
|  | return AttributesType::enumeration; | 
|  | } | 
|  |  | 
|  | return AttributesType::unknown; | 
|  | } | 
|  |  | 
|  | bool fillPayloadData(std::string& payloadData, | 
|  | const std::variant<int64_t, std::string>& attributes, | 
|  | const std::string_view key, AttributesType& attrType) | 
|  | { | 
|  | payloadData += key; | 
|  | payloadData += '='; | 
|  |  | 
|  | if (attrType == AttributesType::string || | 
|  | attrType == AttributesType::enumeration) | 
|  | { | 
|  | if (!std::holds_alternative<std::string>(attributes)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "fillPayloadData: No string data in attributes"); | 
|  | return false; | 
|  | } | 
|  | payloadData += std::get<std::string>(attributes); | 
|  | } | 
|  | else if (attrType == AttributesType::integer) | 
|  | { | 
|  | if (!std::holds_alternative<int64_t>(attributes)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "fillPayloadData: No int64_t data in attributes"); | 
|  | return false; | 
|  | } | 
|  | payloadData += std::to_string(std::get<int64_t>(attributes)); | 
|  | } | 
|  | else | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "fillPayloadData: Unsupported attribute type"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | payloadData += '\n'; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool getPendingList(ipmi::Context::ptr ctx, std::string& payloadData) | 
|  | { | 
|  | std::variant<PendingAttributesType> pendingAttributesData; | 
|  | boost::system::error_code ec; | 
|  |  | 
|  | payloadData.clear(); | 
|  |  | 
|  | auto dbus = getSdBus(); | 
|  | if (!dbus) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "getPendingList: getSdBus() failed"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | std::string service = | 
|  | getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath); | 
|  |  | 
|  | try | 
|  | { | 
|  | pendingAttributesData = | 
|  | dbus->yield_method_call<std::variant<PendingAttributesType>>( | 
|  | ctx->yield, ec, service, | 
|  | "/xyz/openbmc_project/bios_config/manager", | 
|  | "org.freedesktop.DBus.Properties", "Get", | 
|  | "xyz.openbmc_project.BIOSConfig.Manager", "PendingAttributes"); | 
|  | } | 
|  | catch (const std::exception& ex) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>(ex.what()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (ec) | 
|  | { | 
|  | std::string err = "getPendingList: error while trying to get " | 
|  | "PendingAttributes, error = "; | 
|  | err += ec.message(); | 
|  |  | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>(err.c_str()); | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const PendingAttributesType* pendingAttributes = | 
|  | std::get_if<PendingAttributesType>(&pendingAttributesData); | 
|  | if (!pendingAttributes) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "getPendingList: pendingAttributes is null"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | for (const auto& [key, attributes] : *pendingAttributes) | 
|  | { | 
|  | const std::string& itemType = std::get<0>(attributes); | 
|  | AttributesType attrType = getAttrType(itemType); | 
|  |  | 
|  | if (!fillPayloadData(payloadData, std::get<1>(attributes), key, | 
|  | attrType)) | 
|  | { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (payloadData.empty()) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "getPendingList: payloadData is empty"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  | bool updatePayloadFile(std::string& payloadFilePath, std::string payloadData) | 
|  | { | 
|  | std::ofstream payloadFile(payloadFilePath, | 
|  | std::ios::out | std::ios::binary); | 
|  |  | 
|  | payloadFile << payloadData; | 
|  |  | 
|  | if (!payloadFile.good()) | 
|  | { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool computeCheckSum(std::string& payloadFilePath, | 
|  | boost::crc_32_type& calcChecksum) | 
|  | { | 
|  | std::ifstream payloadFile(payloadFilePath.c_str(), | 
|  | std::ios::in | std::ios::binary | std::ios::ate); | 
|  |  | 
|  | if (!payloadFile.good()) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "computeCheckSum: Cannot open Payload1 file"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | payloadFile.seekg(0, payloadFile.end); | 
|  | int length = payloadFile.tellg(); | 
|  | payloadFile.seekg(0, payloadFile.beg); | 
|  |  | 
|  | if (maxGetPayloadDataSize < length) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "computeCheckSum: length > maxGetPayloadDataSize"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | std::unique_ptr<char[]> payloadBuffer(new char[length]); | 
|  |  | 
|  | payloadFile.read(payloadBuffer.get(), length); | 
|  | uint32_t readCount = payloadFile.gcount(); | 
|  |  | 
|  | calcChecksum.process_bytes(payloadBuffer.get(), readCount); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool updatePayloadInfo(std::string& payloadFilePath) | 
|  | { | 
|  | boost::crc_32_type calcChecksum; | 
|  |  | 
|  | uint8_t payloadType = static_cast<uint8_t>(ipmi::PType::IntelXMLType1); | 
|  | auto& payloadInfo = gNVOOBdata.payloadInfo[payloadType]; | 
|  |  | 
|  | if (!computeCheckSum(payloadFilePath, calcChecksum)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "updatePayloadInfo: Cannot compute checksum for Payload1 file"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | payloadInfo.payloadVersion = 0; | 
|  | payloadInfo.payloadflag = 0; | 
|  | payloadInfo.payloadReservationID = rand(); | 
|  |  | 
|  | payloadInfo.payloadType = payloadType; | 
|  |  | 
|  | payloadInfo.payloadTotalChecksum = calcChecksum.checksum(); | 
|  | payloadInfo.payloadCurrentChecksum = payloadInfo.payloadTotalChecksum; | 
|  |  | 
|  | payloadInfo.payloadStatus = (static_cast<uint8_t>(ipmi::PStatus::Valid)); | 
|  |  | 
|  | struct stat filestat; | 
|  | /* Get entry's information. */ | 
|  | if (!stat(payloadFilePath.c_str(), &filestat)) | 
|  | { | 
|  | payloadInfo.payloadTimeStamp = filestat.st_mtime; | 
|  | payloadInfo.payloadTotalSize = filestat.st_size; | 
|  | payloadInfo.payloadCurrentSize = filestat.st_size; | 
|  | payloadInfo.actualTotalPayloadWritten = filestat.st_size; | 
|  | } | 
|  | else | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "updatePayloadInfo: Cannot get file status for Payload1 file"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!flushNVOOBdata()) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "updatePayloadInfo: flushNVOOBdata failed"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool update(ipmi::Context::ptr ctx) | 
|  | { | 
|  | std::string payloadFilePath = | 
|  | "/var/oob/Payload" + | 
|  | std::to_string(static_cast<uint8_t>(ipmi::PType::IntelXMLType1)); | 
|  |  | 
|  | std::string payloadData; | 
|  |  | 
|  | if (!getPendingList(ctx, payloadData)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "payload1::update : getPendingList() failed"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!updatePayloadFile(payloadFilePath, payloadData)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "payload1::update : updatePayloadFile() failed"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (!updatePayloadInfo(payloadFilePath)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "payload1::update : updatePayloadInfo() failed"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  | } // namespace payload1 | 
|  |  | 
|  | /** @brief implement to set the BaseBIOSTable property | 
|  | *  @returns status | 
|  | */ | 
|  | static bool sendAllAttributes(std::string service) | 
|  | { | 
|  | std::shared_ptr<sdbusplus::asio::connection> pSdBusPlus = getSdBus(); | 
|  |  | 
|  | if (pSdBusPlus) | 
|  | { | 
|  | try | 
|  | { | 
|  | pSdBusPlus->async_method_call( | 
|  | [](const boost::system::error_code ec) { | 
|  | /* No more need to keep attributes data in memory */ | 
|  | attributesData.clear(); | 
|  |  | 
|  | if (ec) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "sendAllAttributes error: send all attributes - " | 
|  | "failed"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | "sendAllAttributes: send all attributes - done"); | 
|  | }, | 
|  | service, biosConfigBaseMgrPath, | 
|  | "org.freedesktop.DBus.Properties", "Set", biosConfigIntf, | 
|  | "BaseBIOSTable", | 
|  | std::variant<bios::BiosBaseTableType>(attributesData)); | 
|  |  | 
|  | return true; | 
|  | } | 
|  | catch (const std::exception& ex) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>(ex.what()); | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /** @brief implement to flush the updated data in nv space | 
|  | *  @returns status | 
|  | */ | 
|  | static bool flushNVOOBdata() | 
|  | { | 
|  | std::ofstream outFile(biosConfigNVPath, std::ios::binary); | 
|  |  | 
|  | outFile.seekp(std::ios_base::beg); | 
|  | const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata); | 
|  | outFile.write(writedata, sizeof(struct NVOOBdata)); | 
|  |  | 
|  | if (!outFile.good()) | 
|  | { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** @brief implement to get the System State | 
|  | *  @returns status | 
|  | */ | 
|  | static bool getPostCompleted() | 
|  | { | 
|  | /* | 
|  | * In case of failure we treat postCompleted as true. | 
|  | * So that BIOS config commands is not accepted by BMC by mistake. | 
|  | */ | 
|  | bool postCompleted = true; | 
|  |  | 
|  | try | 
|  | { | 
|  | std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); | 
|  | Value variant = | 
|  | getDbusProperty(*dbus, "xyz.openbmc_project.State.OperatingSystem", | 
|  | "/xyz/openbmc_project/state/os", | 
|  | "xyz.openbmc_project.State.OperatingSystem.Status", | 
|  | "OperatingSystemState"); | 
|  | auto& value = std::get<std::string>(variant); | 
|  |  | 
|  | // The short strings "Standby" is deprecated in favor of the | 
|  | // full enum strings. Support for the short strings will be | 
|  | // removed in the future. | 
|  | postCompleted = (value == "Standby") || | 
|  | (value == "xyz.openbmc_project.State.OperatingSystem." | 
|  | "Status.OSStatus.Standby"); | 
|  | } | 
|  | catch (const std::exception& e) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "'getDbusProperty' failed to read " | 
|  | "xyz.openbmc_project.State.OperatingSystem"); | 
|  | } | 
|  |  | 
|  | return postCompleted; | 
|  | } | 
|  |  | 
|  | /** @brief implement to get the Rest BIOS property | 
|  | *  @returns status | 
|  | */ | 
|  | static int getResetBIOSSettings(uint8_t& ResetFlag) | 
|  | { | 
|  |  | 
|  | try | 
|  | { | 
|  | std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); | 
|  | std::string service = | 
|  | getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath); | 
|  | Value variant = getDbusProperty(*dbus, service, biosConfigBaseMgrPath, | 
|  | biosConfigIntf, resetBIOSSettingsProp); | 
|  |  | 
|  | std::string_view ResetStr = std::get<std::string>(variant); | 
|  | if (ResetStr == | 
|  | "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag.NoAction") | 
|  | { | 
|  | ResetFlag = 0; | 
|  | } | 
|  | else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag." | 
|  | "FactoryDefaults") | 
|  | { | 
|  | ResetFlag = 1; | 
|  | } | 
|  | else if (ResetStr == "xyz.openbmc_project.BIOSConfig.Manager.ResetFlag." | 
|  | "FailSafeDefaults") | 
|  | { | 
|  | ResetFlag = 2; | 
|  | } | 
|  | else | 
|  | { | 
|  | return ipmi::ccUnspecifiedError; | 
|  | } | 
|  |  | 
|  | return ipmi::ccSuccess; | 
|  | } | 
|  | catch (const std::exception& e) | 
|  | { | 
|  | return ipmi::ccUnspecifiedError; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** @brief Get attributes data (bios base table) from bios.xml | 
|  | */ | 
|  | static bool generateAttributesData() | 
|  | { | 
|  | try | 
|  | { | 
|  | bios::Xml biosxml(biosXMLFilePath); | 
|  |  | 
|  | if (!biosxml.doDepexCompute()) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "'depex' compute failed"); | 
|  | } | 
|  |  | 
|  | if (!biosxml.getBaseTable(attributesData)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "Failed to get bios base table"); | 
|  | } | 
|  | } | 
|  | catch (const std::exception& ex) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>(ex.what()); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** @brief Generate attributes data from bios.xml | 
|  | * and send attributes data (bios base table) to dbus using set method. | 
|  | */ | 
|  | static void generateAndSendAttributesData(std::string service, | 
|  | uint8_t payloadType) | 
|  | { | 
|  | if (!generateAttributesData()) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "generateAndSendAttributesData: generateAttributesData - failed"); | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadStatus = | 
|  | static_cast<uint8_t>(ipmi::PStatus::Corrupted); | 
|  | return; | 
|  | } | 
|  |  | 
|  | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | "generateAndSendAttributesData : generateAttributesData is done"); | 
|  |  | 
|  | if (!sendAllAttributes(service)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "generateAndSendAttributesData: sendAllAttributes - failed"); | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadStatus = | 
|  | static_cast<uint8_t>(ipmi::PStatus::Corrupted); | 
|  | return; | 
|  | } | 
|  |  | 
|  | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | "generateAndSendAttributesData : sendAllAttributes is done"); | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadStatus = | 
|  | static_cast<uint8_t>(ipmi::PStatus::Valid); | 
|  | } | 
|  |  | 
|  | /** @brief implement executing the linux command to uncompress and generate the | 
|  | * xmlfile | 
|  | *  @param[in] linux command | 
|  | *  @returns status | 
|  | */ | 
|  | template <typename... ArgTypes> | 
|  | static int generateBIOSXMLFile(const char* path, ArgTypes&&... tArgs) | 
|  | { | 
|  |  | 
|  | boost::process::child execProg(path, const_cast<char*>(tArgs)..., | 
|  | boost::process::std_out > biosXMLFilePath); | 
|  | execProg.wait(); | 
|  | return execProg.exit_code(); | 
|  | } | 
|  |  | 
|  | /** @brief implements to clean up the temp/ existing payload file | 
|  | **/ | 
|  | static void cleanUpPayloadFile(uint8_t& payloadType) | 
|  | { | 
|  | // Clear the payload Information | 
|  | std::string FilePath = "/var/oob/temp" + std::to_string(payloadType); | 
|  | unlink(FilePath.c_str()); | 
|  | FilePath = "/var/oob/Payload" + std::to_string(payloadType); | 
|  | unlink(FilePath.c_str()); | 
|  | if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0)) | 
|  | { | 
|  | unlink("/var/oob/Payload1"); | 
|  | gNVOOBdata.payloadInfo[static_cast<uint8_t>(ipmi::PType::IntelXMLType1)] | 
|  | .payloadStatus = static_cast<uint8_t>(ipmi::PStatus::Unknown); | 
|  | } | 
|  | } | 
|  |  | 
|  | /** @brief implements to create the oob folders and nv space | 
|  | **/ | 
|  | static Cc InitNVOOBdata() | 
|  | { | 
|  | FILE* fptr; | 
|  | uint16_t size; | 
|  |  | 
|  | if (!(std::filesystem::exists(biosConfigFolder))) | 
|  | { | 
|  | std::filesystem::create_directory(biosConfigFolder); | 
|  | } | 
|  |  | 
|  | std::ifstream ifs(biosConfigNVPath, std::ios::in | std::ios::binary); | 
|  |  | 
|  | if (ifs.good()) | 
|  | { | 
|  |  | 
|  | ifs.seekg(std::ios_base::beg); | 
|  | ifs.read(reinterpret_cast<char*>(&gNVOOBdata), | 
|  | sizeof(struct NVOOBdata)); | 
|  | ifs.close(); | 
|  | return ipmi::ccSuccess; | 
|  | } | 
|  | return ipmi::ccResponseError; | 
|  | } | 
|  |  | 
|  | /** @brief implements check the command interface is | 
|  | ** system interface or not | 
|  | **  true mean System interface and false mean LAN or IPMB | 
|  | **/ | 
|  | static bool IsSystemInterface(ipmi::Context::ptr ctx) | 
|  | { | 
|  | ChannelInfo chInfo; | 
|  | Cc status = false; | 
|  |  | 
|  | try | 
|  | { | 
|  | getChannelInfo(ctx->channel, chInfo); | 
|  | } | 
|  | catch (const sdbusplus::exception_t& e) | 
|  | { | 
|  | return false; | 
|  | } | 
|  | if (chInfo.mediumType != | 
|  | static_cast<uint8_t>(EChannelMediumType::systemInterface)) | 
|  | { | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | ipmi::RspType<> ipmiOEMSetBIOSCap(ipmi::Context::ptr ctx, | 
|  | uint8_t BIOSCapabilties, uint8_t reserved1, | 
|  | uint8_t reserved2, uint8_t reserved3) | 
|  | { | 
|  | if (!getPostCompleted() && IsSystemInterface(ctx)) | 
|  | { | 
|  | if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0) | 
|  | { | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  |  | 
|  | gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties; | 
|  | gNVOOBdata.mIsBIOSCapInitDone = true; | 
|  |  | 
|  | flushNVOOBdata(); | 
|  | return ipmi::responseSuccess(); | 
|  | } | 
|  | else | 
|  | { | 
|  | return ipmi::response(ipmiCCNotSupportedInCurrentState); | 
|  | } | 
|  | } | 
|  |  | 
|  | ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t> | 
|  | ipmiOEMGetBIOSCap(ipmi::Context::ptr ctx) | 
|  | { | 
|  | if (gNVOOBdata.mIsBIOSCapInitDone) | 
|  | { | 
|  | return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability, | 
|  | 0, 0, 0); | 
|  | } | 
|  | else | 
|  | { | 
|  | return ipmi::response(ipmiCCBIOSCapabilityInitNotDone); | 
|  | } | 
|  | } | 
|  |  | 
|  | ipmi::RspType<uint32_t> ipmiOEMSetPayload(ipmi::Context::ptr ctx, | 
|  | uint8_t paramSel, uint8_t payloadType, | 
|  | std::vector<uint8_t> payload) | 
|  | { | 
|  | uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported | 
|  | //      1-OOB BIOS config is supported | 
|  |  | 
|  | if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit))) | 
|  | { | 
|  | return ipmi::response(ipmiCCBIOSCapabilityInitNotDone); | 
|  | } | 
|  |  | 
|  | // Validate the Payload Type | 
|  | if (payloadType > maxPayloadSupported) | 
|  | { | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  |  | 
|  | // We should support this Payload type 0 command only in KCS Interface | 
|  | if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0)) | 
|  | { | 
|  | if (!IsSystemInterface(ctx) || getPostCompleted()) | 
|  | { | 
|  | return ipmi::responseCommandNotAvailable(); | 
|  | } | 
|  | } | 
|  |  | 
|  | switch (static_cast<PTState>(paramSel)) | 
|  | { | 
|  | case ipmi::PTState::StartTransfer: | 
|  | { | 
|  | PayloadStartTransfer* pPayloadStartTransfer = | 
|  | reinterpret_cast<PayloadStartTransfer*>(payload.data()); | 
|  | if (payload.size() < sizeof(PayloadStartTransfer)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMSetPayload: BIOS Config Payload size is not " | 
|  | "correct"); | 
|  | return ipmi::responseReqDataLenInvalid(); | 
|  | } | 
|  | cleanUpPayloadFile(payloadType); | 
|  |  | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand(); | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum = | 
|  | pPayloadStartTransfer->payloadTotalChecksum; | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = | 
|  | pPayloadStartTransfer->payloadTotalSize; | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadVersion = | 
|  | pPayloadStartTransfer->payloadVersion; | 
|  | gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0; | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadStatus = | 
|  | static_cast<uint8_t>(ipmi::PStatus::Unknown); | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadType = payloadType; | 
|  |  | 
|  | return ipmi::responseSuccess( | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadReservationID); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ipmi::PTState::InProgress: | 
|  | { | 
|  | PayloadInProgress* pPayloadInProgress = | 
|  | reinterpret_cast<PayloadInProgress*>(payload.data()); | 
|  | PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType]; | 
|  |  | 
|  | if (payload.size() < sizeof(PayloadInProgress)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "BIOS Config Payload size is not correct"); | 
|  | return ipmi::responseReqDataLenInvalid(); | 
|  | } | 
|  |  | 
|  | if (pPayloadInProgress->payloadReservationID != | 
|  | payloadInfo.payloadReservationID) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "BIOS Config Payload reservation ID is not correct"); | 
|  | return ipmi::responseInvalidReservationId(); | 
|  | } | 
|  | payloadInfo.payloadCurrentSize = | 
|  | pPayloadInProgress->payloadCurrentSize; | 
|  | // Need to verify the current Payload Checksum | 
|  | const uint8_t* data = | 
|  | reinterpret_cast<const uint8_t*>(payload.data()); | 
|  | // we have to remove the current size, current offset, current | 
|  | // length,checksum bytes , reservation bytes | 
|  | boost::crc_32_type calcChecksum; | 
|  | calcChecksum.process_bytes(data + 16, payload.size() - 16); | 
|  | if (calcChecksum.checksum() != | 
|  | pPayloadInProgress->payloadCurrentChecksum) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMSetPayload: Payload Checksum Failed"); | 
|  | return ipmi::response(ipmiCCPayloadChecksumFailed); | 
|  | } | 
|  | // store the data in temp file | 
|  | std::string FilePath = | 
|  | "/var/oob/temp" + std::to_string(payloadType); | 
|  |  | 
|  | std::ofstream outFile(FilePath, std::ios::binary | std::ios::app); | 
|  | outFile.seekp(pPayloadInProgress->payloadOffset); | 
|  | // we have to remove the current size, current offset, current | 
|  | // length,checksum bytes , reservation bytes | 
|  |  | 
|  | const char* writedata = | 
|  | reinterpret_cast<const char*>(payload.data()); | 
|  | outFile.write(writedata + 16, payload.size() - 16); | 
|  | outFile.close(); | 
|  |  | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadStatus = | 
|  | static_cast<uint8_t>(ipmi::PStatus::Unknown); | 
|  | gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten += | 
|  | payloadInfo.payloadCurrentSize; | 
|  | return ipmi::responseSuccess(payloadInfo.payloadCurrentSize); | 
|  | } | 
|  | break; | 
|  | case ipmi::PTState::EndTransfer: | 
|  | { | 
|  | PayloadEndTransfer* pPayloadEndTransfer = | 
|  | reinterpret_cast<PayloadEndTransfer*>(payload.data()); | 
|  | PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType]; | 
|  | if (pPayloadEndTransfer->payloadReservationID != | 
|  | payloadInfo.payloadReservationID) | 
|  | { | 
|  | return ipmi::responseInvalidReservationId(); | 
|  | } | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadStatus = | 
|  | static_cast<uint8_t>(ipmi::PStatus::Unknown); | 
|  |  | 
|  | if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten != | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadTotalSize) | 
|  | { | 
|  | return ipmi::response(ipmiCCPayloadPayloadInComplete); | 
|  | } | 
|  | std::string tempFilePath = | 
|  | "/var/oob/temp" + std::to_string(payloadType); | 
|  | std::string payloadFilePath = | 
|  | "/var/oob/Payload" + std::to_string(payloadType); | 
|  | auto renamestatus = | 
|  | std::rename(tempFilePath.c_str(), payloadFilePath.c_str()); | 
|  | if (renamestatus) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMSetPayload: Renaming Payload file - failed"); | 
|  | } | 
|  |  | 
|  | if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0)) | 
|  | { | 
|  | // Unzip the Intel format XML file type 0 | 
|  | auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d", | 
|  | payloadFilePath.c_str()); | 
|  | if (response) | 
|  | { | 
|  |  | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMSetPayload: generateBIOSXMLFile - failed"); | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadStatus = | 
|  | static_cast<uint8_t>(ipmi::PStatus::Corrupted); | 
|  | return ipmi::response(ipmiCCPayloadPayloadPacketMissed); | 
|  | } | 
|  | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | " ipmiOEMSetPayload : Convert XML into native-dbus DONE"); | 
|  |  | 
|  | /* So that we don't block the call */ | 
|  | auto io = getIoContext(); | 
|  | auto dbus = getSdBus(); | 
|  | if (io && dbus) | 
|  | { | 
|  | std::string service = getService(*dbus, biosConfigIntf, | 
|  | biosConfigBaseMgrPath); | 
|  |  | 
|  | boost::asio::post(*io, [service, payloadType] { | 
|  | generateAndSendAttributesData(service, payloadType); | 
|  | }); | 
|  | } | 
|  | else | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | "ipmiOEMSetPayload: Unable to get io context or sdbus"); | 
|  | return ipmi::responseResponseError(); | 
|  | } | 
|  | } | 
|  |  | 
|  | struct stat filestat; | 
|  |  | 
|  | /* Get entry's information. */ | 
|  | if (!stat(payloadFilePath.c_str(), &filestat)) | 
|  | { | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp = | 
|  | filestat.st_mtime; | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = | 
|  | filestat.st_size; | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadStatus = | 
|  | static_cast<uint8_t>(ipmi::PStatus::Valid); | 
|  | } | 
|  | else | 
|  | { | 
|  | return ipmi::responseResponseError(); | 
|  | } | 
|  | flushNVOOBdata(); | 
|  | return ipmi::responseSuccess( | 
|  | gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten); | 
|  | } | 
|  | break; | 
|  | case ipmi::PTState::UserAbort: | 
|  | { | 
|  | PayloadEndTransfer* pPayloadEndTransfer = | 
|  | reinterpret_cast<PayloadEndTransfer*>(payload.data()); | 
|  | PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType]; | 
|  | if (pPayloadEndTransfer->payloadReservationID != | 
|  | payloadInfo.payloadReservationID) | 
|  | { | 
|  | return ipmi::responseInvalidReservationId(); | 
|  | } | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0; | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadType = 0; | 
|  | gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0; | 
|  | // Delete the temp file | 
|  | std::string tempFilePath = | 
|  | "/var/oob/temp" + std::to_string(payloadType); | 
|  | unlink(tempFilePath.c_str()); | 
|  | flushNVOOBdata(); | 
|  | return ipmi::responseSuccess(); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  | return ipmi::responseResponseError(); | 
|  | } | 
|  |  | 
|  | ipmi::RspType<message::Payload> | 
|  | ipmiOEMGetPayload(ipmi::Context::ptr ctx, uint8_t paramSel, | 
|  | uint8_t payloadType, ipmi::message::Payload& payload) | 
|  | { | 
|  | //      1-OOB BIOS config is supported | 
|  | message::Payload retValue; | 
|  |  | 
|  | if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit))) | 
|  | { | 
|  | return ipmi::response(ipmiCCBIOSCapabilityInitNotDone); | 
|  | } | 
|  | // Validate the Payload Type | 
|  | if (payloadType > maxPayloadSupported) | 
|  | { | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  |  | 
|  | if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType1)) | 
|  | { | 
|  | if (!payload1::update(ctx)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMGetPayload: unable to update NVOOBdata for payloadType " | 
|  | "= IntelXMLType1"); | 
|  | return ipmi::response(ipmi::ccUnspecifiedError); | 
|  | } | 
|  | } | 
|  |  | 
|  | struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType]; | 
|  |  | 
|  | switch (static_cast<GetPayloadParameter>(paramSel)) | 
|  | { | 
|  | case ipmi::GetPayloadParameter::GetPayloadInfo: | 
|  | { | 
|  | std::string payloadFilePath = | 
|  | "/var/oob/Payload" + std::to_string(payloadType); | 
|  |  | 
|  | std::ifstream ifs(payloadFilePath, | 
|  | std::ios::in | std::ios::binary | std::ios::ate); | 
|  |  | 
|  | if (!ifs.good()) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMGetPayload: Payload File Error"); | 
|  | // File does not exist code here | 
|  | return ipmi::response(ipmi::ccUnspecifiedError); | 
|  | } | 
|  |  | 
|  | ifs.close(); | 
|  | retValue.pack(res.payloadVersion); | 
|  | retValue.pack(payloadType); | 
|  | retValue.pack(res.payloadTotalSize); | 
|  | retValue.pack(res.payloadTotalChecksum); | 
|  | retValue.pack(res.payloadflag); | 
|  | retValue.pack(res.payloadStatus); | 
|  | retValue.pack(res.payloadTimeStamp); | 
|  |  | 
|  | return ipmi::responseSuccess(std::move(retValue)); | 
|  | } | 
|  |  | 
|  | break; | 
|  | case ipmi::GetPayloadParameter::GetPayloadData: | 
|  | { | 
|  | if (res.payloadStatus == | 
|  | (static_cast<uint8_t>(ipmi::PStatus::Valid))) | 
|  | { | 
|  | std::vector<uint32_t> reqData; | 
|  | if (payload.unpack(reqData) || !payload.fullyUnpacked()) | 
|  | { | 
|  | return ipmi::responseReqDataLenInvalid(); | 
|  | } | 
|  | uint32_t offset = reqData.at(0); | 
|  | uint32_t length = reqData.at(1); | 
|  | std::string payloadFilePath = | 
|  | "/var/oob/Payload" + std::to_string(payloadType); | 
|  |  | 
|  | if (length > static_cast<uint32_t>(maxGetPayloadDataSize)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMGetPayload: length > maxGetPayloadDataSize", | 
|  | phosphor::logging::entry("LENGTH=%d", length), | 
|  | phosphor::logging::entry("maxGetPayloadDataSize=%d", | 
|  | maxGetPayloadDataSize)); | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  |  | 
|  | std::ifstream ifs(payloadFilePath, std::ios::in | | 
|  | std::ios::binary | | 
|  | std::ios::ate); | 
|  |  | 
|  | if (!ifs.good()) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMGetPayload: Payload File Error"); | 
|  | // File does not exist code here | 
|  | return ipmi::response(ipmi::ccUnspecifiedError); | 
|  | } | 
|  | std::ifstream::pos_type fileSize = ifs.tellg(); | 
|  | // Total file data within given offset | 
|  | if (fileSize < static_cast<uint64_t>(offset)) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMGetPayload: filesize < offset"); | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  |  | 
|  | if ((static_cast<uint64_t>(fileSize) - offset) < length) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | "ipmiOEMGetPayload: (filesize - offset) < length "); | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  |  | 
|  | ifs.seekg(offset, std::ios::beg); | 
|  | std::array<uint8_t, maxGetPayloadDataSize> Buffer; | 
|  | ifs.read(reinterpret_cast<char*>(Buffer.data()), length); | 
|  | uint32_t readCount = ifs.gcount(); | 
|  | ifs.close(); | 
|  |  | 
|  | boost::crc_32_type calcChecksum; | 
|  | calcChecksum.process_bytes( | 
|  | reinterpret_cast<char*>(Buffer.data()), readCount); | 
|  | uint32_t chkSum = calcChecksum.checksum(); | 
|  | retValue.pack(payloadType); | 
|  | retValue.pack(readCount); | 
|  | retValue.pack(chkSum); | 
|  |  | 
|  | for (int i = 0; i < readCount; i++) | 
|  | { | 
|  | retValue.pack(Buffer.at(i)); | 
|  | } | 
|  |  | 
|  | return ipmi::responseSuccess(std::move(retValue)); | 
|  | } | 
|  | else | 
|  | { | 
|  | return ipmi::responseResponseError(); | 
|  | } | 
|  | } | 
|  | break; | 
|  | case ipmi::GetPayloadParameter::GetPayloadStatus: | 
|  | { | 
|  | retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus); | 
|  | return ipmi::responseSuccess(std::move(retValue)); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  |  | 
|  | ipmi::RspType<> ipmiOEMSetBIOSHashInfo( | 
|  | ipmi::Context::ptr ctx, std::array<uint8_t, maxSeedSize>& pwdSeed, | 
|  | uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash) | 
|  | { | 
|  | // We should support this command only in KCS Interface | 
|  | if (!IsSystemInterface(ctx)) | 
|  | { | 
|  | return ipmi::responseCommandNotAvailable(); | 
|  | } | 
|  |  | 
|  | // We should not support this command after System Booted - After Exit Boot | 
|  | // service called | 
|  | if (getPostCompleted()) | 
|  | { | 
|  | return ipmi::response(ipmiCCNotSupportedInCurrentState); | 
|  | } | 
|  |  | 
|  | nlohmann::json json; | 
|  |  | 
|  | if ((algoInfo & 0xF) == algoSHA384) | 
|  | { | 
|  | json["HashAlgo"] = "SHA384"; | 
|  | } | 
|  | else if ((algoInfo & 0xF) == algoSHA256) | 
|  | { | 
|  | json["HashAlgo"] = "SHA256"; | 
|  | } | 
|  | else | 
|  | { | 
|  | return ipmi::responseInvalidFieldRequest(); | 
|  | } | 
|  |  | 
|  | json["Seed"] = pwdSeed; | 
|  | json["IsAdminPwdChanged"] = false; | 
|  | json["AdminPwdHash"] = adminPwdHash; | 
|  | json["IsUserPwdChanged"] = false; | 
|  |  | 
|  | std::array<uint8_t, maxHashSize> userPwdHash; | 
|  | userPwdHash.fill({}); // initializing with 0 as user password hash field | 
|  | // is not used presently | 
|  | json["UserPwdHash"] = userPwdHash; | 
|  | json["StatusFlag"] = algoInfo; | 
|  |  | 
|  | std::string hashFilePath = "/var/lib/bios-settings-manager/seedData"; | 
|  | std::ofstream ofs(hashFilePath, std::ios::out); | 
|  | const auto& writeData = json.dump(); | 
|  | ofs << writeData; | 
|  | ofs.close(); | 
|  | return ipmi::responseSuccess(); | 
|  | } | 
|  |  | 
|  | ipmi::RspType<std::array<uint8_t, maxSeedSize>, uint8_t, | 
|  | std::array<uint8_t, maxHashSize>> | 
|  | ipmiOEMGetBIOSHash(ipmi::Context::ptr ctx) | 
|  | { | 
|  | nlohmann::json data = nullptr; | 
|  |  | 
|  | // We should support this command only in KCS Interface | 
|  | if (!IsSystemInterface(ctx)) | 
|  | { | 
|  | return ipmi::responseCommandNotAvailable(); | 
|  | } | 
|  |  | 
|  | // We should not support this command after System Booted - After Exit Boot | 
|  | // service called | 
|  | if (!getPostCompleted()) | 
|  | { | 
|  | std::string HashFilePath = "/var/lib/bios-settings-manager/seedData"; | 
|  |  | 
|  | std::ifstream devIdFile(HashFilePath); | 
|  | if (devIdFile.is_open()) | 
|  | { | 
|  |  | 
|  | try | 
|  | { | 
|  | data = nlohmann::json::parse(devIdFile, nullptr, false); | 
|  | } | 
|  | catch (const nlohmann::json::parse_error& e) | 
|  | { | 
|  | return ipmi::responseResponseError(); | 
|  | } | 
|  |  | 
|  | if (data.is_discarded()) | 
|  | { | 
|  | return ipmi::responseResponseError(); | 
|  | } | 
|  |  | 
|  | std::array<uint8_t, maxHashSize> newAdminHash; | 
|  | std::array<uint8_t, maxSeedSize> seed; | 
|  |  | 
|  | uint8_t flag = 0; | 
|  | uint8_t adminPwdChangedFlag = 0; | 
|  | if (!data.is_discarded()) | 
|  | { | 
|  |  | 
|  | adminPwdChangedFlag = data["IsAdminPwdChanged"]; | 
|  | newAdminHash = data["AdminPwdHash"]; | 
|  | seed = data["Seed"]; | 
|  | } | 
|  |  | 
|  | auto status = getResetBIOSSettings(flag); | 
|  | if (status) | 
|  | { | 
|  | return ipmi::responseResponseError(); | 
|  | } | 
|  | if (adminPwdChangedFlag) | 
|  | { | 
|  | flag |= adminPasswordChanged; | 
|  | } | 
|  |  | 
|  | std::copy(std::begin(newAdminHash), std::end(newAdminHash), | 
|  | std::begin(newAdminHash)); | 
|  |  | 
|  | return ipmi::responseSuccess(seed, flag, newAdminHash); | 
|  | } | 
|  | else | 
|  | { | 
|  | return ipmi::responseResponseError(); | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | return ipmi::response(ipmiCCNotSupportedInCurrentState); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void registerBIOSConfigFunctions(void) | 
|  | { | 
|  | phosphor::logging::log<phosphor::logging::level::INFO>( | 
|  | "BIOSConfig module initialization"); | 
|  | InitNVOOBdata(); | 
|  |  | 
|  | registerHandler(prioOemBase, intel::netFnGeneral, | 
|  | intel::general::cmdSetBIOSCap, Privilege::Admin, | 
|  | ipmiOEMSetBIOSCap); | 
|  |  | 
|  | registerHandler(prioOemBase, intel::netFnGeneral, | 
|  | intel::general::cmdGetBIOSCap, Privilege::User, | 
|  | ipmiOEMGetBIOSCap); | 
|  | registerHandler(prioOemBase, intel::netFnGeneral, | 
|  | intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin, | 
|  | ipmiOEMSetBIOSHashInfo); | 
|  |  | 
|  | registerHandler(prioOemBase, intel::netFnGeneral, | 
|  | intel::general::cmdGetBIOSPwdHash, Privilege::User, | 
|  | ipmiOEMGetBIOSHash); | 
|  |  | 
|  | registerHandler(prioOemBase, intel::netFnGeneral, | 
|  | intel::general::cmdGetPayload, Privilege::User, | 
|  | ipmiOEMGetPayload); | 
|  | registerHandler(prioOemBase, intel::netFnGeneral, | 
|  | intel::general::cmdSetPayload, Privilege::Admin, | 
|  | ipmiOEMSetPayload); | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | } // namespace ipmi |