1 #pragma once 2 #include <tinyxml2.h> 3 4 #include <app.hpp> 5 #include <async_resp.hpp> 6 #include <boost/algorithm/string.hpp> 7 #include <boost/container/flat_set.hpp> 8 #include <error_messages.hpp> 9 #include <event_service_manager.hpp> 10 #include <ibm/locks.hpp> 11 #include <nlohmann/json.hpp> 12 #include <resource_messages.hpp> 13 #include <sdbusplus/message/types.hpp> 14 #include <utils/json_utils.hpp> 15 16 #include <filesystem> 17 #include <fstream> 18 19 using SType = std::string; 20 using SegmentFlags = std::vector<std::pair<std::string, uint32_t>>; 21 using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>; 22 using LockRequests = std::vector<LockRequest>; 23 using Rc = std::pair<bool, std::variant<uint32_t, LockRequest>>; 24 using RcGetLockList = 25 std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>; 26 using ListOfSessionIds = std::vector<std::string>; 27 namespace crow 28 { 29 namespace ibm_mc 30 { 31 constexpr const char* methodNotAllowedMsg = "Method Not Allowed"; 32 constexpr const char* resourceNotFoundMsg = "Resource Not Found"; 33 constexpr const char* contentNotAcceptableMsg = "Content Not Acceptable"; 34 constexpr const char* internalServerError = "Internal Server Error"; 35 36 constexpr size_t maxSaveareaDirSize = 37 10000000; // Allow save area dir size to be max 10MB 38 constexpr size_t minSaveareaFileSize = 39 100; // Allow save area file size of minimum 100B 40 constexpr size_t maxSaveareaFileSize = 41 500000; // Allow save area file size upto 500KB 42 constexpr size_t maxBroadcastMsgSize = 43 1000; // Allow Broadcast message size upto 1KB 44 45 inline bool createSaveAreaPath(crow::Response& res) 46 { 47 // The path /var/lib/obmc will be created by initrdscripts 48 // Create the directories for the save-area files, when we get 49 // first file upload request 50 std::error_code ec; 51 if (!std::filesystem::is_directory("/var/lib/obmc/bmc-console-mgmt", ec)) 52 { 53 std::filesystem::create_directory("/var/lib/obmc/bmc-console-mgmt", ec); 54 } 55 if (ec) 56 { 57 res.result(boost::beast::http::status::internal_server_error); 58 res.jsonValue["Description"] = internalServerError; 59 BMCWEB_LOG_DEBUG 60 << "handleIbmPost: Failed to prepare save-area directory. ec : " 61 << ec; 62 return false; 63 } 64 65 if (!std::filesystem::is_directory( 66 "/var/lib/obmc/bmc-console-mgmt/save-area", ec)) 67 { 68 std::filesystem::create_directory( 69 "/var/lib/obmc/bmc-console-mgmt/save-area", ec); 70 } 71 if (ec) 72 { 73 res.result(boost::beast::http::status::internal_server_error); 74 res.jsonValue["Description"] = internalServerError; 75 BMCWEB_LOG_DEBUG 76 << "handleIbmPost: Failed to prepare save-area directory. ec : " 77 << ec; 78 return false; 79 } 80 return true; 81 } 82 83 inline void handleFilePut(const crow::Request& req, crow::Response& res, 84 const std::string& fileID) 85 { 86 std::error_code ec; 87 // Check the content-type of the request 88 std::string_view contentType = req.getHeaderValue("content-type"); 89 if (boost::starts_with(contentType, "multipart/form-data")) 90 { 91 BMCWEB_LOG_DEBUG 92 << "This is multipart/form-data. Invalid content for PUT"; 93 94 res.result(boost::beast::http::status::not_acceptable); 95 res.jsonValue["Description"] = contentNotAcceptableMsg; 96 return; 97 } 98 BMCWEB_LOG_DEBUG << "Not a multipart/form-data. Continue.."; 99 100 BMCWEB_LOG_DEBUG 101 << "handleIbmPut: Request to create/update the save-area file"; 102 if (!createSaveAreaPath(res)) 103 { 104 res.result(boost::beast::http::status::not_found); 105 res.jsonValue["Description"] = resourceNotFoundMsg; 106 return; 107 } 108 109 std::ofstream file; 110 std::filesystem::path loc("/var/lib/obmc/bmc-console-mgmt/save-area"); 111 112 // Get the current size of the savearea directory 113 std::filesystem::recursive_directory_iterator iter(loc, ec); 114 if (ec) 115 { 116 res.result(boost::beast::http::status::internal_server_error); 117 res.jsonValue["Description"] = internalServerError; 118 BMCWEB_LOG_DEBUG << "handleIbmPut: Failed to prepare save-area " 119 "directory iterator. ec : " 120 << ec; 121 return; 122 } 123 std::uintmax_t saveAreaDirSize = 0; 124 for (auto& it : iter) 125 { 126 if (!std::filesystem::is_directory(it, ec)) 127 { 128 if (ec) 129 { 130 res.result(boost::beast::http::status::internal_server_error); 131 res.jsonValue["Description"] = internalServerError; 132 BMCWEB_LOG_DEBUG << "handleIbmPut: Failed to find save-area " 133 "directory . ec : " 134 << ec; 135 return; 136 } 137 std::uintmax_t fileSize = std::filesystem::file_size(it, ec); 138 if (ec) 139 { 140 res.result(boost::beast::http::status::internal_server_error); 141 res.jsonValue["Description"] = internalServerError; 142 BMCWEB_LOG_DEBUG << "handleIbmPut: Failed to find save-area " 143 "file size inside the directory . ec : " 144 << ec; 145 return; 146 } 147 saveAreaDirSize += fileSize; 148 } 149 } 150 BMCWEB_LOG_DEBUG << "saveAreaDirSize: " << saveAreaDirSize; 151 152 // Get the file size getting uploaded 153 const std::string& data = req.body; 154 BMCWEB_LOG_DEBUG << "data length: " << data.length(); 155 156 if (data.length() < minSaveareaFileSize) 157 { 158 res.result(boost::beast::http::status::bad_request); 159 res.jsonValue["Description"] = 160 "File size is less than minimum allowed size[100B]"; 161 return; 162 } 163 if (data.length() > maxSaveareaFileSize) 164 { 165 res.result(boost::beast::http::status::bad_request); 166 res.jsonValue["Description"] = 167 "File size exceeds maximum allowed size[500KB]"; 168 return; 169 } 170 171 // Form the file path 172 loc /= fileID; 173 BMCWEB_LOG_DEBUG << "Writing to the file: " << loc; 174 175 // Check if the same file exists in the directory 176 bool fileExists = std::filesystem::exists(loc, ec); 177 if (ec) 178 { 179 res.result(boost::beast::http::status::internal_server_error); 180 res.jsonValue["Description"] = internalServerError; 181 BMCWEB_LOG_DEBUG << "handleIbmPut: Failed to find if file exists. ec : " 182 << ec; 183 return; 184 } 185 186 std::uintmax_t newSizeToWrite = 0; 187 if (fileExists) 188 { 189 // File exists. Get the current file size 190 std::uintmax_t currentFileSize = std::filesystem::file_size(loc, ec); 191 if (ec) 192 { 193 res.result(boost::beast::http::status::internal_server_error); 194 res.jsonValue["Description"] = internalServerError; 195 BMCWEB_LOG_DEBUG << "handleIbmPut: Failed to find file size. ec : " 196 << ec; 197 return; 198 } 199 // Calculate the difference in the file size. 200 // If the data.length is greater than the existing file size, then 201 // calculate the difference. Else consider the delta size as zero - 202 // because there is no increase in the total directory size. 203 // We need to add the diff only if the incoming data is larger than the 204 // existing filesize 205 if (data.length() > currentFileSize) 206 { 207 newSizeToWrite = data.length() - currentFileSize; 208 } 209 BMCWEB_LOG_DEBUG << "newSizeToWrite: " << newSizeToWrite; 210 } 211 else 212 { 213 // This is a new file upload 214 newSizeToWrite = data.length(); 215 } 216 217 // Calculate the total dir size before writing the new file 218 BMCWEB_LOG_DEBUG << "total new size: " << saveAreaDirSize + newSizeToWrite; 219 220 if ((saveAreaDirSize + newSizeToWrite) > maxSaveareaDirSize) 221 { 222 res.result(boost::beast::http::status::bad_request); 223 res.jsonValue["Description"] = "File size does not fit in the savearea " 224 "directory maximum allowed size[10MB]"; 225 return; 226 } 227 228 file.open(loc, std::ofstream::out); 229 if (file.fail()) 230 { 231 BMCWEB_LOG_DEBUG << "Error while opening the file for writing"; 232 res.result(boost::beast::http::status::internal_server_error); 233 res.jsonValue["Description"] = "Error while creating the file"; 234 return; 235 } 236 file << data; 237 std::string origin = "/ibm/v1/Host/ConfigFiles/" + fileID; 238 // Push an event 239 if (fileExists) 240 { 241 BMCWEB_LOG_DEBUG << "config file is updated"; 242 res.jsonValue["Description"] = "File Updated"; 243 244 redfish::EventServiceManager::getInstance().sendEvent( 245 redfish::messages::resourceChanged(), origin, "IBMConfigFile"); 246 } 247 else 248 { 249 BMCWEB_LOG_DEBUG << "config file is created"; 250 res.jsonValue["Description"] = "File Created"; 251 252 redfish::EventServiceManager::getInstance().sendEvent( 253 redfish::messages::resourceCreated(), origin, "IBMConfigFile"); 254 } 255 } 256 257 inline void handleConfigFileList(crow::Response& res) 258 { 259 std::vector<std::string> pathObjList; 260 std::filesystem::path loc("/var/lib/obmc/bmc-console-mgmt/save-area"); 261 if (std::filesystem::exists(loc) && std::filesystem::is_directory(loc)) 262 { 263 for (const auto& file : std::filesystem::directory_iterator(loc)) 264 { 265 const std::filesystem::path& pathObj = file.path(); 266 pathObjList.push_back("/ibm/v1/Host/ConfigFiles/" + 267 pathObj.filename().string()); 268 } 269 } 270 res.jsonValue["@odata.type"] = "#IBMConfigFile.v1_0_0.IBMConfigFile"; 271 res.jsonValue["@odata.id"] = "/ibm/v1/Host/ConfigFiles/"; 272 res.jsonValue["Id"] = "ConfigFiles"; 273 res.jsonValue["Name"] = "ConfigFiles"; 274 275 res.jsonValue["Members"] = std::move(pathObjList); 276 res.jsonValue["Actions"]["#IBMConfigFiles.DeleteAll"] = { 277 {"target", 278 "/ibm/v1/Host/ConfigFiles/Actions/IBMConfigFiles.DeleteAll"}}; 279 res.end(); 280 } 281 282 inline void deleteConfigFiles(crow::Response& res) 283 { 284 std::vector<std::string> pathObjList; 285 std::error_code ec; 286 std::filesystem::path loc("/var/lib/obmc/bmc-console-mgmt/save-area"); 287 if (std::filesystem::exists(loc) && std::filesystem::is_directory(loc)) 288 { 289 std::filesystem::remove_all(loc, ec); 290 if (ec) 291 { 292 res.result(boost::beast::http::status::internal_server_error); 293 res.jsonValue["Description"] = internalServerError; 294 BMCWEB_LOG_DEBUG << "deleteConfigFiles: Failed to delete the " 295 "config files directory. ec : " 296 << ec; 297 } 298 } 299 res.end(); 300 } 301 302 inline void getLockServiceData(crow::Response& res) 303 { 304 res.jsonValue["@odata.type"] = "#LockService.v1_0_0.LockService"; 305 res.jsonValue["@odata.id"] = "/ibm/v1/HMC/LockService/"; 306 res.jsonValue["Id"] = "LockService"; 307 res.jsonValue["Name"] = "LockService"; 308 309 res.jsonValue["Actions"]["#LockService.AcquireLock"] = { 310 {"target", "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock"}}; 311 res.jsonValue["Actions"]["#LockService.ReleaseLock"] = { 312 {"target", "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock"}}; 313 res.jsonValue["Actions"]["#LockService.GetLockList"] = { 314 {"target", "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList"}}; 315 res.end(); 316 } 317 318 inline void handleFileGet(crow::Response& res, const std::string& fileID) 319 { 320 BMCWEB_LOG_DEBUG << "HandleGet on SaveArea files on path: " << fileID; 321 std::filesystem::path loc("/var/lib/obmc/bmc-console-mgmt/save-area/" + 322 fileID); 323 if (!std::filesystem::exists(loc)) 324 { 325 BMCWEB_LOG_ERROR << loc << "Not found"; 326 res.result(boost::beast::http::status::not_found); 327 res.jsonValue["Description"] = resourceNotFoundMsg; 328 return; 329 } 330 331 std::ifstream readfile(loc.string()); 332 if (!readfile) 333 { 334 BMCWEB_LOG_ERROR << loc.string() << "Not found"; 335 res.result(boost::beast::http::status::not_found); 336 res.jsonValue["Description"] = resourceNotFoundMsg; 337 return; 338 } 339 340 std::string contentDispositionParam = 341 "attachment; filename=\"" + fileID + "\""; 342 res.addHeader("Content-Disposition", contentDispositionParam); 343 std::string fileData; 344 fileData = {std::istreambuf_iterator<char>(readfile), 345 std::istreambuf_iterator<char>()}; 346 res.jsonValue["Data"] = fileData; 347 return; 348 } 349 350 inline void handleFileDelete(crow::Response& res, const std::string& fileID) 351 { 352 std::string filePath("/var/lib/obmc/bmc-console-mgmt/save-area/" + fileID); 353 BMCWEB_LOG_DEBUG << "Removing the file : " << filePath << "\n"; 354 355 std::ifstream fileOpen(filePath.c_str()); 356 if (static_cast<bool>(fileOpen)) 357 { 358 if (remove(filePath.c_str()) == 0) 359 { 360 BMCWEB_LOG_DEBUG << "File removed!\n"; 361 res.jsonValue["Description"] = "File Deleted"; 362 } 363 else 364 { 365 BMCWEB_LOG_ERROR << "File not removed!\n"; 366 res.result(boost::beast::http::status::internal_server_error); 367 res.jsonValue["Description"] = internalServerError; 368 } 369 } 370 else 371 { 372 BMCWEB_LOG_ERROR << "File not found!\n"; 373 res.result(boost::beast::http::status::not_found); 374 res.jsonValue["Description"] = resourceNotFoundMsg; 375 } 376 return; 377 } 378 379 inline void handleBroadcastService(const crow::Request& req, 380 crow::Response& res) 381 { 382 std::string broadcastMsg; 383 384 if (!redfish::json_util::readJson(req, res, "Message", broadcastMsg)) 385 { 386 BMCWEB_LOG_DEBUG << "Not a Valid JSON"; 387 res.result(boost::beast::http::status::bad_request); 388 return; 389 } 390 if (broadcastMsg.size() > maxBroadcastMsgSize) 391 { 392 BMCWEB_LOG_ERROR << "Message size exceeds maximum allowed size[1KB]"; 393 res.result(boost::beast::http::status::bad_request); 394 return; 395 } 396 redfish::EventServiceManager::getInstance().sendBroadcastMsg(broadcastMsg); 397 res.end(); 398 return; 399 } 400 401 inline void handleFileUrl(const crow::Request& req, crow::Response& res, 402 const std::string& fileID) 403 { 404 if (req.method() == boost::beast::http::verb::put) 405 { 406 handleFilePut(req, res, fileID); 407 res.end(); 408 return; 409 } 410 if (req.method() == boost::beast::http::verb::get) 411 { 412 handleFileGet(res, fileID); 413 res.end(); 414 return; 415 } 416 if (req.method() == boost::beast::http::verb::delete_) 417 { 418 handleFileDelete(res, fileID); 419 res.end(); 420 return; 421 } 422 } 423 424 inline void handleAcquireLockAPI(const crow::Request& req, crow::Response& res, 425 std::vector<nlohmann::json> body) 426 { 427 LockRequests lockRequestStructure; 428 for (auto& element : body) 429 { 430 std::string lockType; 431 uint64_t resourceId; 432 433 SegmentFlags segInfo; 434 std::vector<nlohmann::json> segmentFlags; 435 436 if (!redfish::json_util::readJson(element, res, "LockType", lockType, 437 "ResourceID", resourceId, 438 "SegmentFlags", segmentFlags)) 439 { 440 BMCWEB_LOG_DEBUG << "Not a Valid JSON"; 441 res.result(boost::beast::http::status::bad_request); 442 res.end(); 443 return; 444 } 445 BMCWEB_LOG_DEBUG << lockType; 446 BMCWEB_LOG_DEBUG << resourceId; 447 448 BMCWEB_LOG_DEBUG << "Segment Flags are present"; 449 450 for (auto& e : segmentFlags) 451 { 452 std::string lockFlags; 453 uint32_t segmentLength; 454 455 if (!redfish::json_util::readJson(e, res, "LockFlag", lockFlags, 456 "SegmentLength", segmentLength)) 457 { 458 res.result(boost::beast::http::status::bad_request); 459 res.end(); 460 return; 461 } 462 463 BMCWEB_LOG_DEBUG << "Lockflag : " << lockFlags; 464 BMCWEB_LOG_DEBUG << "SegmentLength : " << segmentLength; 465 466 segInfo.push_back(std::make_pair(lockFlags, segmentLength)); 467 } 468 lockRequestStructure.push_back( 469 make_tuple(req.session->uniqueId, req.session->clientId, lockType, 470 resourceId, segInfo)); 471 } 472 473 // print lock request into journal 474 475 for (auto& i : lockRequestStructure) 476 { 477 BMCWEB_LOG_DEBUG << std::get<0>(i); 478 BMCWEB_LOG_DEBUG << std::get<1>(i); 479 BMCWEB_LOG_DEBUG << std::get<2>(i); 480 BMCWEB_LOG_DEBUG << std::get<3>(i); 481 482 for (const auto& p : std::get<4>(i)) 483 { 484 BMCWEB_LOG_DEBUG << p.first << ", " << p.second; 485 } 486 } 487 488 const LockRequests& t = lockRequestStructure; 489 490 auto varAcquireLock = crow::ibm_mc_lock::Lock::getInstance().acquireLock(t); 491 492 if (varAcquireLock.first) 493 { 494 // Either validity failure of there is a conflict with itself 495 496 auto validityStatus = 497 std::get<std::pair<bool, int>>(varAcquireLock.second); 498 499 if ((!validityStatus.first) && (validityStatus.second == 0)) 500 { 501 BMCWEB_LOG_DEBUG << "Not a Valid record"; 502 BMCWEB_LOG_DEBUG << "Bad json in request"; 503 res.result(boost::beast::http::status::bad_request); 504 res.end(); 505 return; 506 } 507 if (validityStatus.first && (validityStatus.second == 1)) 508 { 509 BMCWEB_LOG_DEBUG << "There is a conflict within itself"; 510 res.result(boost::beast::http::status::bad_request); 511 res.end(); 512 return; 513 } 514 } 515 else 516 { 517 auto conflictStatus = 518 std::get<crow::ibm_mc_lock::Rc>(varAcquireLock.second); 519 if (!conflictStatus.first) 520 { 521 BMCWEB_LOG_DEBUG << "There is no conflict with the locktable"; 522 res.result(boost::beast::http::status::ok); 523 524 auto var = std::get<uint32_t>(conflictStatus.second); 525 nlohmann::json returnJson; 526 returnJson["id"] = var; 527 res.jsonValue["TransactionID"] = var; 528 res.end(); 529 return; 530 } 531 BMCWEB_LOG_DEBUG << "There is a conflict with the lock table"; 532 res.result(boost::beast::http::status::conflict); 533 auto var = 534 std::get<std::pair<uint32_t, LockRequest>>(conflictStatus.second); 535 nlohmann::json returnJson, segments; 536 nlohmann::json myarray = nlohmann::json::array(); 537 returnJson["TransactionID"] = var.first; 538 returnJson["SessionID"] = std::get<0>(var.second); 539 returnJson["HMCID"] = std::get<1>(var.second); 540 returnJson["LockType"] = std::get<2>(var.second); 541 returnJson["ResourceID"] = std::get<3>(var.second); 542 543 for (auto& i : std::get<4>(var.second)) 544 { 545 segments["LockFlag"] = i.first; 546 segments["SegmentLength"] = i.second; 547 myarray.push_back(segments); 548 } 549 550 returnJson["SegmentFlags"] = myarray; 551 552 res.jsonValue["Record"] = returnJson; 553 res.end(); 554 return; 555 } 556 } 557 inline void handleRelaseAllAPI(const crow::Request& req, crow::Response& res) 558 { 559 crow::ibm_mc_lock::Lock::getInstance().releaseLock(req.session->uniqueId); 560 res.result(boost::beast::http::status::ok); 561 res.end(); 562 return; 563 } 564 565 inline void 566 handleReleaseLockAPI(const crow::Request& req, crow::Response& res, 567 const std::vector<uint32_t>& listTransactionIds) 568 { 569 BMCWEB_LOG_DEBUG << listTransactionIds.size(); 570 BMCWEB_LOG_DEBUG << "Data is present"; 571 for (unsigned int listTransactionId : listTransactionIds) 572 { 573 BMCWEB_LOG_DEBUG << listTransactionId; 574 } 575 576 // validate the request ids 577 578 auto varReleaselock = crow::ibm_mc_lock::Lock::getInstance().releaseLock( 579 listTransactionIds, 580 std::make_pair(req.session->clientId, req.session->uniqueId)); 581 582 if (!varReleaselock.first) 583 { 584 // validation Failed 585 res.result(boost::beast::http::status::bad_request); 586 res.end(); 587 return; 588 } 589 auto statusRelease = 590 std::get<crow::ibm_mc_lock::RcRelaseLock>(varReleaselock.second); 591 if (statusRelease.first) 592 { 593 // The current hmc owns all the locks, so we already released 594 // them 595 res.result(boost::beast::http::status::ok); 596 res.end(); 597 return; 598 } 599 600 // valid rid, but the current hmc does not own all the locks 601 BMCWEB_LOG_DEBUG << "Current HMC does not own all the locks"; 602 res.result(boost::beast::http::status::unauthorized); 603 604 auto var = statusRelease.second; 605 nlohmann::json returnJson, segments; 606 nlohmann::json myArray = nlohmann::json::array(); 607 returnJson["TransactionID"] = var.first; 608 returnJson["SessionID"] = std::get<0>(var.second); 609 returnJson["HMCID"] = std::get<1>(var.second); 610 returnJson["LockType"] = std::get<2>(var.second); 611 returnJson["ResourceID"] = std::get<3>(var.second); 612 613 for (auto& i : std::get<4>(var.second)) 614 { 615 segments["LockFlag"] = i.first; 616 segments["SegmentLength"] = i.second; 617 myArray.push_back(segments); 618 } 619 620 returnJson["SegmentFlags"] = myArray; 621 res.jsonValue["Record"] = returnJson; 622 res.end(); 623 return; 624 } 625 626 inline void handleGetLockListAPI(crow::Response& res, 627 const ListOfSessionIds& listSessionIds) 628 { 629 BMCWEB_LOG_DEBUG << listSessionIds.size(); 630 631 auto status = 632 crow::ibm_mc_lock::Lock::getInstance().getLockList(listSessionIds); 633 auto var = std::get<std::vector<std::pair<uint32_t, LockRequests>>>(status); 634 635 nlohmann::json lockRecords = nlohmann::json::array(); 636 637 for (const auto& transactionId : var) 638 { 639 for (const auto& lockRecord : transactionId.second) 640 { 641 nlohmann::json returnJson; 642 643 returnJson["TransactionID"] = transactionId.first; 644 returnJson["SessionID"] = std::get<0>(lockRecord); 645 returnJson["HMCID"] = std::get<1>(lockRecord); 646 returnJson["LockType"] = std::get<2>(lockRecord); 647 returnJson["ResourceID"] = std::get<3>(lockRecord); 648 649 nlohmann::json segments; 650 nlohmann::json segmentInfoArray = nlohmann::json::array(); 651 652 for (const auto& segment : std::get<4>(lockRecord)) 653 { 654 segments["LockFlag"] = segment.first; 655 segments["SegmentLength"] = segment.second; 656 segmentInfoArray.push_back(segments); 657 } 658 659 returnJson["SegmentFlags"] = segmentInfoArray; 660 lockRecords.push_back(returnJson); 661 } 662 } 663 res.result(boost::beast::http::status::ok); 664 res.jsonValue["Records"] = lockRecords; 665 res.end(); 666 } 667 668 inline bool isValidConfigFileName(const std::string& fileName, 669 crow::Response& res) 670 { 671 if (fileName.empty()) 672 { 673 BMCWEB_LOG_ERROR << "Empty filename"; 674 res.jsonValue["Description"] = "Empty file path in the url"; 675 return false; 676 } 677 678 // ConfigFile name is allowed to take upper and lowercase letters, 679 // numbers and hyphen 680 std::size_t found = fileName.find_first_not_of( 681 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-"); 682 if (found != std::string::npos) 683 { 684 BMCWEB_LOG_ERROR << "Unsupported character in filename: " << fileName; 685 res.jsonValue["Description"] = "Unsupported character in filename"; 686 return false; 687 } 688 689 // Check the filename length 690 if (fileName.length() > 20) 691 { 692 BMCWEB_LOG_ERROR << "Name must be maximum 20 characters. " 693 "Input filename length is: " 694 << fileName.length(); 695 res.jsonValue["Description"] = "Filename must be maximum 20 characters"; 696 return false; 697 } 698 699 return true; 700 } 701 702 inline void requestRoutes(App& app) 703 { 704 705 // allowed only for admin 706 BMCWEB_ROUTE(app, "/ibm/v1/") 707 .privileges({"ConfigureComponents", "ConfigureManager"}) 708 .methods(boost::beast::http::verb::get)( 709 [](const crow::Request&, crow::Response& res) { 710 res.jsonValue["@odata.type"] = 711 "#ibmServiceRoot.v1_0_0.ibmServiceRoot"; 712 res.jsonValue["@odata.id"] = "/ibm/v1/"; 713 res.jsonValue["Id"] = "IBM Rest RootService"; 714 res.jsonValue["Name"] = "IBM Service Root"; 715 res.jsonValue["ConfigFiles"] = { 716 {"@odata.id", "/ibm/v1/Host/ConfigFiles"}}; 717 res.jsonValue["LockService"] = { 718 {"@odata.id", "/ibm/v1/HMC/LockService"}}; 719 res.jsonValue["BroadcastService"] = { 720 {"@odata.id", "/ibm/v1/HMC/BroadcastService"}}; 721 res.end(); 722 }); 723 724 BMCWEB_ROUTE(app, "/ibm/v1/Host/ConfigFiles") 725 .privileges({"ConfigureComponents", "ConfigureManager"}) 726 .methods(boost::beast::http::verb::get)( 727 [](const crow::Request&, crow::Response& res) { 728 handleConfigFileList(res); 729 }); 730 731 BMCWEB_ROUTE(app, 732 "/ibm/v1/Host/ConfigFiles/Actions/IBMConfigFiles.DeleteAll") 733 .privileges({"ConfigureComponents", "ConfigureManager"}) 734 .methods(boost::beast::http::verb::post)( 735 [](const crow::Request&, crow::Response& res) { 736 deleteConfigFiles(res); 737 }); 738 739 BMCWEB_ROUTE(app, "/ibm/v1/Host/ConfigFiles/<str>") 740 .privileges({"ConfigureComponents", "ConfigureManager"}) 741 .methods( 742 boost::beast::http::verb::put, boost::beast::http::verb::get, 743 boost::beast::http::verb::delete_)([](const crow::Request& req, 744 crow::Response& res, 745 const std::string& fileName) { 746 std::shared_ptr<bmcweb::AsyncResp> asyncResp = 747 std::make_shared<bmcweb::AsyncResp>(res); 748 BMCWEB_LOG_DEBUG << "ConfigFile : " << fileName; 749 // Validate the incoming fileName 750 if (!isValidConfigFileName(fileName, res)) 751 { 752 asyncResp->res.result(boost::beast::http::status::bad_request); 753 return; 754 } 755 handleFileUrl(req, res, fileName); 756 }); 757 758 BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService") 759 .privileges({"ConfigureComponents", "ConfigureManager"}) 760 .methods(boost::beast::http::verb::get)( 761 [](const crow::Request&, crow::Response& res) { 762 getLockServiceData(res); 763 }); 764 765 BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.AcquireLock") 766 .privileges({"ConfigureComponents", "ConfigureManager"}) 767 .methods(boost::beast::http::verb::post)( 768 [](const crow::Request& req, crow::Response& res) { 769 std::vector<nlohmann::json> body; 770 if (!redfish::json_util::readJson(req, res, "Request", body)) 771 { 772 BMCWEB_LOG_DEBUG << "Not a Valid JSON"; 773 res.result(boost::beast::http::status::bad_request); 774 res.end(); 775 return; 776 } 777 handleAcquireLockAPI(req, res, body); 778 }); 779 BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.ReleaseLock") 780 .privileges({"ConfigureComponents", "ConfigureManager"}) 781 .methods(boost::beast::http::verb::post)([](const crow::Request& req, 782 crow::Response& res) { 783 std::string type; 784 std::vector<uint32_t> listTransactionIds; 785 786 if (!redfish::json_util::readJson(req, res, "Type", type, 787 "TransactionIDs", 788 listTransactionIds)) 789 { 790 res.result(boost::beast::http::status::bad_request); 791 res.end(); 792 return; 793 } 794 if (type == "Transaction") 795 { 796 handleReleaseLockAPI(req, res, listTransactionIds); 797 } 798 else if (type == "Session") 799 { 800 handleRelaseAllAPI(req, res); 801 } 802 else 803 { 804 BMCWEB_LOG_DEBUG << " Value of Type : " << type 805 << "is Not a Valid key"; 806 redfish::messages::propertyValueNotInList(res, type, "Type"); 807 } 808 }); 809 BMCWEB_ROUTE(app, "/ibm/v1/HMC/LockService/Actions/LockService.GetLockList") 810 .privileges({"ConfigureComponents", "ConfigureManager"}) 811 .methods(boost::beast::http::verb::post)( 812 [](const crow::Request& req, crow::Response& res) { 813 ListOfSessionIds listSessionIds; 814 815 if (!redfish::json_util::readJson(req, res, "SessionIDs", 816 listSessionIds)) 817 { 818 res.result(boost::beast::http::status::bad_request); 819 res.end(); 820 return; 821 } 822 handleGetLockListAPI(res, listSessionIds); 823 }); 824 825 BMCWEB_ROUTE(app, "/ibm/v1/HMC/BroadcastService") 826 .privileges({"ConfigureComponents", "ConfigureManager"}) 827 .methods(boost::beast::http::verb::post)( 828 [](const crow::Request& req, crow::Response& res) { 829 handleBroadcastService(req, res); 830 }); 831 } 832 833 } // namespace ibm_mc 834 } // namespace crow 835