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