blob: 673474557cdf941f3dfebbe5113c9f1b39a18c8f [file] [log] [blame]
/*
// 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 <openssl/sha.h>
#include <tinyxml2.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 <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/message/types.hpp>
#include <filesystem>
#include <string_view>
namespace ipmi
{
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}}}}
*/
using BiosBaseTableType =
std::map<std::string,
std::tuple<std::string, bool, std::string, std::string,
std::string, std::variant<int64_t, std::string>,
std::variant<int64_t, std::string>,
std::vector<std::tuple<
std::string, std::variant<int64_t, std::string>>>>>;
using OptionType =
std::vector<std::tuple<std::string, std::variant<int64_t, std::string>>>;
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
};
/** @brief implement to set the BaseBIOSTable property
* @returns status
*/
static int sendAllAttributes(ipmi::Context::ptr ctx)
{
boost::system::error_code ec;
std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
std::string service =
getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
ec.clear();
ctx->bus->yield_method_call<>(
ctx->yield, ec, service, biosConfigBaseMgrPath,
"org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
"BaseBIOSTable", std::variant<BiosBaseTableType>(attributesData));
if (ec)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Failed to sendAllAttributes");
return -1;
}
return 0;
}
/** @brief implement to flush the updated data in nv space
* @returns status
*/
static uint8_t flushNVOOBdata()
{
std::ofstream outFile(biosConfigNVPath, std::ios::binary);
if (outFile.good())
{
outFile.seekp(std::ios_base::beg);
const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
outFile.write(writedata, sizeof(struct NVOOBdata));
outFile.close();
}
return 0;
}
/** @brief implement to get the System State
* @returns status
*/
static int getSystemOSState(std::string& OsStatus)
{
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");
OsStatus = std::get<std::string>(variant);
return ipmi::ccSuccess;
}
catch (const std::exception& e)
{
return ipmi::ccUnspecifiedError;
}
}
/** @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 implement generate naive- dbus from XML file
* @returns status
*/
static int generateAttributesData()
{
// Open the bios.xml and parse it
// Extract the needed data and store it in AttributesData variable
// Close the bios.xml
phosphor::logging::log<phosphor::logging::level::ERR>(
"generateAttributesData");
tinyxml2::XMLDocument xmlDoc;
xmlDoc.LoadFile(biosXMLFilePath);
tinyxml2::XMLNode* pRoot = xmlDoc.FirstChild();
if (pRoot == nullptr)
{
return ipmi::ccUnspecifiedError;
}
tinyxml2::XMLElement* pElement = pRoot->FirstChildElement("biosknobs");
if (pElement == nullptr)
{
return ipmi::ccUnspecifiedError;
}
tinyxml2::XMLElement* pKnobsElement = pElement->FirstChildElement("knob");
while (pKnobsElement != nullptr)
{
bool readOnlyStatus = false;
std::string attrType =
"xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
std::string name, curvalue, dname, menupath, defaultvalue, description;
name = pKnobsElement->Attribute("name")
? pKnobsElement->Attribute("name")
: "";
curvalue = pKnobsElement->Attribute("CurrentVal")
? pKnobsElement->Attribute("CurrentVal")
: "";
dname = pKnobsElement->Attribute("prompt")
? pKnobsElement->Attribute("prompt")
: "";
menupath = pKnobsElement->Attribute("SetupPgPtr")
? pKnobsElement->Attribute("SetupPgPtr")
: "";
defaultvalue = pKnobsElement->Attribute("default")
? pKnobsElement->Attribute("default")
: "";
description = pKnobsElement->Attribute("description")
? pKnobsElement->Attribute("description")
: "";
if (!name.empty() && !curvalue.empty() && !dname.empty() &&
!menupath.empty() && !defaultvalue.empty())
{
std::string rootPath = "./" + std::string(menupath);
OptionType optionArray;
tinyxml2::XMLElement* pOptionsElement =
pKnobsElement->FirstChildElement("options");
nlohmann::json optionsArray = nlohmann::json::array();
if (pOptionsElement != nullptr)
{
tinyxml2::XMLElement* pOptionElement =
pOptionsElement->FirstChildElement("option");
while (pOptionElement != nullptr)
{
const std::string optType =
"xyz.openbmc_project.BIOSConfig.Manager.BoundType."
"OneOf";
const std::string attrValue =
pOptionElement->Attribute("value");
if (!optType.empty() && !attrValue.empty())
{
optionArray.push_back(
std::make_pair(optType, attrValue));
}
pOptionElement =
pOptionElement->NextSiblingElement("option");
}
}
attributesData.emplace(std::make_pair(
name, std::make_tuple(attrType, readOnlyStatus, dname,
description, rootPath, curvalue,
defaultvalue, optionArray)));
}
pKnobsElement = pKnobsElement->NextSiblingElement("knob");
}
return ipmi::ccSuccess;
}
/** @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 (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)
{
std::string OSState;
getSystemOSState(OSState);
if (OSState != "OperatingState" && 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))
{
std::string OSState;
getSystemOSState(OSState);
if (!IsSystemInterface(ctx) || OSState == "OperatingState")
{
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)
{
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");
response = generateAttributesData();
if (response)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"ipmiOEMSetPayload: generateAttributesData - failed");
gNVOOBdata.payloadInfo[payloadType].payloadStatus =
static_cast<uint8_t>(ipmi::PStatus::Corrupted);
return ipmi::responseResponseError();
}
phosphor::logging::log<phosphor::logging::level::INFO>(
" ipmiOEMSetPayload : BaseBIOSTable Property is set");
response = sendAllAttributes(ctx);
if (response)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"ipmiOEMSetPayload: sendAllAttributes - failed");
gNVOOBdata.payloadInfo[payloadType].payloadStatus =
static_cast<uint8_t>(ipmi::PStatus::Corrupted);
return ipmi::responseResponseError();
}
}
gNVOOBdata.payloadInfo[payloadType].payloadStatus =
static_cast<uint8_t>(ipmi::PStatus::Valid);
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;
}
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();
}
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);
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))
{
ifs.close();
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)
{
std::string OSState;
// We should support this command only in KCS Interface
if (!IsSystemInterface(ctx))
{
return ipmi::responseCommandNotAvailable();
}
getSystemOSState(OSState);
// We should not support this command after System Booted - After Exit Boot
// service called
if (OSState == "OperatingState")
{
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)
{
std::string OSState;
nlohmann::json data = nullptr;
// We should support this command only in KCS Interface
if (!IsSystemInterface(ctx))
{
return ipmi::responseCommandNotAvailable();
}
getSystemOSState(OSState);
// We should not support this command after System Booted - After Exit Boot
// service called
if (OSState != "OperatingState")
{
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