1107077deSPrzemyslaw Czarnowski /* 2107077deSPrzemyslaw Czarnowski // Copyright (c) 2018 Intel Corporation 3107077deSPrzemyslaw Czarnowski // 4107077deSPrzemyslaw Czarnowski // Licensed under the Apache License, Version 2.0 (the "License"); 5107077deSPrzemyslaw Czarnowski // you may not use this file except in compliance with the License. 6107077deSPrzemyslaw Czarnowski // You may obtain a copy of the License at 7107077deSPrzemyslaw Czarnowski // 8107077deSPrzemyslaw Czarnowski // http://www.apache.org/licenses/LICENSE-2.0 9107077deSPrzemyslaw Czarnowski // 10107077deSPrzemyslaw Czarnowski // Unless required by applicable law or agreed to in writing, software 11107077deSPrzemyslaw Czarnowski // distributed under the License is distributed on an "AS IS" BASIS, 12107077deSPrzemyslaw Czarnowski // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13107077deSPrzemyslaw Czarnowski // See the License for the specific language governing permissions and 14107077deSPrzemyslaw Czarnowski // limitations under the License. 15107077deSPrzemyslaw Czarnowski */ 16107077deSPrzemyslaw Czarnowski #pragma once 17107077deSPrzemyslaw Czarnowski 187e860f15SJohn Edward Broadbent #include <app.hpp> 19107077deSPrzemyslaw Czarnowski #include <boost/container/flat_map.hpp> 20988fb7b2SAdrian Ambrożewicz #include <boost/process/async_pipe.hpp> 21988fb7b2SAdrian Ambrożewicz #include <boost/type_traits/has_dereference.hpp> 22107077deSPrzemyslaw Czarnowski #include <utils/json_utils.hpp> 23107077deSPrzemyslaw Czarnowski // for GetObjectType and ManagedObjectType 24ed398213SEd Tanous 25e13c2760SPrzemyslaw Czarnowski #include <account_service.hpp> 269e319cf0SAnna Platash #include <boost/url/url_view.hpp> 27ed398213SEd Tanous #include <registries/privilege_registry.hpp> 28107077deSPrzemyslaw Czarnowski 29107077deSPrzemyslaw Czarnowski namespace redfish 30107077deSPrzemyslaw Czarnowski { 319e319cf0SAnna Platash /** 329e319cf0SAnna Platash * @brief Function extracts transfer protocol name from URI. 339e319cf0SAnna Platash */ 3422db1728SEd Tanous inline std::string getTransferProtocolTypeFromUri(const std::string& imageUri) 359e319cf0SAnna Platash { 36d32c4fa9SEd Tanous boost::urls::error_code ec; 37d32c4fa9SEd Tanous boost::urls::url_view url = 38d32c4fa9SEd Tanous boost::urls::parse_uri(boost::string_view(imageUri), ec); 39d32c4fa9SEd Tanous if (ec) 409e319cf0SAnna Platash { 41d32c4fa9SEd Tanous return "None"; 42d32c4fa9SEd Tanous } 43d32c4fa9SEd Tanous boost::string_view scheme = url.scheme(); 449e319cf0SAnna Platash if (scheme == "smb") 459e319cf0SAnna Platash { 469e319cf0SAnna Platash return "CIFS"; 479e319cf0SAnna Platash } 4822db1728SEd Tanous if (scheme == "https") 499e319cf0SAnna Platash { 509e319cf0SAnna Platash return "HTTPS"; 519e319cf0SAnna Platash } 52d32c4fa9SEd Tanous 539e319cf0SAnna Platash return "None"; 549e319cf0SAnna Platash } 55107077deSPrzemyslaw Czarnowski 56107077deSPrzemyslaw Czarnowski /** 57107077deSPrzemyslaw Czarnowski * @brief Read all known properties from VM object interfaces 58107077deSPrzemyslaw Czarnowski */ 5922db1728SEd Tanous inline void 608d1b46d7Szhanghch05 vmParseInterfaceObject(const DbusInterfaceType& interface, 618d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp) 62107077deSPrzemyslaw Czarnowski { 63107077deSPrzemyslaw Czarnowski const auto mountPointIface = 64107077deSPrzemyslaw Czarnowski interface.find("xyz.openbmc_project.VirtualMedia.MountPoint"); 65107077deSPrzemyslaw Czarnowski if (mountPointIface == interface.cend()) 66107077deSPrzemyslaw Czarnowski { 67107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Interface MountPoint not found"; 68107077deSPrzemyslaw Czarnowski return; 69107077deSPrzemyslaw Czarnowski } 70107077deSPrzemyslaw Czarnowski 71107077deSPrzemyslaw Czarnowski const auto processIface = 72107077deSPrzemyslaw Czarnowski interface.find("xyz.openbmc_project.VirtualMedia.Process"); 73107077deSPrzemyslaw Czarnowski if (processIface == interface.cend()) 74107077deSPrzemyslaw Czarnowski { 75107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Interface Process not found"; 76107077deSPrzemyslaw Czarnowski return; 77107077deSPrzemyslaw Czarnowski } 78107077deSPrzemyslaw Czarnowski 79107077deSPrzemyslaw Czarnowski const auto endpointIdProperty = mountPointIface->second.find("EndpointId"); 80107077deSPrzemyslaw Czarnowski if (endpointIdProperty == mountPointIface->second.cend()) 81107077deSPrzemyslaw Czarnowski { 82107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Property EndpointId not found"; 83107077deSPrzemyslaw Czarnowski return; 84107077deSPrzemyslaw Czarnowski } 85107077deSPrzemyslaw Czarnowski 86107077deSPrzemyslaw Czarnowski const auto activeProperty = processIface->second.find("Active"); 87107077deSPrzemyslaw Czarnowski if (activeProperty == processIface->second.cend()) 88107077deSPrzemyslaw Czarnowski { 89107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Property Active not found"; 90107077deSPrzemyslaw Czarnowski return; 91107077deSPrzemyslaw Czarnowski } 92107077deSPrzemyslaw Czarnowski 93107077deSPrzemyslaw Czarnowski const bool* activeValue = std::get_if<bool>(&activeProperty->second); 94107077deSPrzemyslaw Czarnowski if (!activeValue) 95107077deSPrzemyslaw Czarnowski { 96107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Value Active not found"; 97107077deSPrzemyslaw Czarnowski return; 98107077deSPrzemyslaw Czarnowski } 99107077deSPrzemyslaw Czarnowski 100107077deSPrzemyslaw Czarnowski const std::string* endpointIdValue = 101107077deSPrzemyslaw Czarnowski std::get_if<std::string>(&endpointIdProperty->second); 102107077deSPrzemyslaw Czarnowski if (endpointIdValue) 103107077deSPrzemyslaw Czarnowski { 104107077deSPrzemyslaw Czarnowski if (!endpointIdValue->empty()) 105107077deSPrzemyslaw Czarnowski { 106107077deSPrzemyslaw Czarnowski // Proxy mode 107d04ba325SPrzemyslaw Czarnowski aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] = 108d04ba325SPrzemyslaw Czarnowski *endpointIdValue; 109107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["TransferProtocolType"] = "OEM"; 110107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Inserted"] = *activeValue; 111107077deSPrzemyslaw Czarnowski if (*activeValue == true) 112107077deSPrzemyslaw Czarnowski { 113107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["ConnectedVia"] = "Applet"; 114107077deSPrzemyslaw Czarnowski } 115107077deSPrzemyslaw Czarnowski } 116107077deSPrzemyslaw Czarnowski else 117107077deSPrzemyslaw Czarnowski { 118107077deSPrzemyslaw Czarnowski // Legacy mode 1199e319cf0SAnna Platash for (const auto& property : mountPointIface->second) 1209e319cf0SAnna Platash { 1219e319cf0SAnna Platash if (property.first == "ImageURL") 122107077deSPrzemyslaw Czarnowski { 123107077deSPrzemyslaw Czarnowski const std::string* imageUrlValue = 1249e319cf0SAnna Platash std::get_if<std::string>(&property.second); 125107077deSPrzemyslaw Czarnowski if (imageUrlValue && !imageUrlValue->empty()) 126107077deSPrzemyslaw Czarnowski { 127da4784d8SPrzemyslaw Czarnowski std::filesystem::path filePath = *imageUrlValue; 128da4784d8SPrzemyslaw Czarnowski if (!filePath.has_filename()) 129da4784d8SPrzemyslaw Czarnowski { 1309e319cf0SAnna Platash // this will handle https share, which not 1319e319cf0SAnna Platash // necessarily has to have filename given. 132da4784d8SPrzemyslaw Czarnowski aResp->res.jsonValue["ImageName"] = ""; 133da4784d8SPrzemyslaw Czarnowski } 134da4784d8SPrzemyslaw Czarnowski else 135da4784d8SPrzemyslaw Czarnowski { 1369e319cf0SAnna Platash aResp->res.jsonValue["ImageName"] = 1379e319cf0SAnna Platash filePath.filename(); 138da4784d8SPrzemyslaw Czarnowski } 139da4784d8SPrzemyslaw Czarnowski 140da4784d8SPrzemyslaw Czarnowski aResp->res.jsonValue["Image"] = *imageUrlValue; 141107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Inserted"] = *activeValue; 1429e319cf0SAnna Platash aResp->res.jsonValue["TransferProtocolType"] = 1439e319cf0SAnna Platash getTransferProtocolTypeFromUri(*imageUrlValue); 1449e319cf0SAnna Platash 145107077deSPrzemyslaw Czarnowski if (*activeValue == true) 146107077deSPrzemyslaw Czarnowski { 147107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["ConnectedVia"] = "URI"; 148107077deSPrzemyslaw Czarnowski } 149107077deSPrzemyslaw Czarnowski } 150107077deSPrzemyslaw Czarnowski } 1519e319cf0SAnna Platash else if (property.first == "WriteProtected") 1529e319cf0SAnna Platash { 1539e319cf0SAnna Platash const bool* writeProtectedValue = 1549e319cf0SAnna Platash std::get_if<bool>(&property.second); 1559e319cf0SAnna Platash if (writeProtectedValue) 1569e319cf0SAnna Platash { 1579e319cf0SAnna Platash aResp->res.jsonValue["WriteProtected"] = 1589e319cf0SAnna Platash *writeProtectedValue; 1599e319cf0SAnna Platash } 1609e319cf0SAnna Platash } 1619e319cf0SAnna Platash } 162107077deSPrzemyslaw Czarnowski } 163107077deSPrzemyslaw Czarnowski } 164107077deSPrzemyslaw Czarnowski } 165107077deSPrzemyslaw Czarnowski 166107077deSPrzemyslaw Czarnowski /** 167107077deSPrzemyslaw Czarnowski * @brief Fill template for Virtual Media Item. 168107077deSPrzemyslaw Czarnowski */ 16922db1728SEd Tanous inline nlohmann::json vmItemTemplate(const std::string& name, 170107077deSPrzemyslaw Czarnowski const std::string& resName) 171107077deSPrzemyslaw Czarnowski { 172107077deSPrzemyslaw Czarnowski nlohmann::json item; 17322db1728SEd Tanous 17422db1728SEd Tanous std::string id = "/redfish/v1/Managers/"; 17522db1728SEd Tanous id += name; 17622db1728SEd Tanous id += "/VirtualMedia/"; 17722db1728SEd Tanous id += resName; 17822db1728SEd Tanous item["@odata.id"] = std::move(id); 17922db1728SEd Tanous 180d04ba325SPrzemyslaw Czarnowski item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia"; 181107077deSPrzemyslaw Czarnowski item["Name"] = "Virtual Removable Media"; 182107077deSPrzemyslaw Czarnowski item["Id"] = resName; 183107077deSPrzemyslaw Czarnowski item["WriteProtected"] = true; 184107077deSPrzemyslaw Czarnowski item["MediaTypes"] = {"CD", "USBStick"}; 185107077deSPrzemyslaw Czarnowski item["TransferMethod"] = "Stream"; 186d04ba325SPrzemyslaw Czarnowski item["Oem"]["OpenBMC"]["@odata.type"] = 187d04ba325SPrzemyslaw Czarnowski "#OemVirtualMedia.v1_0_0.VirtualMedia"; 188107077deSPrzemyslaw Czarnowski 189107077deSPrzemyslaw Czarnowski return item; 190107077deSPrzemyslaw Czarnowski } 191107077deSPrzemyslaw Czarnowski 192107077deSPrzemyslaw Czarnowski /** 193107077deSPrzemyslaw Czarnowski * @brief Fills collection data 194107077deSPrzemyslaw Czarnowski */ 19522db1728SEd Tanous inline void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> aResp, 196107077deSPrzemyslaw Czarnowski const std::string& service, 197107077deSPrzemyslaw Czarnowski const std::string& name) 198107077deSPrzemyslaw Czarnowski { 199107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Get available Virtual Media resources."; 200107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 201107077deSPrzemyslaw Czarnowski [name, aResp{std::move(aResp)}](const boost::system::error_code ec, 202107077deSPrzemyslaw Czarnowski ManagedObjectType& subtree) { 203107077deSPrzemyslaw Czarnowski if (ec) 204107077deSPrzemyslaw Czarnowski { 205107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "DBUS response error"; 206107077deSPrzemyslaw Czarnowski return; 207107077deSPrzemyslaw Czarnowski } 208107077deSPrzemyslaw Czarnowski nlohmann::json& members = aResp->res.jsonValue["Members"]; 209107077deSPrzemyslaw Czarnowski members = nlohmann::json::array(); 210107077deSPrzemyslaw Czarnowski 211107077deSPrzemyslaw Czarnowski for (const auto& object : subtree) 212107077deSPrzemyslaw Czarnowski { 213107077deSPrzemyslaw Czarnowski nlohmann::json item; 2142dfd18efSEd Tanous std::string path = object.first.filename(); 2152dfd18efSEd Tanous if (path.empty()) 216107077deSPrzemyslaw Czarnowski { 217107077deSPrzemyslaw Czarnowski continue; 218107077deSPrzemyslaw Czarnowski } 219107077deSPrzemyslaw Czarnowski 22022db1728SEd Tanous std::string id = "/redfish/v1/Managers/"; 22122db1728SEd Tanous id += name; 22222db1728SEd Tanous id += "/VirtualMedia/"; 22322db1728SEd Tanous id += path; 224107077deSPrzemyslaw Czarnowski 22522db1728SEd Tanous item["@odata.id"] = std::move(id); 226107077deSPrzemyslaw Czarnowski members.emplace_back(std::move(item)); 227107077deSPrzemyslaw Czarnowski } 228107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Members@odata.count"] = members.size(); 229107077deSPrzemyslaw Czarnowski }, 230107077deSPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia", 231107077deSPrzemyslaw Czarnowski "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 232107077deSPrzemyslaw Czarnowski } 233107077deSPrzemyslaw Czarnowski 234107077deSPrzemyslaw Czarnowski /** 235107077deSPrzemyslaw Czarnowski * @brief Fills data for specific resource 236107077deSPrzemyslaw Czarnowski */ 23722db1728SEd Tanous inline void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 238107077deSPrzemyslaw Czarnowski const std::string& service, const std::string& name, 239107077deSPrzemyslaw Czarnowski const std::string& resName) 240107077deSPrzemyslaw Czarnowski { 241107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Get Virtual Media resource data."; 242107077deSPrzemyslaw Czarnowski 243107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 244107077deSPrzemyslaw Czarnowski [resName, name, aResp](const boost::system::error_code ec, 245107077deSPrzemyslaw Czarnowski ManagedObjectType& subtree) { 246107077deSPrzemyslaw Czarnowski if (ec) 247107077deSPrzemyslaw Czarnowski { 248107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "DBUS response error"; 249e13c2760SPrzemyslaw Czarnowski 250107077deSPrzemyslaw Czarnowski return; 251107077deSPrzemyslaw Czarnowski } 252107077deSPrzemyslaw Czarnowski 253107077deSPrzemyslaw Czarnowski for (auto& item : subtree) 254107077deSPrzemyslaw Czarnowski { 2552dfd18efSEd Tanous std::string thispath = item.first.filename(); 2562dfd18efSEd Tanous if (thispath.empty()) 257107077deSPrzemyslaw Czarnowski { 258107077deSPrzemyslaw Czarnowski continue; 259107077deSPrzemyslaw Czarnowski } 260107077deSPrzemyslaw Czarnowski 2612dfd18efSEd Tanous if (thispath != resName) 262107077deSPrzemyslaw Czarnowski { 263107077deSPrzemyslaw Czarnowski continue; 264107077deSPrzemyslaw Czarnowski } 265107077deSPrzemyslaw Czarnowski 2661a6258dcSPrzemyslaw Czarnowski // "Legacy"/"Proxy" 2671a6258dcSPrzemyslaw Czarnowski auto mode = item.first.parent_path(); 2681a6258dcSPrzemyslaw Czarnowski // "VirtualMedia" 2691a6258dcSPrzemyslaw Czarnowski auto type = mode.parent_path(); 2701a6258dcSPrzemyslaw Czarnowski if (mode.filename().empty() || type.filename().empty()) 2711a6258dcSPrzemyslaw Czarnowski { 2721a6258dcSPrzemyslaw Czarnowski continue; 2731a6258dcSPrzemyslaw Czarnowski } 2741a6258dcSPrzemyslaw Czarnowski 2751a6258dcSPrzemyslaw Czarnowski if (type.filename() != "VirtualMedia") 2761a6258dcSPrzemyslaw Czarnowski { 2771a6258dcSPrzemyslaw Czarnowski continue; 2781a6258dcSPrzemyslaw Czarnowski } 2791a6258dcSPrzemyslaw Czarnowski 280107077deSPrzemyslaw Czarnowski aResp->res.jsonValue = vmItemTemplate(name, resName); 28122db1728SEd Tanous std::string actionsId = "/redfish/v1/Managers/"; 28222db1728SEd Tanous actionsId += name; 28322db1728SEd Tanous actionsId += "/VirtualMedia/"; 28422db1728SEd Tanous actionsId += resName; 28522db1728SEd Tanous actionsId += "/Actions"; 286107077deSPrzemyslaw Czarnowski 287e13c2760SPrzemyslaw Czarnowski // Check if dbus path is Legacy type 2881a6258dcSPrzemyslaw Czarnowski if (mode.filename() == "Legacy") 289e13c2760SPrzemyslaw Czarnowski { 290e13c2760SPrzemyslaw Czarnowski aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"] 291e13c2760SPrzemyslaw Czarnowski ["target"] = 29222db1728SEd Tanous actionsId + "/VirtualMedia.InsertMedia"; 293e13c2760SPrzemyslaw Czarnowski } 294e13c2760SPrzemyslaw Czarnowski 295107077deSPrzemyslaw Czarnowski vmParseInterfaceObject(item.second, aResp); 296107077deSPrzemyslaw Czarnowski 297e13c2760SPrzemyslaw Czarnowski aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"] 298e13c2760SPrzemyslaw Czarnowski ["target"] = 29922db1728SEd Tanous actionsId + "/VirtualMedia.EjectMedia"; 300e13c2760SPrzemyslaw Czarnowski 301107077deSPrzemyslaw Czarnowski return; 302107077deSPrzemyslaw Czarnowski } 303107077deSPrzemyslaw Czarnowski 304107077deSPrzemyslaw Czarnowski messages::resourceNotFound( 305d04ba325SPrzemyslaw Czarnowski aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName); 306107077deSPrzemyslaw Czarnowski }, 307107077deSPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia", 308107077deSPrzemyslaw Czarnowski "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 309107077deSPrzemyslaw Czarnowski } 310107077deSPrzemyslaw Czarnowski 311e13c2760SPrzemyslaw Czarnowski /** 312c6f4e017SAgata Olender * @brief Transfer protocols supported for InsertMedia action. 313c6f4e017SAgata Olender * 314c6f4e017SAgata Olender */ 315c6f4e017SAgata Olender enum class TransferProtocol 316c6f4e017SAgata Olender { 317c6f4e017SAgata Olender https, 318c6f4e017SAgata Olender smb, 319c6f4e017SAgata Olender invalid 320c6f4e017SAgata Olender }; 321c6f4e017SAgata Olender 322c6f4e017SAgata Olender /** 323c6f4e017SAgata Olender * @brief Function extracts transfer protocol type from URI. 324c6f4e017SAgata Olender * 325c6f4e017SAgata Olender */ 32622db1728SEd Tanous inline std::optional<TransferProtocol> 327c6f4e017SAgata Olender getTransferProtocolFromUri(const std::string& imageUri) 328c6f4e017SAgata Olender { 329d32c4fa9SEd Tanous boost::urls::error_code ec; 330d32c4fa9SEd Tanous boost::urls::url_view url = 331d32c4fa9SEd Tanous boost::urls::parse_uri(boost::string_view(imageUri), ec); 332d32c4fa9SEd Tanous if (ec) 3339e319cf0SAnna Platash { 334d32c4fa9SEd Tanous return {}; 335d32c4fa9SEd Tanous } 336d32c4fa9SEd Tanous 337d32c4fa9SEd Tanous boost::string_view scheme = url.scheme(); 3389e319cf0SAnna Platash if (scheme == "smb") 339c6f4e017SAgata Olender { 340c6f4e017SAgata Olender return TransferProtocol::smb; 341c6f4e017SAgata Olender } 34281ce609eSEd Tanous if (scheme == "https") 343c6f4e017SAgata Olender { 344c6f4e017SAgata Olender return TransferProtocol::https; 345c6f4e017SAgata Olender } 34622db1728SEd Tanous if (!scheme.empty()) 347c6f4e017SAgata Olender { 348c6f4e017SAgata Olender return TransferProtocol::invalid; 349c6f4e017SAgata Olender } 3509e319cf0SAnna Platash 3519e319cf0SAnna Platash return {}; 352c6f4e017SAgata Olender } 353c6f4e017SAgata Olender 354c6f4e017SAgata Olender /** 355c6f4e017SAgata Olender * @brief Function convert transfer protocol from string param. 356c6f4e017SAgata Olender * 357c6f4e017SAgata Olender */ 35822db1728SEd Tanous inline std::optional<TransferProtocol> getTransferProtocolFromParam( 359c6f4e017SAgata Olender const std::optional<std::string>& transferProtocolType) 360c6f4e017SAgata Olender { 361c6f4e017SAgata Olender if (transferProtocolType == std::nullopt) 362c6f4e017SAgata Olender { 363c6f4e017SAgata Olender return {}; 364c6f4e017SAgata Olender } 365c6f4e017SAgata Olender 366c6f4e017SAgata Olender if (*transferProtocolType == "CIFS") 367c6f4e017SAgata Olender { 368c6f4e017SAgata Olender return TransferProtocol::smb; 369c6f4e017SAgata Olender } 370c6f4e017SAgata Olender 371c6f4e017SAgata Olender if (*transferProtocolType == "HTTPS") 372c6f4e017SAgata Olender { 373c6f4e017SAgata Olender return TransferProtocol::https; 374c6f4e017SAgata Olender } 375c6f4e017SAgata Olender 376c6f4e017SAgata Olender return TransferProtocol::invalid; 377c6f4e017SAgata Olender } 378c6f4e017SAgata Olender 379c6f4e017SAgata Olender /** 380c6f4e017SAgata Olender * @brief Function extends URI with transfer protocol type. 381c6f4e017SAgata Olender * 382c6f4e017SAgata Olender */ 38322db1728SEd Tanous inline std::string 384c6f4e017SAgata Olender getUriWithTransferProtocol(const std::string& imageUri, 385c6f4e017SAgata Olender const TransferProtocol& transferProtocol) 386c6f4e017SAgata Olender { 387c6f4e017SAgata Olender if (transferProtocol == TransferProtocol::smb) 388c6f4e017SAgata Olender { 389c6f4e017SAgata Olender return "smb://" + imageUri; 390c6f4e017SAgata Olender } 391c6f4e017SAgata Olender 392c6f4e017SAgata Olender if (transferProtocol == TransferProtocol::https) 393c6f4e017SAgata Olender { 394c6f4e017SAgata Olender return "https://" + imageUri; 395c6f4e017SAgata Olender } 396c6f4e017SAgata Olender 397c6f4e017SAgata Olender return imageUri; 398c6f4e017SAgata Olender } 399c6f4e017SAgata Olender 400c6f4e017SAgata Olender /** 401c6f4e017SAgata Olender * @brief Function validate parameters of insert media request. 402c6f4e017SAgata Olender * 403c6f4e017SAgata Olender */ 40422db1728SEd Tanous inline bool 40522db1728SEd Tanous validateParams(crow::Response& res, std::string& imageUrl, 406c6f4e017SAgata Olender const std::optional<bool>& inserted, 407c6f4e017SAgata Olender const std::optional<std::string>& transferMethod, 408c6f4e017SAgata Olender const std::optional<std::string>& transferProtocolType) 409c6f4e017SAgata Olender { 410c6f4e017SAgata Olender BMCWEB_LOG_DEBUG << "Validation started"; 411c6f4e017SAgata Olender // required param imageUrl must not be empty 412c6f4e017SAgata Olender if (imageUrl.empty()) 413c6f4e017SAgata Olender { 414c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter Image is empty."; 415c6f4e017SAgata Olender 41622db1728SEd Tanous messages::propertyValueFormatError(res, "<empty>", "Image"); 417c6f4e017SAgata Olender 418c6f4e017SAgata Olender return false; 419c6f4e017SAgata Olender } 420c6f4e017SAgata Olender 421c6f4e017SAgata Olender // optional param inserted must be true 422c6f4e017SAgata Olender if ((inserted != std::nullopt) && (*inserted != true)) 423c6f4e017SAgata Olender { 424c6f4e017SAgata Olender BMCWEB_LOG_ERROR 425c6f4e017SAgata Olender << "Request action optional parameter Inserted must be true."; 426c6f4e017SAgata Olender 42722db1728SEd Tanous messages::actionParameterNotSupported(res, "Inserted", "InsertMedia"); 428c6f4e017SAgata Olender 429c6f4e017SAgata Olender return false; 430c6f4e017SAgata Olender } 431c6f4e017SAgata Olender 432c6f4e017SAgata Olender // optional param transferMethod must be stream 433c6f4e017SAgata Olender if ((transferMethod != std::nullopt) && (*transferMethod != "Stream")) 434c6f4e017SAgata Olender { 435c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action optional parameter " 436c6f4e017SAgata Olender "TransferMethod must be Stream."; 437c6f4e017SAgata Olender 43822db1728SEd Tanous messages::actionParameterNotSupported(res, "TransferMethod", 43922db1728SEd Tanous "InsertMedia"); 440c6f4e017SAgata Olender 441c6f4e017SAgata Olender return false; 442c6f4e017SAgata Olender } 443c6f4e017SAgata Olender 444c6f4e017SAgata Olender std::optional<TransferProtocol> uriTransferProtocolType = 445c6f4e017SAgata Olender getTransferProtocolFromUri(imageUrl); 446c6f4e017SAgata Olender 447c6f4e017SAgata Olender std::optional<TransferProtocol> paramTransferProtocolType = 448c6f4e017SAgata Olender getTransferProtocolFromParam(transferProtocolType); 449c6f4e017SAgata Olender 450c6f4e017SAgata Olender // ImageUrl does not contain valid protocol type 451c6f4e017SAgata Olender if (*uriTransferProtocolType == TransferProtocol::invalid) 452c6f4e017SAgata Olender { 453c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must " 454c6f4e017SAgata Olender "contain specified protocol type from list: " 455c6f4e017SAgata Olender "(smb, https)."; 456c6f4e017SAgata Olender 45722db1728SEd Tanous messages::resourceAtUriInUnknownFormat(res, imageUrl); 458c6f4e017SAgata Olender 459c6f4e017SAgata Olender return false; 460c6f4e017SAgata Olender } 461c6f4e017SAgata Olender 462c6f4e017SAgata Olender // transferProtocolType should contain value from list 463c6f4e017SAgata Olender if (*paramTransferProtocolType == TransferProtocol::invalid) 464c6f4e017SAgata Olender { 465c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType " 466c6f4e017SAgata Olender "must be provided with value from list: " 467c6f4e017SAgata Olender "(CIFS, HTTPS)."; 468c6f4e017SAgata Olender 46922db1728SEd Tanous messages::propertyValueNotInList(res, *transferProtocolType, 47022db1728SEd Tanous "TransferProtocolType"); 471c6f4e017SAgata Olender return false; 472c6f4e017SAgata Olender } 473c6f4e017SAgata Olender 474c6f4e017SAgata Olender // valid transfer protocol not provided either with URI nor param 475c6f4e017SAgata Olender if ((uriTransferProtocolType == std::nullopt) && 476c6f4e017SAgata Olender (paramTransferProtocolType == std::nullopt)) 477c6f4e017SAgata Olender { 478c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must " 479c6f4e017SAgata Olender "contain specified protocol type or param " 480c6f4e017SAgata Olender "TransferProtocolType must be provided."; 481c6f4e017SAgata Olender 48222db1728SEd Tanous messages::resourceAtUriInUnknownFormat(res, imageUrl); 483c6f4e017SAgata Olender 484c6f4e017SAgata Olender return false; 485c6f4e017SAgata Olender } 486c6f4e017SAgata Olender 487c6f4e017SAgata Olender // valid transfer protocol provided both with URI and param 488c6f4e017SAgata Olender if ((paramTransferProtocolType != std::nullopt) && 489c6f4e017SAgata Olender (uriTransferProtocolType != std::nullopt)) 490c6f4e017SAgata Olender { 491c6f4e017SAgata Olender // check if protocol is the same for URI and param 492c6f4e017SAgata Olender if (*paramTransferProtocolType != *uriTransferProtocolType) 493c6f4e017SAgata Olender { 494c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter " 495c6f4e017SAgata Olender "TransferProtocolType must contain the " 496c6f4e017SAgata Olender "same protocol type as protocol type " 497c6f4e017SAgata Olender "provided with param imageUrl."; 498c6f4e017SAgata Olender 49922db1728SEd Tanous messages::actionParameterValueTypeError(res, *transferProtocolType, 50022db1728SEd Tanous "TransferProtocolType", 50122db1728SEd Tanous "InsertMedia"); 502c6f4e017SAgata Olender 503c6f4e017SAgata Olender return false; 504c6f4e017SAgata Olender } 505c6f4e017SAgata Olender } 506c6f4e017SAgata Olender 507c6f4e017SAgata Olender // validation passed 508c6f4e017SAgata Olender // add protocol to URI if needed 509c6f4e017SAgata Olender if (uriTransferProtocolType == std::nullopt) 510c6f4e017SAgata Olender { 51122db1728SEd Tanous imageUrl = 51222db1728SEd Tanous getUriWithTransferProtocol(imageUrl, *paramTransferProtocolType); 513c6f4e017SAgata Olender } 514c6f4e017SAgata Olender 515c6f4e017SAgata Olender return true; 516c6f4e017SAgata Olender } 517c6f4e017SAgata Olender 5181214b7e7SGunnar Mills template <typename T> 5191214b7e7SGunnar Mills static void secureCleanup(T& value) 520988fb7b2SAdrian Ambrożewicz { 521988fb7b2SAdrian Ambrożewicz auto raw = const_cast<typename T::value_type*>(value.data()); 522988fb7b2SAdrian Ambrożewicz explicit_bzero(raw, value.size() * sizeof(*raw)); 523988fb7b2SAdrian Ambrożewicz } 524988fb7b2SAdrian Ambrożewicz 525988fb7b2SAdrian Ambrożewicz class Credentials 526988fb7b2SAdrian Ambrożewicz { 527988fb7b2SAdrian Ambrożewicz public: 528988fb7b2SAdrian Ambrożewicz Credentials(std::string&& user, std::string&& password) : 529988fb7b2SAdrian Ambrożewicz userBuf(std::move(user)), passBuf(std::move(password)) 5301214b7e7SGunnar Mills {} 531988fb7b2SAdrian Ambrożewicz 532988fb7b2SAdrian Ambrożewicz ~Credentials() 533988fb7b2SAdrian Ambrożewicz { 534988fb7b2SAdrian Ambrożewicz secureCleanup(userBuf); 535988fb7b2SAdrian Ambrożewicz secureCleanup(passBuf); 536988fb7b2SAdrian Ambrożewicz } 537988fb7b2SAdrian Ambrożewicz 538988fb7b2SAdrian Ambrożewicz const std::string& user() 539988fb7b2SAdrian Ambrożewicz { 540988fb7b2SAdrian Ambrożewicz return userBuf; 541988fb7b2SAdrian Ambrożewicz } 542988fb7b2SAdrian Ambrożewicz 543988fb7b2SAdrian Ambrożewicz const std::string& password() 544988fb7b2SAdrian Ambrożewicz { 545988fb7b2SAdrian Ambrożewicz return passBuf; 546988fb7b2SAdrian Ambrożewicz } 547988fb7b2SAdrian Ambrożewicz 548988fb7b2SAdrian Ambrożewicz Credentials() = delete; 549988fb7b2SAdrian Ambrożewicz Credentials(const Credentials&) = delete; 550988fb7b2SAdrian Ambrożewicz Credentials& operator=(const Credentials&) = delete; 551988fb7b2SAdrian Ambrożewicz 55222db1728SEd Tanous private: 553988fb7b2SAdrian Ambrożewicz std::string userBuf; 554988fb7b2SAdrian Ambrożewicz std::string passBuf; 555988fb7b2SAdrian Ambrożewicz }; 556988fb7b2SAdrian Ambrożewicz 557988fb7b2SAdrian Ambrożewicz class CredentialsProvider 558988fb7b2SAdrian Ambrożewicz { 559988fb7b2SAdrian Ambrożewicz public: 5601214b7e7SGunnar Mills template <typename T> 5611214b7e7SGunnar Mills struct Deleter 562988fb7b2SAdrian Ambrożewicz { 563988fb7b2SAdrian Ambrożewicz void operator()(T* buff) const 564988fb7b2SAdrian Ambrożewicz { 565988fb7b2SAdrian Ambrożewicz if (buff) 566988fb7b2SAdrian Ambrożewicz { 567988fb7b2SAdrian Ambrożewicz secureCleanup(*buff); 568988fb7b2SAdrian Ambrożewicz delete buff; 569988fb7b2SAdrian Ambrożewicz } 570988fb7b2SAdrian Ambrożewicz } 571988fb7b2SAdrian Ambrożewicz }; 572988fb7b2SAdrian Ambrożewicz 573988fb7b2SAdrian Ambrożewicz using Buffer = std::vector<char>; 574988fb7b2SAdrian Ambrożewicz using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>; 575988fb7b2SAdrian Ambrożewicz // Using explicit definition instead of std::function to avoid implicit 576988fb7b2SAdrian Ambrożewicz // conversions eg. stack copy instead of reference 577988fb7b2SAdrian Ambrożewicz using FormatterFunc = void(const std::string& username, 578988fb7b2SAdrian Ambrożewicz const std::string& password, Buffer& dest); 579988fb7b2SAdrian Ambrożewicz 580988fb7b2SAdrian Ambrożewicz CredentialsProvider(std::string&& user, std::string&& password) : 581988fb7b2SAdrian Ambrożewicz credentials(std::move(user), std::move(password)) 5821214b7e7SGunnar Mills {} 583988fb7b2SAdrian Ambrożewicz 584988fb7b2SAdrian Ambrożewicz const std::string& user() 585988fb7b2SAdrian Ambrożewicz { 586988fb7b2SAdrian Ambrożewicz return credentials.user(); 587988fb7b2SAdrian Ambrożewicz } 588988fb7b2SAdrian Ambrożewicz 589988fb7b2SAdrian Ambrożewicz const std::string& password() 590988fb7b2SAdrian Ambrożewicz { 591988fb7b2SAdrian Ambrożewicz return credentials.password(); 592988fb7b2SAdrian Ambrożewicz } 593988fb7b2SAdrian Ambrożewicz 59481ce609eSEd Tanous SecureBuffer pack(FormatterFunc formatter) 595988fb7b2SAdrian Ambrożewicz { 596988fb7b2SAdrian Ambrożewicz SecureBuffer packed{new Buffer{}}; 597988fb7b2SAdrian Ambrożewicz if (formatter) 598988fb7b2SAdrian Ambrożewicz { 599988fb7b2SAdrian Ambrożewicz formatter(credentials.user(), credentials.password(), *packed); 600988fb7b2SAdrian Ambrożewicz } 601988fb7b2SAdrian Ambrożewicz 602988fb7b2SAdrian Ambrożewicz return packed; 603988fb7b2SAdrian Ambrożewicz } 604988fb7b2SAdrian Ambrożewicz 605988fb7b2SAdrian Ambrożewicz private: 606988fb7b2SAdrian Ambrożewicz Credentials credentials; 607988fb7b2SAdrian Ambrożewicz }; 608988fb7b2SAdrian Ambrożewicz 609988fb7b2SAdrian Ambrożewicz // Wrapper for boost::async_pipe ensuring proper pipe cleanup 6101214b7e7SGunnar Mills template <typename Buffer> 6111214b7e7SGunnar Mills class Pipe 612988fb7b2SAdrian Ambrożewicz { 613988fb7b2SAdrian Ambrożewicz public: 614988fb7b2SAdrian Ambrożewicz using unix_fd = sdbusplus::message::unix_fd; 615988fb7b2SAdrian Ambrożewicz 616988fb7b2SAdrian Ambrożewicz Pipe(boost::asio::io_context& io, Buffer&& buffer) : 617988fb7b2SAdrian Ambrożewicz impl(io), buffer{std::move(buffer)} 6181214b7e7SGunnar Mills {} 619988fb7b2SAdrian Ambrożewicz 620988fb7b2SAdrian Ambrożewicz ~Pipe() 621988fb7b2SAdrian Ambrożewicz { 622988fb7b2SAdrian Ambrożewicz // Named pipe needs to be explicitly removed 623988fb7b2SAdrian Ambrożewicz impl.close(); 624988fb7b2SAdrian Ambrożewicz } 625988fb7b2SAdrian Ambrożewicz 626988fb7b2SAdrian Ambrożewicz unix_fd fd() 627988fb7b2SAdrian Ambrożewicz { 628988fb7b2SAdrian Ambrożewicz return unix_fd{impl.native_source()}; 629988fb7b2SAdrian Ambrożewicz } 630988fb7b2SAdrian Ambrożewicz 631988fb7b2SAdrian Ambrożewicz template <typename WriteHandler> 63281ce609eSEd Tanous void asyncWrite(WriteHandler&& handler) 633988fb7b2SAdrian Ambrożewicz { 634988fb7b2SAdrian Ambrożewicz impl.async_write_some(data(), std::forward<WriteHandler>(handler)); 635988fb7b2SAdrian Ambrożewicz } 636988fb7b2SAdrian Ambrożewicz 637988fb7b2SAdrian Ambrożewicz private: 638988fb7b2SAdrian Ambrożewicz // Specialization for pointer types 639988fb7b2SAdrian Ambrożewicz template <typename B = Buffer> 640988fb7b2SAdrian Ambrożewicz typename std::enable_if<boost::has_dereference<B>::value, 641988fb7b2SAdrian Ambrożewicz boost::asio::const_buffer>::type 642988fb7b2SAdrian Ambrożewicz data() 643988fb7b2SAdrian Ambrożewicz { 644988fb7b2SAdrian Ambrożewicz return boost::asio::buffer(*buffer); 645988fb7b2SAdrian Ambrożewicz } 646988fb7b2SAdrian Ambrożewicz 647988fb7b2SAdrian Ambrożewicz template <typename B = Buffer> 648988fb7b2SAdrian Ambrożewicz typename std::enable_if<!boost::has_dereference<B>::value, 649988fb7b2SAdrian Ambrożewicz boost::asio::const_buffer>::type 650988fb7b2SAdrian Ambrożewicz data() 651988fb7b2SAdrian Ambrożewicz { 652988fb7b2SAdrian Ambrożewicz return boost::asio::buffer(buffer); 653988fb7b2SAdrian Ambrożewicz } 654988fb7b2SAdrian Ambrożewicz 655988fb7b2SAdrian Ambrożewicz const std::string name; 656988fb7b2SAdrian Ambrożewicz boost::process::async_pipe impl; 657988fb7b2SAdrian Ambrożewicz Buffer buffer; 658988fb7b2SAdrian Ambrożewicz }; 659988fb7b2SAdrian Ambrożewicz 660e13c2760SPrzemyslaw Czarnowski /** 661e13c2760SPrzemyslaw Czarnowski * @brief Function transceives data with dbus directly. 662e13c2760SPrzemyslaw Czarnowski * 663e13c2760SPrzemyslaw Czarnowski * All BMC state properties will be retrieved before sending reset request. 664e13c2760SPrzemyslaw Czarnowski */ 66522db1728SEd Tanous inline void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 666e13c2760SPrzemyslaw Czarnowski const std::string& service, const std::string& name, 667988fb7b2SAdrian Ambrożewicz const std::string& imageUrl, const bool rw, 668988fb7b2SAdrian Ambrożewicz std::string&& userName, std::string&& password) 669e13c2760SPrzemyslaw Czarnowski { 670988fb7b2SAdrian Ambrożewicz using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>; 671988fb7b2SAdrian Ambrożewicz constexpr const size_t secretLimit = 1024; 672988fb7b2SAdrian Ambrożewicz 673988fb7b2SAdrian Ambrożewicz std::shared_ptr<SecurePipe> secretPipe; 674988fb7b2SAdrian Ambrożewicz std::variant<int, SecurePipe::unix_fd> unixFd = -1; 675988fb7b2SAdrian Ambrożewicz 676988fb7b2SAdrian Ambrożewicz if (!userName.empty() || !password.empty()) 677988fb7b2SAdrian Ambrożewicz { 678988fb7b2SAdrian Ambrożewicz // Encapsulate in safe buffer 679988fb7b2SAdrian Ambrożewicz CredentialsProvider credentials(std::move(userName), 680988fb7b2SAdrian Ambrożewicz std::move(password)); 681988fb7b2SAdrian Ambrożewicz 682988fb7b2SAdrian Ambrożewicz // Payload must contain data + NULL delimiters 683988fb7b2SAdrian Ambrożewicz if (credentials.user().size() + credentials.password().size() + 2 > 684988fb7b2SAdrian Ambrożewicz secretLimit) 685988fb7b2SAdrian Ambrożewicz { 686988fb7b2SAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Credentials too long to handle"; 687988fb7b2SAdrian Ambrożewicz messages::unrecognizedRequestBody(asyncResp->res); 688988fb7b2SAdrian Ambrożewicz return; 689988fb7b2SAdrian Ambrożewicz } 690988fb7b2SAdrian Ambrożewicz 691988fb7b2SAdrian Ambrożewicz // Pack secret 69222db1728SEd Tanous auto secret = credentials.pack( 69322db1728SEd Tanous [](const auto& user, const auto& pass, auto& buff) { 694988fb7b2SAdrian Ambrożewicz std::copy(user.begin(), user.end(), std::back_inserter(buff)); 695988fb7b2SAdrian Ambrożewicz buff.push_back('\0'); 696988fb7b2SAdrian Ambrożewicz std::copy(pass.begin(), pass.end(), std::back_inserter(buff)); 697988fb7b2SAdrian Ambrożewicz buff.push_back('\0'); 698988fb7b2SAdrian Ambrożewicz }); 699988fb7b2SAdrian Ambrożewicz 700988fb7b2SAdrian Ambrożewicz // Open pipe 701988fb7b2SAdrian Ambrożewicz secretPipe = std::make_shared<SecurePipe>( 70222db1728SEd Tanous crow::connections::systemBus->get_io_context(), std::move(secret)); 703988fb7b2SAdrian Ambrożewicz unixFd = secretPipe->fd(); 704988fb7b2SAdrian Ambrożewicz 705988fb7b2SAdrian Ambrożewicz // Pass secret over pipe 70681ce609eSEd Tanous secretPipe->asyncWrite( 707f5b16f03SVikram Bodireddy [asyncResp](const boost::system::error_code& ec, std::size_t) { 708988fb7b2SAdrian Ambrożewicz if (ec) 709988fb7b2SAdrian Ambrożewicz { 710988fb7b2SAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec; 711988fb7b2SAdrian Ambrożewicz messages::internalError(asyncResp->res); 712988fb7b2SAdrian Ambrożewicz } 713988fb7b2SAdrian Ambrożewicz }); 714988fb7b2SAdrian Ambrożewicz } 715988fb7b2SAdrian Ambrożewicz 716e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 717988fb7b2SAdrian Ambrożewicz [asyncResp, secretPipe](const boost::system::error_code ec, 718988fb7b2SAdrian Ambrożewicz bool success) { 719e13c2760SPrzemyslaw Czarnowski if (ec) 720e13c2760SPrzemyslaw Czarnowski { 721e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 722e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 723d6da5bebSAdrian Ambrożewicz } 724d6da5bebSAdrian Ambrożewicz else if (!success) 725d6da5bebSAdrian Ambrożewicz { 726d6da5bebSAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Service responded with error"; 727d6da5bebSAdrian Ambrożewicz messages::generalError(asyncResp->res); 728e13c2760SPrzemyslaw Czarnowski } 729e13c2760SPrzemyslaw Czarnowski }, 730e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, 731988fb7b2SAdrian Ambrożewicz "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw, 732988fb7b2SAdrian Ambrożewicz unixFd); 733e13c2760SPrzemyslaw Czarnowski } 734e13c2760SPrzemyslaw Czarnowski 735e13c2760SPrzemyslaw Czarnowski /** 736e13c2760SPrzemyslaw Czarnowski * @brief Function transceives data with dbus directly. 737e13c2760SPrzemyslaw Czarnowski * 738e13c2760SPrzemyslaw Czarnowski * All BMC state properties will be retrieved before sending reset request. 739e13c2760SPrzemyslaw Czarnowski */ 74022db1728SEd Tanous inline void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 741e13c2760SPrzemyslaw Czarnowski const std::string& service, const std::string& name, 742e13c2760SPrzemyslaw Czarnowski bool legacy) 743e13c2760SPrzemyslaw Czarnowski { 744e13c2760SPrzemyslaw Czarnowski 745e13c2760SPrzemyslaw Czarnowski // Legacy mount requires parameter with image 746e13c2760SPrzemyslaw Czarnowski if (legacy) 747e13c2760SPrzemyslaw Czarnowski { 748e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 749e13c2760SPrzemyslaw Czarnowski [asyncResp](const boost::system::error_code ec) { 750e13c2760SPrzemyslaw Czarnowski if (ec) 751e13c2760SPrzemyslaw Czarnowski { 752e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 753e13c2760SPrzemyslaw Czarnowski 754e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 755e13c2760SPrzemyslaw Czarnowski return; 756e13c2760SPrzemyslaw Czarnowski } 757e13c2760SPrzemyslaw Czarnowski }, 758e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, 759e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount"); 760e13c2760SPrzemyslaw Czarnowski } 761e13c2760SPrzemyslaw Czarnowski else // proxy 762e13c2760SPrzemyslaw Czarnowski { 763e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 764e13c2760SPrzemyslaw Czarnowski [asyncResp](const boost::system::error_code ec) { 765e13c2760SPrzemyslaw Czarnowski if (ec) 766e13c2760SPrzemyslaw Czarnowski { 767e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 768e13c2760SPrzemyslaw Czarnowski 769e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 770e13c2760SPrzemyslaw Czarnowski return; 771e13c2760SPrzemyslaw Czarnowski } 772e13c2760SPrzemyslaw Czarnowski }, 773e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name, 774e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount"); 775e13c2760SPrzemyslaw Czarnowski } 776e13c2760SPrzemyslaw Czarnowski } 777e13c2760SPrzemyslaw Czarnowski 77822db1728SEd Tanous inline void requestNBDVirtualMediaRoutes(App& app) 779107077deSPrzemyslaw Czarnowski { 780*0fda0f12SGeorge Liu BMCWEB_ROUTE( 781*0fda0f12SGeorge Liu app, 782*0fda0f12SGeorge Liu "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.InsertMedia") 783ed398213SEd Tanous .privileges(redfish::privileges::postVirtualMedia) 78422db1728SEd Tanous .methods(boost::beast::http::verb::post)( 78522db1728SEd Tanous [](const crow::Request& req, 78622db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 78722db1728SEd Tanous const std::string& name, const std::string& resName) { 78822db1728SEd Tanous if (name != "bmc") 789107077deSPrzemyslaw Czarnowski { 79022db1728SEd Tanous messages::resourceNotFound(asyncResp->res, 79122db1728SEd Tanous "VirtualMedia.Insert", resName); 792107077deSPrzemyslaw Czarnowski 793107077deSPrzemyslaw Czarnowski return; 794107077deSPrzemyslaw Czarnowski } 795107077deSPrzemyslaw Czarnowski 79622db1728SEd Tanous crow::connections::systemBus->async_method_call( 79722db1728SEd Tanous [asyncResp, req, 79822db1728SEd Tanous resName](const boost::system::error_code ec, 79922db1728SEd Tanous const GetObjectType& getObjectType) { 80022db1728SEd Tanous if (ec) 80122db1728SEd Tanous { 80222db1728SEd Tanous BMCWEB_LOG_ERROR 80322db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 80422db1728SEd Tanous << ec; 80522db1728SEd Tanous messages::internalError(asyncResp->res); 806107077deSPrzemyslaw Czarnowski 80722db1728SEd Tanous return; 80822db1728SEd Tanous } 80922db1728SEd Tanous std::string service = getObjectType.begin()->first; 81022db1728SEd Tanous BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 81122db1728SEd Tanous 81222db1728SEd Tanous crow::connections::systemBus->async_method_call( 81322db1728SEd Tanous [service, resName, req, 81422db1728SEd Tanous asyncResp](const boost::system::error_code ec, 81522db1728SEd Tanous ManagedObjectType& subtree) { 81622db1728SEd Tanous if (ec) 81722db1728SEd Tanous { 81822db1728SEd Tanous BMCWEB_LOG_DEBUG << "DBUS response error"; 81922db1728SEd Tanous 82022db1728SEd Tanous return; 82122db1728SEd Tanous } 82222db1728SEd Tanous 82322db1728SEd Tanous for (const auto& object : subtree) 82422db1728SEd Tanous { 82522db1728SEd Tanous const std::string& path = 82622db1728SEd Tanous static_cast<const std::string&>( 82722db1728SEd Tanous object.first); 82822db1728SEd Tanous 82922db1728SEd Tanous std::size_t lastIndex = path.rfind('/'); 83022db1728SEd Tanous if (lastIndex == std::string::npos) 83122db1728SEd Tanous { 83222db1728SEd Tanous continue; 83322db1728SEd Tanous } 83422db1728SEd Tanous 83522db1728SEd Tanous lastIndex += 1; 83622db1728SEd Tanous 83722db1728SEd Tanous if (path.substr(lastIndex) == resName) 83822db1728SEd Tanous { 83922db1728SEd Tanous lastIndex = path.rfind("Proxy"); 84022db1728SEd Tanous if (lastIndex != std::string::npos) 84122db1728SEd Tanous { 84222db1728SEd Tanous // Not possible in proxy mode 84322db1728SEd Tanous BMCWEB_LOG_DEBUG 84422db1728SEd Tanous << "InsertMedia not " 84522db1728SEd Tanous "allowed in proxy mode"; 84622db1728SEd Tanous messages::resourceNotFound( 84722db1728SEd Tanous asyncResp->res, 84822db1728SEd Tanous "VirtualMedia.InsertMedia", 84922db1728SEd Tanous resName); 85022db1728SEd Tanous 85122db1728SEd Tanous return; 85222db1728SEd Tanous } 85322db1728SEd Tanous 85422db1728SEd Tanous lastIndex = path.rfind("Legacy"); 85522db1728SEd Tanous if (lastIndex == std::string::npos) 85622db1728SEd Tanous { 85722db1728SEd Tanous continue; 85822db1728SEd Tanous } 85922db1728SEd Tanous 86022db1728SEd Tanous // Legacy mode 86122db1728SEd Tanous std::string imageUrl; 86222db1728SEd Tanous std::optional<std::string> userName; 86322db1728SEd Tanous std::optional<std::string> password; 86422db1728SEd Tanous std::optional<std::string> 86522db1728SEd Tanous transferMethod; 86622db1728SEd Tanous std::optional<std::string> 86722db1728SEd Tanous transferProtocolType; 86822db1728SEd Tanous std::optional<bool> writeProtected = 86922db1728SEd Tanous true; 87022db1728SEd Tanous std::optional<bool> inserted; 87122db1728SEd Tanous 87222db1728SEd Tanous // Read obligatory parameters (url of 87322db1728SEd Tanous // image) 87422db1728SEd Tanous if (!json_util::readJson( 87522db1728SEd Tanous req, asyncResp->res, "Image", 87622db1728SEd Tanous imageUrl, "WriteProtected", 87722db1728SEd Tanous writeProtected, "UserName", 87822db1728SEd Tanous userName, "Password", password, 87922db1728SEd Tanous "Inserted", inserted, 88022db1728SEd Tanous "TransferMethod", 88122db1728SEd Tanous transferMethod, 88222db1728SEd Tanous "TransferProtocolType", 88322db1728SEd Tanous transferProtocolType)) 88422db1728SEd Tanous { 88522db1728SEd Tanous BMCWEB_LOG_DEBUG 88622db1728SEd Tanous << "Image is not provided"; 88722db1728SEd Tanous return; 88822db1728SEd Tanous } 88922db1728SEd Tanous 89022db1728SEd Tanous bool paramsValid = validateParams( 89122db1728SEd Tanous asyncResp->res, imageUrl, inserted, 89222db1728SEd Tanous transferMethod, 89322db1728SEd Tanous transferProtocolType); 89422db1728SEd Tanous 89522db1728SEd Tanous if (paramsValid == false) 89622db1728SEd Tanous { 89722db1728SEd Tanous return; 89822db1728SEd Tanous } 89922db1728SEd Tanous 90022db1728SEd Tanous // manager is irrelevant for 90122db1728SEd Tanous // VirtualMedia dbus calls 90222db1728SEd Tanous doMountVmLegacy(asyncResp, service, 90322db1728SEd Tanous resName, imageUrl, 90422db1728SEd Tanous !(*writeProtected), 90522db1728SEd Tanous std::move(*userName), 90622db1728SEd Tanous std::move(*password)); 90722db1728SEd Tanous 90822db1728SEd Tanous return; 90922db1728SEd Tanous } 91022db1728SEd Tanous } 91122db1728SEd Tanous BMCWEB_LOG_DEBUG << "Parent item not found"; 91222db1728SEd Tanous messages::resourceNotFound( 91322db1728SEd Tanous asyncResp->res, "VirtualMedia", resName); 91422db1728SEd Tanous }, 91522db1728SEd Tanous service, "/xyz/openbmc_project/VirtualMedia", 91622db1728SEd Tanous "org.freedesktop.DBus.ObjectManager", 91722db1728SEd Tanous "GetManagedObjects"); 91822db1728SEd Tanous }, 91922db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", 92022db1728SEd Tanous "/xyz/openbmc_project/object_mapper", 92122db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", 92222db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 92322db1728SEd Tanous std::array<const char*, 0>()); 92422db1728SEd Tanous }); 92522db1728SEd Tanous 926*0fda0f12SGeorge Liu BMCWEB_ROUTE( 927*0fda0f12SGeorge Liu app, 928*0fda0f12SGeorge Liu "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.EjectMedia") 929ed398213SEd Tanous .privileges(redfish::privileges::postVirtualMedia) 93022db1728SEd Tanous .methods(boost::beast::http::verb::post)( 93122db1728SEd Tanous [](const crow::Request& req, 93222db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 93322db1728SEd Tanous const std::string& name, const std::string& resName) { 934107077deSPrzemyslaw Czarnowski if (name != "bmc") 935107077deSPrzemyslaw Czarnowski { 93622db1728SEd Tanous messages::resourceNotFound(asyncResp->res, 93722db1728SEd Tanous "VirtualMedia.Eject", resName); 93822db1728SEd Tanous 93922db1728SEd Tanous return; 94022db1728SEd Tanous } 94122db1728SEd Tanous 94222db1728SEd Tanous crow::connections::systemBus->async_method_call( 94322db1728SEd Tanous [asyncResp, req, 94422db1728SEd Tanous resName](const boost::system::error_code ec, 94522db1728SEd Tanous const GetObjectType& getObjectType) { 94622db1728SEd Tanous if (ec) 94722db1728SEd Tanous { 94822db1728SEd Tanous BMCWEB_LOG_ERROR 94922db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 95022db1728SEd Tanous << ec; 95122db1728SEd Tanous messages::internalError(asyncResp->res); 95222db1728SEd Tanous 95322db1728SEd Tanous return; 95422db1728SEd Tanous } 95522db1728SEd Tanous std::string service = getObjectType.begin()->first; 95622db1728SEd Tanous BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 95722db1728SEd Tanous 95822db1728SEd Tanous crow::connections::systemBus->async_method_call( 95922db1728SEd Tanous [resName, service, req, asyncResp{asyncResp}]( 96022db1728SEd Tanous const boost::system::error_code ec, 96122db1728SEd Tanous ManagedObjectType& subtree) { 96222db1728SEd Tanous if (ec) 96322db1728SEd Tanous { 96422db1728SEd Tanous BMCWEB_LOG_DEBUG << "DBUS response error"; 96522db1728SEd Tanous 96622db1728SEd Tanous return; 96722db1728SEd Tanous } 96822db1728SEd Tanous 96922db1728SEd Tanous for (const auto& object : subtree) 97022db1728SEd Tanous { 97122db1728SEd Tanous const std::string& path = 97222db1728SEd Tanous static_cast<const std::string&>( 97322db1728SEd Tanous object.first); 97422db1728SEd Tanous 97522db1728SEd Tanous std::size_t lastIndex = path.rfind('/'); 97622db1728SEd Tanous if (lastIndex == std::string::npos) 97722db1728SEd Tanous { 97822db1728SEd Tanous continue; 97922db1728SEd Tanous } 98022db1728SEd Tanous 98122db1728SEd Tanous lastIndex += 1; 98222db1728SEd Tanous 98322db1728SEd Tanous if (path.substr(lastIndex) == resName) 98422db1728SEd Tanous { 98522db1728SEd Tanous lastIndex = path.rfind("Proxy"); 98622db1728SEd Tanous if (lastIndex != std::string::npos) 98722db1728SEd Tanous { 98822db1728SEd Tanous // Proxy mode 98922db1728SEd Tanous doVmAction(asyncResp, service, 99022db1728SEd Tanous resName, false); 99122db1728SEd Tanous } 99222db1728SEd Tanous 99322db1728SEd Tanous lastIndex = path.rfind("Legacy"); 99422db1728SEd Tanous if (lastIndex != std::string::npos) 99522db1728SEd Tanous { 99622db1728SEd Tanous // Legacy mode 99722db1728SEd Tanous doVmAction(asyncResp, service, 99822db1728SEd Tanous resName, true); 99922db1728SEd Tanous } 100022db1728SEd Tanous 100122db1728SEd Tanous return; 100222db1728SEd Tanous } 100322db1728SEd Tanous } 100422db1728SEd Tanous BMCWEB_LOG_DEBUG << "Parent item not found"; 100522db1728SEd Tanous messages::resourceNotFound( 100622db1728SEd Tanous asyncResp->res, "VirtualMedia", resName); 100722db1728SEd Tanous }, 100822db1728SEd Tanous service, "/xyz/openbmc_project/VirtualMedia", 100922db1728SEd Tanous "org.freedesktop.DBus.ObjectManager", 101022db1728SEd Tanous "GetManagedObjects"); 101122db1728SEd Tanous }, 101222db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", 101322db1728SEd Tanous "/xyz/openbmc_project/object_mapper", 101422db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", 101522db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 101622db1728SEd Tanous std::array<const char*, 0>()); 101722db1728SEd Tanous }); 101822db1728SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/") 1019ed398213SEd Tanous .privileges(redfish::privileges::getVirtualMediaCollection) 102022db1728SEd Tanous .methods(boost::beast::http::verb::get)( 102122db1728SEd Tanous [](const crow::Request& /* req */, 102222db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 102322db1728SEd Tanous const std::string& name) { 102422db1728SEd Tanous if (name != "bmc") 102522db1728SEd Tanous { 102622db1728SEd Tanous messages::resourceNotFound(asyncResp->res, "VirtualMedia", 102722db1728SEd Tanous name); 1028107077deSPrzemyslaw Czarnowski 1029107077deSPrzemyslaw Czarnowski return; 1030107077deSPrzemyslaw Czarnowski } 1031107077deSPrzemyslaw Czarnowski 10328d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1033107077deSPrzemyslaw Czarnowski "#VirtualMediaCollection.VirtualMediaCollection"; 10348d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Virtual Media Services"; 10358d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = 1036d6c414f3SPrzemyslaw Czarnowski "/redfish/v1/Managers/" + name + "/VirtualMedia"; 1037107077deSPrzemyslaw Czarnowski 1038107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 1039107077deSPrzemyslaw Czarnowski [asyncResp, name](const boost::system::error_code ec, 1040107077deSPrzemyslaw Czarnowski const GetObjectType& getObjectType) { 1041107077deSPrzemyslaw Czarnowski if (ec) 1042107077deSPrzemyslaw Czarnowski { 104322db1728SEd Tanous BMCWEB_LOG_ERROR 104422db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 1045107077deSPrzemyslaw Czarnowski << ec; 1046107077deSPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 1047107077deSPrzemyslaw Czarnowski 1048107077deSPrzemyslaw Czarnowski return; 1049107077deSPrzemyslaw Czarnowski } 1050107077deSPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 1051107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 1052107077deSPrzemyslaw Czarnowski 1053107077deSPrzemyslaw Czarnowski getVmResourceList(asyncResp, service, name); 1054107077deSPrzemyslaw Czarnowski }, 1055107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 1056107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 1057107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 105822db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 105922db1728SEd Tanous std::array<const char*, 0>()); 106022db1728SEd Tanous }); 1061107077deSPrzemyslaw Czarnowski 106222db1728SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/") 1063ed398213SEd Tanous .privileges(redfish::privileges::getVirtualMedia) 106422db1728SEd Tanous .methods(boost::beast::http::verb::get)( 106522db1728SEd Tanous [](const crow::Request& /* req */, 106622db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 106722db1728SEd Tanous const std::string& name, const std::string& resName) { 1068107077deSPrzemyslaw Czarnowski if (name != "bmc") 1069107077deSPrzemyslaw Czarnowski { 107022db1728SEd Tanous messages::resourceNotFound(asyncResp->res, "VirtualMedia", 107122db1728SEd Tanous resName); 1072107077deSPrzemyslaw Czarnowski 1073107077deSPrzemyslaw Czarnowski return; 1074107077deSPrzemyslaw Czarnowski } 1075107077deSPrzemyslaw Czarnowski 1076107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 107722db1728SEd Tanous [asyncResp, name, 107822db1728SEd Tanous resName](const boost::system::error_code ec, 1079107077deSPrzemyslaw Czarnowski const GetObjectType& getObjectType) { 1080107077deSPrzemyslaw Czarnowski if (ec) 1081107077deSPrzemyslaw Czarnowski { 108222db1728SEd Tanous BMCWEB_LOG_ERROR 108322db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 1084107077deSPrzemyslaw Czarnowski << ec; 1085107077deSPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 1086107077deSPrzemyslaw Czarnowski 1087107077deSPrzemyslaw Czarnowski return; 1088107077deSPrzemyslaw Czarnowski } 1089107077deSPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 1090107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 1091107077deSPrzemyslaw Czarnowski 1092107077deSPrzemyslaw Czarnowski getVmData(asyncResp, service, name, resName); 1093107077deSPrzemyslaw Czarnowski }, 1094107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 1095107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 1096107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 109722db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 109822db1728SEd Tanous std::array<const char*, 0>()); 109922db1728SEd Tanous }); 1100107077deSPrzemyslaw Czarnowski } 1101107077deSPrzemyslaw Czarnowski 1102107077deSPrzemyslaw Czarnowski } // namespace redfish 1103