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; 674*168e20c1SEd Tanous dbus::utility::DbusVariantType 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 77898be3e39SEd Tanous struct InsertMediaActionParams 77998be3e39SEd Tanous { 78098be3e39SEd Tanous std::string imageUrl; 78198be3e39SEd Tanous std::optional<std::string> userName; 78298be3e39SEd Tanous std::optional<std::string> password; 78398be3e39SEd Tanous std::optional<std::string> transferMethod; 78498be3e39SEd Tanous std::optional<std::string> transferProtocolType; 78598be3e39SEd Tanous std::optional<bool> writeProtected = true; 78698be3e39SEd Tanous std::optional<bool> inserted; 78798be3e39SEd Tanous }; 78898be3e39SEd Tanous 78922db1728SEd Tanous inline void requestNBDVirtualMediaRoutes(App& app) 790107077deSPrzemyslaw Czarnowski { 7910fda0f12SGeorge Liu BMCWEB_ROUTE( 7920fda0f12SGeorge Liu app, 7930fda0f12SGeorge Liu "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.InsertMedia") 794ed398213SEd Tanous .privileges(redfish::privileges::postVirtualMedia) 79522db1728SEd Tanous .methods(boost::beast::http::verb::post)( 79622db1728SEd Tanous [](const crow::Request& req, 79722db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 79822db1728SEd Tanous const std::string& name, const std::string& resName) { 79922db1728SEd Tanous if (name != "bmc") 800107077deSPrzemyslaw Czarnowski { 80122db1728SEd Tanous messages::resourceNotFound(asyncResp->res, 80222db1728SEd Tanous "VirtualMedia.Insert", resName); 803107077deSPrzemyslaw Czarnowski 804107077deSPrzemyslaw Czarnowski return; 805107077deSPrzemyslaw Czarnowski } 80698be3e39SEd Tanous InsertMediaActionParams actionParams; 80798be3e39SEd Tanous 80898be3e39SEd Tanous // Read obligatory parameters (url of 80998be3e39SEd Tanous // image) 81098be3e39SEd Tanous if (!json_util::readJson( 81198be3e39SEd Tanous req, asyncResp->res, "Image", actionParams.imageUrl, 81298be3e39SEd Tanous "WriteProtected", actionParams.writeProtected, 81398be3e39SEd Tanous "UserName", actionParams.userName, "Password", 81498be3e39SEd Tanous actionParams.password, "Inserted", 81598be3e39SEd Tanous actionParams.inserted, "TransferMethod", 81698be3e39SEd Tanous actionParams.transferMethod, "TransferProtocolType", 81798be3e39SEd Tanous actionParams.transferProtocolType)) 81898be3e39SEd Tanous { 81998be3e39SEd Tanous BMCWEB_LOG_DEBUG << "Image is not provided"; 82098be3e39SEd Tanous return; 82198be3e39SEd Tanous } 82298be3e39SEd Tanous 82398be3e39SEd Tanous bool paramsValid = validateParams( 82498be3e39SEd Tanous asyncResp->res, actionParams.imageUrl, 82598be3e39SEd Tanous actionParams.inserted, actionParams.transferMethod, 82698be3e39SEd Tanous actionParams.transferProtocolType); 82798be3e39SEd Tanous 82898be3e39SEd Tanous if (paramsValid == false) 82998be3e39SEd Tanous { 83098be3e39SEd Tanous return; 83198be3e39SEd Tanous } 832107077deSPrzemyslaw Czarnowski 83322db1728SEd Tanous crow::connections::systemBus->async_method_call( 83498be3e39SEd Tanous [asyncResp, actionParams, 83522db1728SEd Tanous resName](const boost::system::error_code ec, 83698be3e39SEd Tanous const GetObjectType& getObjectType) mutable { 83722db1728SEd Tanous if (ec) 83822db1728SEd Tanous { 83922db1728SEd Tanous BMCWEB_LOG_ERROR 84022db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 84122db1728SEd Tanous << ec; 84222db1728SEd Tanous messages::internalError(asyncResp->res); 843107077deSPrzemyslaw Czarnowski 84422db1728SEd Tanous return; 84522db1728SEd Tanous } 84622db1728SEd Tanous std::string service = getObjectType.begin()->first; 84722db1728SEd Tanous BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 84822db1728SEd Tanous 84922db1728SEd Tanous crow::connections::systemBus->async_method_call( 85098be3e39SEd Tanous [service, resName, actionParams, 85122db1728SEd Tanous asyncResp](const boost::system::error_code ec, 85298be3e39SEd Tanous ManagedObjectType& subtree) mutable { 85322db1728SEd Tanous if (ec) 85422db1728SEd Tanous { 85522db1728SEd Tanous BMCWEB_LOG_DEBUG << "DBUS response error"; 85622db1728SEd Tanous 85722db1728SEd Tanous return; 85822db1728SEd Tanous } 85922db1728SEd Tanous 86022db1728SEd Tanous for (const auto& object : subtree) 86122db1728SEd Tanous { 86222db1728SEd Tanous const std::string& path = 86322db1728SEd Tanous static_cast<const std::string&>( 86422db1728SEd Tanous object.first); 86522db1728SEd Tanous 86622db1728SEd Tanous std::size_t lastIndex = path.rfind('/'); 86722db1728SEd Tanous if (lastIndex == std::string::npos) 86822db1728SEd Tanous { 86922db1728SEd Tanous continue; 87022db1728SEd Tanous } 87122db1728SEd Tanous 87222db1728SEd Tanous lastIndex += 1; 87322db1728SEd Tanous 87422db1728SEd Tanous if (path.substr(lastIndex) == resName) 87522db1728SEd Tanous { 87622db1728SEd Tanous lastIndex = path.rfind("Proxy"); 87722db1728SEd Tanous if (lastIndex != std::string::npos) 87822db1728SEd Tanous { 87922db1728SEd Tanous // Not possible in proxy mode 88022db1728SEd Tanous BMCWEB_LOG_DEBUG 88122db1728SEd Tanous << "InsertMedia not " 88222db1728SEd Tanous "allowed in proxy mode"; 88322db1728SEd Tanous messages::resourceNotFound( 88422db1728SEd Tanous asyncResp->res, 88522db1728SEd Tanous "VirtualMedia.InsertMedia", 88622db1728SEd Tanous resName); 88722db1728SEd Tanous 88822db1728SEd Tanous return; 88922db1728SEd Tanous } 89022db1728SEd Tanous 89122db1728SEd Tanous lastIndex = path.rfind("Legacy"); 89222db1728SEd Tanous if (lastIndex == std::string::npos) 89322db1728SEd Tanous { 89422db1728SEd Tanous continue; 89522db1728SEd Tanous } 89622db1728SEd Tanous 89722db1728SEd Tanous // manager is irrelevant for 89822db1728SEd Tanous // VirtualMedia dbus calls 89998be3e39SEd Tanous doMountVmLegacy( 90098be3e39SEd Tanous asyncResp, service, resName, 90198be3e39SEd Tanous actionParams.imageUrl, 90298be3e39SEd Tanous !(*actionParams.writeProtected), 90398be3e39SEd Tanous std::move(*actionParams.userName), 90498be3e39SEd Tanous std::move(*actionParams.password)); 90522db1728SEd Tanous 90622db1728SEd Tanous return; 90722db1728SEd Tanous } 90822db1728SEd Tanous } 90922db1728SEd Tanous BMCWEB_LOG_DEBUG << "Parent item not found"; 91022db1728SEd Tanous messages::resourceNotFound( 91122db1728SEd Tanous asyncResp->res, "VirtualMedia", resName); 91222db1728SEd Tanous }, 91322db1728SEd Tanous service, "/xyz/openbmc_project/VirtualMedia", 91422db1728SEd Tanous "org.freedesktop.DBus.ObjectManager", 91522db1728SEd Tanous "GetManagedObjects"); 91622db1728SEd Tanous }, 91722db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", 91822db1728SEd Tanous "/xyz/openbmc_project/object_mapper", 91922db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", 92022db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 92122db1728SEd Tanous std::array<const char*, 0>()); 92222db1728SEd Tanous }); 92322db1728SEd Tanous 9240fda0f12SGeorge Liu BMCWEB_ROUTE( 9250fda0f12SGeorge Liu app, 9260fda0f12SGeorge Liu "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.EjectMedia") 927ed398213SEd Tanous .privileges(redfish::privileges::postVirtualMedia) 92822db1728SEd Tanous .methods(boost::beast::http::verb::post)( 92998be3e39SEd Tanous [](const crow::Request&, 93022db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 93122db1728SEd Tanous const std::string& name, const std::string& resName) { 932107077deSPrzemyslaw Czarnowski if (name != "bmc") 933107077deSPrzemyslaw Czarnowski { 93422db1728SEd Tanous messages::resourceNotFound(asyncResp->res, 93522db1728SEd Tanous "VirtualMedia.Eject", resName); 93622db1728SEd Tanous 93722db1728SEd Tanous return; 93822db1728SEd Tanous } 93922db1728SEd Tanous 94022db1728SEd Tanous crow::connections::systemBus->async_method_call( 94198be3e39SEd Tanous [asyncResp, resName](const boost::system::error_code ec, 94222db1728SEd Tanous const GetObjectType& getObjectType) { 94322db1728SEd Tanous if (ec) 94422db1728SEd Tanous { 94522db1728SEd Tanous BMCWEB_LOG_ERROR 94622db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 94722db1728SEd Tanous << ec; 94822db1728SEd Tanous messages::internalError(asyncResp->res); 94922db1728SEd Tanous 95022db1728SEd Tanous return; 95122db1728SEd Tanous } 95222db1728SEd Tanous std::string service = getObjectType.begin()->first; 95322db1728SEd Tanous BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 95422db1728SEd Tanous 95522db1728SEd Tanous crow::connections::systemBus->async_method_call( 95698be3e39SEd Tanous [resName, service, asyncResp{asyncResp}]( 95722db1728SEd Tanous const boost::system::error_code ec, 95822db1728SEd Tanous ManagedObjectType& subtree) { 95922db1728SEd Tanous if (ec) 96022db1728SEd Tanous { 96122db1728SEd Tanous BMCWEB_LOG_DEBUG << "DBUS response error"; 96222db1728SEd Tanous 96322db1728SEd Tanous return; 96422db1728SEd Tanous } 96522db1728SEd Tanous 96622db1728SEd Tanous for (const auto& object : subtree) 96722db1728SEd Tanous { 96822db1728SEd Tanous const std::string& path = 96922db1728SEd Tanous static_cast<const std::string&>( 97022db1728SEd Tanous object.first); 97122db1728SEd Tanous 97222db1728SEd Tanous std::size_t lastIndex = path.rfind('/'); 97322db1728SEd Tanous if (lastIndex == std::string::npos) 97422db1728SEd Tanous { 97522db1728SEd Tanous continue; 97622db1728SEd Tanous } 97722db1728SEd Tanous 97822db1728SEd Tanous lastIndex += 1; 97922db1728SEd Tanous 98022db1728SEd Tanous if (path.substr(lastIndex) == resName) 98122db1728SEd Tanous { 98222db1728SEd Tanous lastIndex = path.rfind("Proxy"); 98322db1728SEd Tanous if (lastIndex != std::string::npos) 98422db1728SEd Tanous { 98522db1728SEd Tanous // Proxy mode 98622db1728SEd Tanous doVmAction(asyncResp, service, 98722db1728SEd Tanous resName, false); 98822db1728SEd Tanous } 98922db1728SEd Tanous 99022db1728SEd Tanous lastIndex = path.rfind("Legacy"); 99122db1728SEd Tanous if (lastIndex != std::string::npos) 99222db1728SEd Tanous { 99322db1728SEd Tanous // Legacy mode 99422db1728SEd Tanous doVmAction(asyncResp, service, 99522db1728SEd Tanous resName, true); 99622db1728SEd Tanous } 99722db1728SEd Tanous 99822db1728SEd Tanous return; 99922db1728SEd Tanous } 100022db1728SEd Tanous } 100122db1728SEd Tanous BMCWEB_LOG_DEBUG << "Parent item not found"; 100222db1728SEd Tanous messages::resourceNotFound( 100322db1728SEd Tanous asyncResp->res, "VirtualMedia", resName); 100422db1728SEd Tanous }, 100522db1728SEd Tanous service, "/xyz/openbmc_project/VirtualMedia", 100622db1728SEd Tanous "org.freedesktop.DBus.ObjectManager", 100722db1728SEd Tanous "GetManagedObjects"); 100822db1728SEd Tanous }, 100922db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", 101022db1728SEd Tanous "/xyz/openbmc_project/object_mapper", 101122db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", 101222db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 101322db1728SEd Tanous std::array<const char*, 0>()); 101422db1728SEd Tanous }); 101522db1728SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/") 1016ed398213SEd Tanous .privileges(redfish::privileges::getVirtualMediaCollection) 101722db1728SEd Tanous .methods(boost::beast::http::verb::get)( 101822db1728SEd Tanous [](const crow::Request& /* req */, 101922db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 102022db1728SEd Tanous const std::string& name) { 102122db1728SEd Tanous if (name != "bmc") 102222db1728SEd Tanous { 102322db1728SEd Tanous messages::resourceNotFound(asyncResp->res, "VirtualMedia", 102422db1728SEd Tanous name); 1025107077deSPrzemyslaw Czarnowski 1026107077deSPrzemyslaw Czarnowski return; 1027107077deSPrzemyslaw Czarnowski } 1028107077deSPrzemyslaw Czarnowski 10298d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1030107077deSPrzemyslaw Czarnowski "#VirtualMediaCollection.VirtualMediaCollection"; 10318d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Virtual Media Services"; 10328d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = 1033d6c414f3SPrzemyslaw Czarnowski "/redfish/v1/Managers/" + name + "/VirtualMedia"; 1034107077deSPrzemyslaw Czarnowski 1035107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 1036107077deSPrzemyslaw Czarnowski [asyncResp, name](const boost::system::error_code ec, 1037107077deSPrzemyslaw Czarnowski const GetObjectType& getObjectType) { 1038107077deSPrzemyslaw Czarnowski if (ec) 1039107077deSPrzemyslaw Czarnowski { 104022db1728SEd Tanous BMCWEB_LOG_ERROR 104122db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 1042107077deSPrzemyslaw Czarnowski << ec; 1043107077deSPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 1044107077deSPrzemyslaw Czarnowski 1045107077deSPrzemyslaw Czarnowski return; 1046107077deSPrzemyslaw Czarnowski } 1047107077deSPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 1048107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 1049107077deSPrzemyslaw Czarnowski 1050107077deSPrzemyslaw Czarnowski getVmResourceList(asyncResp, service, name); 1051107077deSPrzemyslaw Czarnowski }, 1052107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 1053107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 1054107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 105522db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 105622db1728SEd Tanous std::array<const char*, 0>()); 105722db1728SEd Tanous }); 1058107077deSPrzemyslaw Czarnowski 105922db1728SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/") 1060ed398213SEd Tanous .privileges(redfish::privileges::getVirtualMedia) 106122db1728SEd Tanous .methods(boost::beast::http::verb::get)( 106222db1728SEd Tanous [](const crow::Request& /* req */, 106322db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 106422db1728SEd Tanous const std::string& name, const std::string& resName) { 1065107077deSPrzemyslaw Czarnowski if (name != "bmc") 1066107077deSPrzemyslaw Czarnowski { 106722db1728SEd Tanous messages::resourceNotFound(asyncResp->res, "VirtualMedia", 106822db1728SEd Tanous resName); 1069107077deSPrzemyslaw Czarnowski 1070107077deSPrzemyslaw Czarnowski return; 1071107077deSPrzemyslaw Czarnowski } 1072107077deSPrzemyslaw Czarnowski 1073107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 107422db1728SEd Tanous [asyncResp, name, 107522db1728SEd Tanous resName](const boost::system::error_code ec, 1076107077deSPrzemyslaw Czarnowski const GetObjectType& getObjectType) { 1077107077deSPrzemyslaw Czarnowski if (ec) 1078107077deSPrzemyslaw Czarnowski { 107922db1728SEd Tanous BMCWEB_LOG_ERROR 108022db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 1081107077deSPrzemyslaw Czarnowski << ec; 1082107077deSPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 1083107077deSPrzemyslaw Czarnowski 1084107077deSPrzemyslaw Czarnowski return; 1085107077deSPrzemyslaw Czarnowski } 1086107077deSPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 1087107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 1088107077deSPrzemyslaw Czarnowski 1089107077deSPrzemyslaw Czarnowski getVmData(asyncResp, service, name, resName); 1090107077deSPrzemyslaw Czarnowski }, 1091107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 1092107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 1093107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 109422db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 109522db1728SEd Tanous std::array<const char*, 0>()); 109622db1728SEd Tanous }); 1097107077deSPrzemyslaw Czarnowski } 1098107077deSPrzemyslaw Czarnowski 1099107077deSPrzemyslaw Czarnowski } // namespace redfish 1100