blob: 38b044c13a5ba78541296aeba92c19c510309ba9 [file] [log] [blame]
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +08001/*
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 <openssl/sha.h>
18#include <tinyxml2.h>
19
20#include <biosconfigcommands.hpp>
21#include <boost/crc.hpp>
22#include <boost/process/child.hpp>
23#include <boost/process/io.hpp>
24#include <ipmid/api.hpp>
25#include <ipmid/message.hpp>
26#include <ipmid/message/types.hpp>
27#include <ipmid/types.hpp>
28#include <ipmid/utils.hpp>
29#include <nlohmann/json.hpp>
30#include <oemcommands.hpp>
31#include <phosphor-logging/elog-errors.hpp>
32#include <phosphor-logging/log.hpp>
33#include <sdbusplus/bus.hpp>
34#include <sdbusplus/message/types.hpp>
35
36#include <filesystem>
37
38namespace ipmi
39{
40static void registerBIOSConfigFunctions() __attribute__((constructor));
41
42// Define BIOS config related Completion Code
43using Cc = uint8_t;
44static constexpr Cc ipmiCCPayloadPayloadPacketMissed = 0x80;
45static constexpr Cc ipmiCCBIOSPasswordInitNotDone = 0x80;
46static constexpr Cc ipmiCCPayloadChecksumFailed = 0x81;
47static constexpr Cc ipmiCCNotSupportedInCurrentState = 0x82;
48static constexpr Cc ipmiCCPayloadPayloadInComplete = 0x83;
49static constexpr Cc ipmiCCBIOSCapabilityInitNotDone = 0x85;
50static constexpr Cc ipmiCCPayloadLengthIllegal = 0x85;
51
52static constexpr uint8_t userPasswordChanged = (1 << 5);
53static constexpr uint8_t adminPasswordChanged = (1 << 4);
54
55static constexpr const char* biosConfigFolder = "/var/oob";
56static constexpr const char* biosConfigNVPath = "/var/oob/nvoobdata.dat";
57static constexpr const uint8_t algoSHA384 = 2;
58static constexpr const uint8_t biosCapOffsetBit = 0x3;
59static constexpr uint16_t maxGetPayloadDataSize = 4096;
60static constexpr const char* biosXMLFilePath = "/var/oob/bios.xml";
61static constexpr const char* biosXMLFilePath1 = "/var/oob/tempbios.xml";
62
63static constexpr const char* biosConfigBaseMgrPath =
64 "/xyz/openbmc_project/bios_config/manager";
65static constexpr const char* biosConfigIntf =
66 "xyz.openbmc_project.BIOSConfig.Manager";
67static constexpr const char* resetBIOSSettingsProp = "ResetBIOSSettings";
68/*baseBIOSTable
69map{attributeName,struct{attributeType,readonlyStatus,displayname,
70 description,menuPath,current,default,
71 array{struct{optionstring,optionvalue}}}}
72*/
73std::map<std::string,
74 std::tuple<std::string, bool, std::string, std::string, std::string,
75 std::variant<int64_t, std::string>,
76 std::variant<int64_t, std::string>,
77 std::map<std::string, std::variant<int64_t, std::string>>>>
78 AttributesData;
79
80NVOOBdata gNVOOBdata;
81
82enum class PTState : uint8_t
83{
84 StartTransfer = 0,
85 InProgress = 1,
86 EndTransfer = 2,
87 UserAbort = 3
88};
89enum class PStatus : uint8_t
90{
91 Unknown = 0,
92 Valid = 1,
93 Corrupted = 2
94};
95enum class PType : uint8_t
96{
97 IntelXMLType0 = 0,
98 IntelXMLType1 = 1,
99 OTAPayload = 5,
100};
101
102//
103// GetPayload Payload status enumeration
104//
105enum class GetPayloadParameter : uint8_t
106{
107 GetPayloadInfo = 0, // 0
108 GetPayloadData = 1, // 1
109 GetPayloadStatus = 2
110};
111
112/** @brief implement to set the BaseBIOSTable property
113 * @returns status
114 */
115static int sendAllAttributes(ipmi::Context::ptr ctx)
116{
117 boost::system::error_code ec;
118 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
119 std::string service =
120 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
121 ec.clear();
122 ctx->bus->yield_method_call<>(
123 ctx->yield, ec, service, biosConfigBaseMgrPath,
124 "org.freedesktop.DBus.Properties", "Set", biosConfigIntf,
125 "BaseBIOSTable", AttributesData);
126 if (ec)
127 {
128 phosphor::logging::log<phosphor::logging::level::ERR>(
129 "Failed to sendAllAttributes");
130 return -1;
131 }
132 return 0;
133}
134
135/** @brief implement to flush the updated data in nv space
136 * @returns status
137 */
138static uint8_t flushNVOOBdata()
139{
140 std::ofstream outFile(biosConfigNVPath, std::ios::binary | std::ios::app);
141 if (outFile.good())
142 {
143 outFile.seekp(std::ios_base::beg);
144 const char* writedata = reinterpret_cast<const char*>(&gNVOOBdata);
145 outFile.write(writedata, sizeof(struct NVOOBdata));
146 outFile.close();
147 }
148 return 0;
149}
150
151/** @brief implement to get the System State
152 * @returns status
153 */
154
155static int getSystemOSState(std::string& OsStatus)
156{
157
158 try
159 {
160 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
161 Value variant =
162 getDbusProperty(*dbus, "xyz.openbmc_project.State.OperatingSystem",
163 "/xyz/openbmc_project/state/os",
164 "xyz.openbmc_project.State.OperatingSystem.Status",
165 "OperatingSystemState");
166 OsStatus = std::get<std::string>(variant);
167 return ipmi::ccSuccess;
168 }
169 catch (const std::exception& e)
170 {
171 return ipmi::ccUnspecifiedError;
172 }
173}
174
175/** @brief implement to get the Rest BIOS property
176 * @returns status
177 */
178static int getResetBIOSSettings(uint8_t& ResetFlag)
179{
180
181 try
182 {
183 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
184 std::string service =
185 getService(*dbus, biosConfigIntf, biosConfigBaseMgrPath);
186 Value variant = getDbusProperty(*dbus, service, biosConfigBaseMgrPath,
187 biosConfigIntf, resetBIOSSettingsProp);
188 ResetFlag = static_cast<uint8_t>(std::get<std::uint8_t>(variant));
189 return ipmi::ccSuccess;
190 }
191 catch (const std::exception& e)
192 {
193 return ipmi::ccUnspecifiedError;
194 }
195}
196
197/** @brief implement generate naive- dbus from XML file
198 * @returns status
199 */
200static int generateAttributesData()
201{
202 // Open the bios.xml and parse it
203 // Extract the needed data and store it in AttributesData variable
204 // Close the bios.xml
205 phosphor::logging::log<phosphor::logging::level::ERR>(
206 "generateAttributesData");
207 tinyxml2::XMLDocument xmlDoc;
208
209 xmlDoc.LoadFile(biosXMLFilePath);
210 tinyxml2::XMLNode* pRoot = xmlDoc.FirstChild();
211 if (pRoot == nullptr)
212 {
213 return 0;
214 }
215 tinyxml2::XMLElement* pElement = pRoot->FirstChildElement("biosknobs");
216 if (pElement == nullptr)
217 {
218 return 0;
219 }
220 tinyxml2::XMLElement* pKnobsElement = pElement->FirstChildElement("knob");
221
222 while (pKnobsElement != nullptr)
223 {
224 bool readOnlyStatus = false;
225 std::string attrType =
226 "xyz.openbmc_project.BIOSConfig.Manager.AttributeType.String";
227 std::string name, curvalue, dname, menupath, defaultvalue, description;
228 name = pKnobsElement->Attribute("name")
229 ? pKnobsElement->Attribute("name")
230 : "";
231 curvalue = pKnobsElement->Attribute("CurrentVal")
232 ? pKnobsElement->Attribute("CurrentVal")
233 : "";
234 dname = pKnobsElement->Attribute("prompt")
235 ? pKnobsElement->Attribute("prompt")
236 : "";
237 menupath = pKnobsElement->Attribute("SetupPgPtr")
238 ? pKnobsElement->Attribute("SetupPgPtr")
239 : "";
240 defaultvalue = pKnobsElement->Attribute("default")
241 ? pKnobsElement->Attribute("default")
242 : "";
243 description = pKnobsElement->Attribute("description")
244 ? pKnobsElement->Attribute("description")
245 : "";
246 phosphor::logging::log<phosphor::logging::level::INFO>(name.c_str());
247 if (!name.empty() && !curvalue.empty() && !dname.empty() &&
248 !menupath.empty() && !defaultvalue.empty())
249 {
250 std::string rootPath = "./" + std::string(menupath);
251
252 std::map<std::string, std::variant<int64_t, std::string>> optionMap;
253 tinyxml2::XMLElement* pOptionsElement =
254 pKnobsElement->FirstChildElement("options");
255 nlohmann::json optionsArray = nlohmann::json::array();
256 if (pOptionsElement != nullptr)
257 {
258 tinyxml2::XMLElement* pOptionElement =
259 pOptionsElement->FirstChildElement("option");
260 while (pOptionElement != nullptr)
261 {
262 const std::string text = pOptionElement->Attribute("text");
263 const std::string attrValue =
264 pOptionElement->Attribute("value");
265 if (!text.empty() && !attrValue.empty())
266 {
267
268 optionMap.emplace(std::make_pair(std::move(text),
269 std::move(attrValue)));
270 }
271 pOptionElement =
272 pOptionElement->NextSiblingElement("option");
273 }
274 }
275
276 AttributesData.emplace(std::make_pair(
277 name,
278 std::make_tuple(attrType, readOnlyStatus, dname, description,
279 rootPath, curvalue, defaultvalue, optionMap)));
280 }
281 pKnobsElement = pKnobsElement->NextSiblingElement("knob");
282 }
283
284 return 0;
285}
286
287/** @brief implement executing the linux command to uncompress and generate the
288 * xmlfile
289 * @param[in] linux command
290 * @returns status
291 */
292template <typename... ArgTypes>
293static int generateBIOSXMLFile(const char* path, ArgTypes&&... tArgs)
294{
295
296 boost::process::child execProg(path, const_cast<char*>(tArgs)...,
297 boost::process::std_out > biosXMLFilePath);
298 execProg.wait();
299 return execProg.exit_code();
300}
301
302/** @brief implements to clean up the temp/ existing payload file
303 **/
304static void cleanUpPayloadFile(uint8_t& payloadType)
305{
306 // Clear the payload Information
307 std::string FilePath = "/var/oob/temp" + std::to_string(payloadType);
308 unlink(FilePath.c_str());
309 FilePath = "/var/oob/Payload" + std::to_string(payloadType);
310 unlink(FilePath.c_str());
311 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
312 {
313 unlink("/var/oob/Payload1");
314 gNVOOBdata.payloadInfo[static_cast<uint8_t>(ipmi::PType::IntelXMLType1)]
315 .payloadStatus = static_cast<uint8_t>(ipmi::PStatus::Unknown);
316 }
317}
318
319/** @brief implements to create the oob folders and nv space
320 **/
321static Cc InitNVOOBdata()
322{
323 FILE* fptr;
324 uint16_t size;
325
326 if (!(std::filesystem::exists(biosConfigFolder)))
327 {
328 std::filesystem::create_directory(biosConfigFolder);
329 }
330
331 std::ifstream ifs(biosConfigNVPath,
332 std::ios::in | std::ios::binary | std::ios::ate);
333
334 if (ifs.good())
335 {
336
337 ifs.read(reinterpret_cast<char*>(&gNVOOBdata),
338 sizeof(struct NVOOBdata));
339 ifs.close();
340 return ipmi::ccSuccess;
341 }
342 return ipmi::ccResponseError;
343}
344
345/** @brief implements check the command interface is
346 ** system interface or not
347 ** true mean System interface and false mean LAN or IPMB
348 **/
349static bool IsSystemInterface(ipmi::Context::ptr ctx)
350{
351 ChannelInfo chInfo;
352 Cc status = false;
353
354 try
355 {
356 getChannelInfo(ctx->channel, chInfo);
357 }
358 catch (sdbusplus::exception_t& e)
359 {
360 return false;
361 }
362 if (chInfo.mediumType !=
363 static_cast<uint8_t>(EChannelMediumType::systemInterface))
364 {
365 return false;
366 }
367 return true;
368}
369
370ipmi::RspType<> ipmiOEMSetBIOSCap(ipmi::Context::ptr ctx,
371 uint8_t BIOSCapabilties, uint8_t reserved1,
372 uint8_t reserved2, uint8_t reserved3)
373{
374 std::string OSState;
375 getSystemOSState(OSState);
376
377 if (OSState != "OperatingState" && IsSystemInterface(ctx))
378 {
379 if (reserved1 != 0 || reserved2 != 0 || reserved3 != 0)
380 {
381 return ipmi::responseInvalidFieldRequest();
382 }
383
384 gNVOOBdata.mBIOSCapabilities.OOBCapability = BIOSCapabilties;
385 gNVOOBdata.mIsBIOSCapInitDone = true;
386
387 flushNVOOBdata();
388 return ipmi::responseSuccess();
389 }
390 else
391 {
392
393 return ipmi::response(ipmiCCNotSupportedInCurrentState);
394 }
395}
396
397ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t>
398 ipmiOEMGetBIOSCap(ipmi::Context::ptr ctx)
399{
400 if (gNVOOBdata.mIsBIOSCapInitDone)
401 {
402 return ipmi::responseSuccess(gNVOOBdata.mBIOSCapabilities.OOBCapability,
403 0, 0, 0);
404 }
405 else
406 {
407 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
408 }
409}
410
411ipmi::RspType<uint32_t> ipmiOEMSetPayload(ipmi::Context::ptr ctx,
412 uint8_t paramSel, uint8_t payloadType,
413 std::vector<uint8_t> payload)
414{
415 uint8_t biosCapOffsetBit = 2; // BIT:1 0-OOB BIOS config not supported
416 // 1-OOB BIOS config is supported
417
418 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
419 {
420 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
421 }
422 // Validate the Payload Type
423 if (payloadType > maxPayloadSupported)
424 {
425 return ipmi::responseInvalidFieldRequest();
426 }
427
428 // We should support this Payload type 0 command only in KCS Interface
429 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
430 {
431 std::string OSState;
432
433 getSystemOSState(OSState);
434 if (!IsSystemInterface(ctx) || OSState == "OperatingState")
435 {
436 return ipmi::responseCommandNotAvailable();
437 }
438 }
439
440 switch (static_cast<PTState>(paramSel))
441 {
442 case ipmi::PTState::StartTransfer:
443 {
444 PayloadStartTransfer* pPayloadStartTransfer =
445 reinterpret_cast<PayloadStartTransfer*>(payload.data());
446 if (payload.size() < sizeof(PayloadStartTransfer))
447 {
448 phosphor::logging::log<phosphor::logging::level::ERR>(
449 "ipmiOEMSetPayload: BIOS Config Payload size is not "
450 "correct");
451 return ipmi::responseReqDataLenInvalid();
452 }
453 cleanUpPayloadFile(payloadType);
454
455 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = rand();
456 gNVOOBdata.payloadInfo[payloadType].payloadTotalChecksum =
457 pPayloadStartTransfer->payloadTotalChecksum;
458 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
459 pPayloadStartTransfer->payloadTotalSize;
460 gNVOOBdata.payloadInfo[payloadType].payloadVersion =
461 pPayloadStartTransfer->payloadVersion;
462 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten = 0;
463 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
464 static_cast<uint8_t>(ipmi::PStatus::Unknown);
465
466 return ipmi::responseSuccess(
467 gNVOOBdata.payloadInfo[payloadType].payloadReservationID);
468 }
469 break;
470
471 case ipmi::PTState::InProgress:
472 {
473 PayloadInProgress* pPayloadInProgress =
474 reinterpret_cast<PayloadInProgress*>(payload.data());
475 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
476
477 if (payload.size() < sizeof(PayloadInProgress))
478 {
479 phosphor::logging::log<phosphor::logging::level::ERR>(
480 "BIOS Config Payload size is not correct");
481 return ipmi::responseReqDataLenInvalid();
482 }
483
484 if (pPayloadInProgress->payloadReservationID !=
485 payloadInfo.payloadReservationID)
486 {
487 return ipmi::responseInvalidReservationId();
488 }
489 payloadInfo.payloadCurrentSize =
490 pPayloadInProgress->payloadCurrentSize;
491 // Need to verify the current Payload Checksum
492 const uint8_t* data =
493 reinterpret_cast<const uint8_t*>(payload.data());
494 // we have to remove the current size, current offset, current
495 // length,checksum bytes , reservation bytes
496 boost::crc_32_type calcChecksum;
497 calcChecksum.process_bytes(data + 16, payload.size() - 16);
498 if (calcChecksum.checksum() !=
499 pPayloadInProgress->payloadCurrentChecksum)
500 {
501 phosphor::logging::log<phosphor::logging::level::ERR>(
502 "ipmiOEMSetPayload: Payload Checksum Failed");
503 return ipmi::response(ipmiCCPayloadChecksumFailed);
504 }
505 // store the data in temp file
506 std::string FilePath =
507 "/var/oob/temp" + std::to_string(payloadType);
508
509 std::ofstream outFile(FilePath, std::ios::binary | std::ios::app);
510 outFile.seekp(pPayloadInProgress->payloadOffset);
511 // we have to remove the current size, current offset, current
512 // length,checksum bytes , reservation bytes
513
514 const char* writedata =
515 reinterpret_cast<const char*>(payload.data());
516 outFile.write(writedata + 16, payload.size() - 16);
517 outFile.close();
518
519 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
520 static_cast<uint8_t>(ipmi::PStatus::Unknown);
521 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten +=
522 payloadInfo.payloadCurrentSize;
523 return ipmi::responseSuccess(payloadInfo.payloadCurrentSize);
524 }
525 break;
526 case ipmi::PTState::EndTransfer:
527 {
528 PayloadEndTransfer* pPayloadEndTransfer =
529 reinterpret_cast<PayloadEndTransfer*>(payload.data());
530 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
531 if (pPayloadEndTransfer->payloadReservationID !=
532 payloadInfo.payloadReservationID)
533 {
534 return ipmi::responseInvalidReservationId();
535 }
536 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
537 static_cast<uint8_t>(ipmi::PStatus::Unknown);
538
539 if (gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten !=
540 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize)
541 {
542
543 return ipmi::response(ipmiCCPayloadPayloadInComplete);
544 }
545 std::string tempFilePath =
546 "/var/oob/temp" + std::to_string(payloadType);
547 std::string PayloadFilePath =
548 "/var/oob/Payload" + std::to_string(payloadType);
549 auto renamestatus =
550 std::rename(tempFilePath.c_str(), PayloadFilePath.c_str());
551 if (renamestatus)
552 {
553 phosphor::logging::log<phosphor::logging::level::ERR>(
554 "ipmiOEMSetPayload: Renaming Payload file - failed");
555 }
556
557 gNVOOBdata.payloadInfo[payloadType].payloadFilePath =
558 PayloadFilePath;
559 if (payloadType == static_cast<uint8_t>(ipmi::PType::IntelXMLType0))
560 {
561 // Unzip the Intel format XML file type 0
562 auto response = generateBIOSXMLFile("/usr/bin/lzcat", "-d",
563 PayloadFilePath.c_str());
564 if (response)
565 {
566
567 phosphor::logging::log<phosphor::logging::level::ERR>(
568 "ipmiOEMSetPayload: generateBIOSXMLFile - failed");
569 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
570 static_cast<uint8_t>(ipmi::PStatus::Corrupted);
571 return ipmi::response(ipmiCCPayloadPayloadPacketMissed);
572 }
573 }
574 gNVOOBdata.payloadInfo[payloadType].payloadStatus =
575 static_cast<uint8_t>(ipmi::PStatus::Valid);
576
577 struct stat filestat;
578
579 /* Get entry's information. */
580 if (!stat(PayloadFilePath.c_str(), &filestat))
581 {
582 gNVOOBdata.payloadInfo[payloadType].payloadTimeStamp =
583 filestat.st_mtime;
584 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize =
585 filestat.st_size;
586 gNVOOBdata.payloadInfo[payloadType].payloadFilePath =
587 PayloadFilePath;
588 }
589 else
590 {
591 return ipmi::responseResponseError();
592 }
593
594 phosphor::logging::log<phosphor::logging::level::INFO>(
595 " ipmiOEMSetPayload : Convert XML into native-dbus DONE");
596 generateAttributesData();
597
598 phosphor::logging::log<phosphor::logging::level::INFO>(
599 " ipmiOEMSetPayload : BaseBIOSTable Property is set");
600 sendAllAttributes(ctx);
601
602 flushNVOOBdata();
603 return ipmi::responseSuccess(
604 gNVOOBdata.payloadInfo[payloadType].actualTotalPayloadWritten);
605 }
606 break;
607 case ipmi::PTState::UserAbort:
608 {
609 PayloadEndTransfer* pPayloadEndTransfer =
610 reinterpret_cast<PayloadEndTransfer*>(payload.data());
611 PayloadInfo payloadInfo = gNVOOBdata.payloadInfo[payloadType];
612 if (pPayloadEndTransfer->payloadReservationID !=
613 payloadInfo.payloadReservationID)
614 {
615 return ipmi::responseInvalidReservationId();
616 }
617 gNVOOBdata.payloadInfo[payloadType].payloadReservationID = 0;
618 gNVOOBdata.payloadInfo[payloadType].payloadType = 0;
619 gNVOOBdata.payloadInfo[payloadType].payloadTotalSize = 0;
620 // Delete the temp file
621 std::string tempFilePath =
622 "/var/oob/temp" + std::to_string(payloadType);
623 unlink(tempFilePath.c_str());
624 flushNVOOBdata();
625 return ipmi::responseSuccess();
626 }
627 break;
628 default:
629 return ipmi::responseInvalidFieldRequest();
630 }
631 return ipmi::responseResponseError();
632}
633
634ipmi::RspType<message::Payload>
635 ipmiOEMGetPayload(ipmi::Context::ptr ctx, uint8_t paramSel,
636 uint8_t payloadType, ipmi::message::Payload& payload)
637{
638 // 1-OOB BIOS config is supported
639 message::Payload retValue;
640
641 if (!(gNVOOBdata.mBIOSCapabilities.OOBCapability & (biosCapOffsetBit)))
642 {
643 return ipmi::response(ipmiCCBIOSCapabilityInitNotDone);
644 }
645 // Validate the Payload Type
646 if (payloadType > maxPayloadSupported)
647 {
648 return ipmi::responseInvalidFieldRequest();
649 }
650
651 struct PayloadInfo res = gNVOOBdata.payloadInfo[payloadType];
652
653 switch (static_cast<GetPayloadParameter>(paramSel))
654 {
655 case ipmi::GetPayloadParameter::GetPayloadInfo:
656 {
657 retValue.pack(res.payloadVersion);
658 retValue.pack(res.payloadType);
659 retValue.pack(res.payloadTotalSize);
660 retValue.pack(res.payloadTotalChecksum);
661 retValue.pack(res.payloadflag);
662 retValue.pack(res.payloadStatus);
663 retValue.pack(res.payloadTimeStamp);
664
665 return ipmi::responseSuccess(std::move(retValue));
666 }
667
668 break;
669 case ipmi::GetPayloadParameter::GetPayloadData:
670 {
671 if (res.payloadStatus ==
672 (static_cast<uint8_t>(ipmi::PStatus::Valid)))
673 {
674 std::vector<uint32_t> reqData;
675 if (payload.unpack(reqData) || !payload.fullyUnpacked())
676 {
677 return ipmi::responseReqDataLenInvalid();
678 }
679 uint32_t offset = reqData.at(0);
680 uint32_t length = reqData.at(1);
681
682 std::ifstream ifs(res.payloadFilePath, std::ios::in |
683 std::ios::binary |
684 std::ios::ate);
685 std::ifstream::pos_type fileSize = ifs.tellg();
686 // Total file data within given offset
687 if (fileSize < static_cast<uint64_t>(offset))
688 {
689 ifs.close();
690 return ipmi::responseInvalidFieldRequest();
691 }
692
693 ifs.seekg(offset, std::ios::beg);
694 std::array<uint8_t, maxGetPayloadDataSize> Buffer;
695 ifs.read(reinterpret_cast<char*>(Buffer.data()), length);
696 uint32_t readCount = ifs.gcount();
697 ifs.close();
698
699 boost::crc_32_type calcChecksum;
700 calcChecksum.process_bytes(
701 reinterpret_cast<char*>(Buffer.data()), readCount);
702 uint32_t chkSum = calcChecksum.checksum();
703 retValue.pack(payloadType);
704 retValue.pack(readCount);
705 retValue.pack(chkSum);
706
707 for (int i = 0; i < readCount; i++)
708 {
709 retValue.pack(Buffer.at(i));
710 }
711 return ipmi::responseSuccess(std::move(retValue));
712 }
713 else
714 {
715 return ipmi::responseResponseError();
716 }
717 }
718 break;
719 case ipmi::GetPayloadParameter::GetPayloadStatus:
720 {
721 retValue.pack(gNVOOBdata.payloadInfo[payloadType].payloadStatus);
722 return ipmi::responseSuccess(std::move(retValue));
723 }
724 break;
725 default:
726 return ipmi::responseInvalidFieldRequest();
727 }
728 return ipmi::responseInvalidFieldRequest();
729}
730
731ipmi::RspType<> ipmiOEMSetBIOSHashInfo(
732 ipmi::Context::ptr ctx, std::array<uint8_t, maxSeedSize>& pwdSeed,
733 uint8_t algoInfo, std::array<uint8_t, maxHashSize>& adminPwdHash,
734 std::array<uint8_t, maxHashSize>& userPwdHash)
735{
736
737 std::string OSState;
738
739 // We should support this command only in KCS Interface
740 if (!IsSystemInterface(ctx))
741 {
742 return ipmi::responseCommandNotAvailable();
743 }
744 getSystemOSState(OSState);
745 // We should not support this command after System Booted - After Exit Boot
746 // service called
747
748 if (OSState != "OperatingState")
749 {
750
Suryakanth Sekarf4866952021-02-25 16:06:57 +0530751 if ((algoInfo & 0xF) != algoSHA384)
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800752 {
753 // Atpresent, we are supporting only SHA384- HASH algo in BIOS side
754 return ipmi::responseInvalidFieldRequest();
755 }
756 std::string HashFilePath = "/var/lib/bios-settings-manager/seedData";
757
758 nlohmann::json json;
759 json["Seed"] = pwdSeed;
760 json["HashAlgo"] = "SHA384";
761 json["IsAdminPwdChanged"] = false;
762 json["AdminPwdHash"] = adminPwdHash;
763 json["IsUserPwdChanged"] = false;
764 json["UserPwdHash"] = userPwdHash;
Suryakanth Sekarf4866952021-02-25 16:06:57 +0530765 json["StatusFlag"] = algoInfo;
Kuiying Wang6d6dc7a2020-04-02 10:15:19 +0800766 std::ofstream ofs(HashFilePath, std::ios::out);
767 const auto& writeData = json.dump();
768 ofs << writeData;
769 ofs.close();
770 return ipmi::responseSuccess();
771 }
772 else
773 {
774
775 return ipmi::response(ipmiCCNotSupportedInCurrentState);
776 }
777}
778
779ipmi::RspType<uint8_t, std::array<uint8_t, maxHashSize>,
780 std::array<uint8_t, maxHashSize>>
781 ipmiOEMGetBIOSHash(ipmi::Context::ptr ctx)
782{
783
784 std::string OSState;
785 nlohmann::json data = nullptr;
786
787 // We should support this command only in KCS Interface
788 if (!IsSystemInterface(ctx))
789 {
790 return ipmi::responseCommandNotAvailable();
791 }
792
793 getSystemOSState(OSState);
794 // We should not support this command after System Booted - After Exit Boot
795 // service called
796
797 if (OSState != "OperatingState")
798 {
799 std::string HashFilePath =
800 "/var/lib/bios-settings-manager/passwordData";
801
802 std::ifstream devIdFile(HashFilePath);
803 if (devIdFile.is_open())
804 {
805
806 try
807 {
808 data = nlohmann::json::parse(devIdFile, nullptr, false);
809 }
810 catch (const nlohmann::json::parse_error& e)
811 {
812 return ipmi::responseResponseError();
813 }
814
815 if (data.is_discarded())
816 {
817 return ipmi::responseResponseError();
818 }
819
820 std::array<uint8_t, maxHashSize> newAdminHash;
821 std::array<uint8_t, maxHashSize> newUserHash;
822 uint8_t flag = 0;
823 uint8_t adminPwdChangedFlag = 0;
824 uint8_t userPwdChangedFlag = 0;
825 if (!data.is_discarded())
826 {
827
828 adminPwdChangedFlag = data["IsAdminPwdChanged"];
829 newAdminHash = data["AdminPwdHash"];
830 newUserHash = data["UserPwdHash"];
831 userPwdChangedFlag = data["IsUserPwdChanged"];
832 }
833
834 // 0: BIT 4 - New Admin Password Not Present
835 // 1: BIT 4 - New Admin Password Hash Present
836 // 0: BIT 5 - New User Password Not Present
837 // 1: BIT 5 - New User Password Hash Present
838 // 0: BIT 0 - Default Setting flag is not set
839 // 1: BIT 0 - Default Setting flag is set
840 auto status = getResetBIOSSettings(flag);
841 if (status)
842 {
843 return ipmi::responseResponseError();
844 }
845 if (adminPwdChangedFlag)
846 {
847 flag |= adminPasswordChanged;
848 }
849 if (userPwdChangedFlag)
850 {
851 flag |= userPasswordChanged;
852 }
853
854 std::copy(std::begin(newAdminHash), std::end(newAdminHash),
855 std::begin(newAdminHash));
856 std::copy(std::begin(newUserHash), std::end(newUserHash),
857 std::begin(newUserHash));
858 return ipmi::responseSuccess(flag, newAdminHash, newUserHash);
859 }
860 else
861 {
862 return ipmi::responseResponseError();
863 }
864 }
865 else
866 {
867
868 return ipmi::response(ipmiCCNotSupportedInCurrentState);
869 }
870}
871
872static void registerBIOSConfigFunctions(void)
873{
874 phosphor::logging::log<phosphor::logging::level::INFO>(
875 "BIOSConfig module initialization");
876 InitNVOOBdata();
877
878 registerHandler(prioOemBase, intel::netFnGeneral,
879 intel::general::cmdSetBIOSCap, Privilege::Admin,
880 ipmiOEMSetBIOSCap);
881
882 registerHandler(prioOemBase, intel::netFnGeneral,
883 intel::general::cmdGetBIOSCap, Privilege::User,
884 ipmiOEMGetBIOSCap);
885 registerHandler(prioOemBase, intel::netFnGeneral,
886 intel::general::cmdSetBIOSPwdHashInfo, Privilege::Admin,
887 ipmiOEMSetBIOSHashInfo);
888
889 registerHandler(prioOemBase, intel::netFnGeneral,
890 intel::general::cmdGetBIOSPwdHash, Privilege::User,
891 ipmiOEMGetBIOSHash);
892
893 registerHandler(prioOemBase, intel::netFnGeneral,
894 intel::general::cmdGetPayload, Privilege::User,
895 ipmiOEMGetPayload);
896 registerHandler(prioOemBase, intel::netFnGeneral,
897 intel::general::cmdSetPayload, Privilege::Admin,
898 ipmiOEMSetPayload);
899
900 return;
901}
902
903} // namespace ipmi