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