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 24e13c2760SPrzemyslaw Czarnowski #include <account_service.hpp> 259e319cf0SAnna Platash #include <boost/url/url_view.hpp> 26107077deSPrzemyslaw Czarnowski 27107077deSPrzemyslaw Czarnowski namespace redfish 28107077deSPrzemyslaw Czarnowski { 299e319cf0SAnna Platash /** 309e319cf0SAnna Platash * @brief Function extracts transfer protocol name from URI. 319e319cf0SAnna Platash */ 32*22db1728SEd Tanous inline std::string getTransferProtocolTypeFromUri(const std::string& imageUri) 339e319cf0SAnna Platash { 349e319cf0SAnna Platash try 359e319cf0SAnna Platash { 369e319cf0SAnna Platash std::string_view scheme = boost::urls::url_view(imageUri).scheme(); 379e319cf0SAnna Platash if (scheme == "smb") 389e319cf0SAnna Platash { 399e319cf0SAnna Platash return "CIFS"; 409e319cf0SAnna Platash } 41*22db1728SEd Tanous if (scheme == "https") 429e319cf0SAnna Platash { 439e319cf0SAnna Platash return "HTTPS"; 449e319cf0SAnna Platash } 459e319cf0SAnna Platash } 469e319cf0SAnna Platash catch (std::exception& p) 479e319cf0SAnna Platash { 489e319cf0SAnna Platash BMCWEB_LOG_ERROR << p.what(); 499e319cf0SAnna Platash } 509e319cf0SAnna Platash return "None"; 519e319cf0SAnna Platash } 52107077deSPrzemyslaw Czarnowski 53107077deSPrzemyslaw Czarnowski /** 54107077deSPrzemyslaw Czarnowski * @brief Read all known properties from VM object interfaces 55107077deSPrzemyslaw Czarnowski */ 56*22db1728SEd Tanous inline void 578d1b46d7Szhanghch05 vmParseInterfaceObject(const DbusInterfaceType& interface, 588d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& aResp) 59107077deSPrzemyslaw Czarnowski { 60107077deSPrzemyslaw Czarnowski const auto mountPointIface = 61107077deSPrzemyslaw Czarnowski interface.find("xyz.openbmc_project.VirtualMedia.MountPoint"); 62107077deSPrzemyslaw Czarnowski if (mountPointIface == interface.cend()) 63107077deSPrzemyslaw Czarnowski { 64107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Interface MountPoint not found"; 65107077deSPrzemyslaw Czarnowski return; 66107077deSPrzemyslaw Czarnowski } 67107077deSPrzemyslaw Czarnowski 68107077deSPrzemyslaw Czarnowski const auto processIface = 69107077deSPrzemyslaw Czarnowski interface.find("xyz.openbmc_project.VirtualMedia.Process"); 70107077deSPrzemyslaw Czarnowski if (processIface == interface.cend()) 71107077deSPrzemyslaw Czarnowski { 72107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Interface Process not found"; 73107077deSPrzemyslaw Czarnowski return; 74107077deSPrzemyslaw Czarnowski } 75107077deSPrzemyslaw Czarnowski 76107077deSPrzemyslaw Czarnowski const auto endpointIdProperty = mountPointIface->second.find("EndpointId"); 77107077deSPrzemyslaw Czarnowski if (endpointIdProperty == mountPointIface->second.cend()) 78107077deSPrzemyslaw Czarnowski { 79107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Property EndpointId not found"; 80107077deSPrzemyslaw Czarnowski return; 81107077deSPrzemyslaw Czarnowski } 82107077deSPrzemyslaw Czarnowski 83107077deSPrzemyslaw Czarnowski const auto activeProperty = processIface->second.find("Active"); 84107077deSPrzemyslaw Czarnowski if (activeProperty == processIface->second.cend()) 85107077deSPrzemyslaw Czarnowski { 86107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Property Active not found"; 87107077deSPrzemyslaw Czarnowski return; 88107077deSPrzemyslaw Czarnowski } 89107077deSPrzemyslaw Czarnowski 90107077deSPrzemyslaw Czarnowski const bool* activeValue = std::get_if<bool>(&activeProperty->second); 91107077deSPrzemyslaw Czarnowski if (!activeValue) 92107077deSPrzemyslaw Czarnowski { 93107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Value Active not found"; 94107077deSPrzemyslaw Czarnowski return; 95107077deSPrzemyslaw Czarnowski } 96107077deSPrzemyslaw Czarnowski 97107077deSPrzemyslaw Czarnowski const std::string* endpointIdValue = 98107077deSPrzemyslaw Czarnowski std::get_if<std::string>(&endpointIdProperty->second); 99107077deSPrzemyslaw Czarnowski if (endpointIdValue) 100107077deSPrzemyslaw Czarnowski { 101107077deSPrzemyslaw Czarnowski if (!endpointIdValue->empty()) 102107077deSPrzemyslaw Czarnowski { 103107077deSPrzemyslaw Czarnowski // Proxy mode 104d04ba325SPrzemyslaw Czarnowski aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] = 105d04ba325SPrzemyslaw Czarnowski *endpointIdValue; 106107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["TransferProtocolType"] = "OEM"; 107107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Inserted"] = *activeValue; 108107077deSPrzemyslaw Czarnowski if (*activeValue == true) 109107077deSPrzemyslaw Czarnowski { 110107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["ConnectedVia"] = "Applet"; 111107077deSPrzemyslaw Czarnowski } 112107077deSPrzemyslaw Czarnowski } 113107077deSPrzemyslaw Czarnowski else 114107077deSPrzemyslaw Czarnowski { 115107077deSPrzemyslaw Czarnowski // Legacy mode 1169e319cf0SAnna Platash for (const auto& property : mountPointIface->second) 1179e319cf0SAnna Platash { 1189e319cf0SAnna Platash if (property.first == "ImageURL") 119107077deSPrzemyslaw Czarnowski { 120107077deSPrzemyslaw Czarnowski const std::string* imageUrlValue = 1219e319cf0SAnna Platash std::get_if<std::string>(&property.second); 122107077deSPrzemyslaw Czarnowski if (imageUrlValue && !imageUrlValue->empty()) 123107077deSPrzemyslaw Czarnowski { 124da4784d8SPrzemyslaw Czarnowski std::filesystem::path filePath = *imageUrlValue; 125da4784d8SPrzemyslaw Czarnowski if (!filePath.has_filename()) 126da4784d8SPrzemyslaw Czarnowski { 1279e319cf0SAnna Platash // this will handle https share, which not 1289e319cf0SAnna Platash // necessarily has to have filename given. 129da4784d8SPrzemyslaw Czarnowski aResp->res.jsonValue["ImageName"] = ""; 130da4784d8SPrzemyslaw Czarnowski } 131da4784d8SPrzemyslaw Czarnowski else 132da4784d8SPrzemyslaw Czarnowski { 1339e319cf0SAnna Platash aResp->res.jsonValue["ImageName"] = 1349e319cf0SAnna Platash filePath.filename(); 135da4784d8SPrzemyslaw Czarnowski } 136da4784d8SPrzemyslaw Czarnowski 137da4784d8SPrzemyslaw Czarnowski aResp->res.jsonValue["Image"] = *imageUrlValue; 138107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Inserted"] = *activeValue; 1399e319cf0SAnna Platash aResp->res.jsonValue["TransferProtocolType"] = 1409e319cf0SAnna Platash getTransferProtocolTypeFromUri(*imageUrlValue); 1419e319cf0SAnna Platash 142107077deSPrzemyslaw Czarnowski if (*activeValue == true) 143107077deSPrzemyslaw Czarnowski { 144107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["ConnectedVia"] = "URI"; 145107077deSPrzemyslaw Czarnowski } 146107077deSPrzemyslaw Czarnowski } 147107077deSPrzemyslaw Czarnowski } 1489e319cf0SAnna Platash else if (property.first == "WriteProtected") 1499e319cf0SAnna Platash { 1509e319cf0SAnna Platash const bool* writeProtectedValue = 1519e319cf0SAnna Platash std::get_if<bool>(&property.second); 1529e319cf0SAnna Platash if (writeProtectedValue) 1539e319cf0SAnna Platash { 1549e319cf0SAnna Platash aResp->res.jsonValue["WriteProtected"] = 1559e319cf0SAnna Platash *writeProtectedValue; 1569e319cf0SAnna Platash } 1579e319cf0SAnna Platash } 1589e319cf0SAnna Platash } 159107077deSPrzemyslaw Czarnowski } 160107077deSPrzemyslaw Czarnowski } 161107077deSPrzemyslaw Czarnowski } 162107077deSPrzemyslaw Czarnowski 163107077deSPrzemyslaw Czarnowski /** 164107077deSPrzemyslaw Czarnowski * @brief Fill template for Virtual Media Item. 165107077deSPrzemyslaw Czarnowski */ 166*22db1728SEd Tanous inline nlohmann::json vmItemTemplate(const std::string& name, 167107077deSPrzemyslaw Czarnowski const std::string& resName) 168107077deSPrzemyslaw Czarnowski { 169107077deSPrzemyslaw Czarnowski nlohmann::json item; 170*22db1728SEd Tanous 171*22db1728SEd Tanous std::string id = "/redfish/v1/Managers/"; 172*22db1728SEd Tanous id += name; 173*22db1728SEd Tanous id += "/VirtualMedia/"; 174*22db1728SEd Tanous id += resName; 175*22db1728SEd Tanous item["@odata.id"] = std::move(id); 176*22db1728SEd Tanous 177d04ba325SPrzemyslaw Czarnowski item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia"; 178107077deSPrzemyslaw Czarnowski item["Name"] = "Virtual Removable Media"; 179107077deSPrzemyslaw Czarnowski item["Id"] = resName; 180107077deSPrzemyslaw Czarnowski item["WriteProtected"] = true; 181107077deSPrzemyslaw Czarnowski item["MediaTypes"] = {"CD", "USBStick"}; 182107077deSPrzemyslaw Czarnowski item["TransferMethod"] = "Stream"; 183d04ba325SPrzemyslaw Czarnowski item["Oem"]["OpenBMC"]["@odata.type"] = 184d04ba325SPrzemyslaw Czarnowski "#OemVirtualMedia.v1_0_0.VirtualMedia"; 185107077deSPrzemyslaw Czarnowski 186107077deSPrzemyslaw Czarnowski return item; 187107077deSPrzemyslaw Czarnowski } 188107077deSPrzemyslaw Czarnowski 189107077deSPrzemyslaw Czarnowski /** 190107077deSPrzemyslaw Czarnowski * @brief Fills collection data 191107077deSPrzemyslaw Czarnowski */ 192*22db1728SEd Tanous inline void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> aResp, 193107077deSPrzemyslaw Czarnowski const std::string& service, 194107077deSPrzemyslaw Czarnowski const std::string& name) 195107077deSPrzemyslaw Czarnowski { 196107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Get available Virtual Media resources."; 197107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 198107077deSPrzemyslaw Czarnowski [name, aResp{std::move(aResp)}](const boost::system::error_code ec, 199107077deSPrzemyslaw Czarnowski ManagedObjectType& subtree) { 200107077deSPrzemyslaw Czarnowski if (ec) 201107077deSPrzemyslaw Czarnowski { 202107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "DBUS response error"; 203107077deSPrzemyslaw Czarnowski return; 204107077deSPrzemyslaw Czarnowski } 205107077deSPrzemyslaw Czarnowski nlohmann::json& members = aResp->res.jsonValue["Members"]; 206107077deSPrzemyslaw Czarnowski members = nlohmann::json::array(); 207107077deSPrzemyslaw Czarnowski 208107077deSPrzemyslaw Czarnowski for (const auto& object : subtree) 209107077deSPrzemyslaw Czarnowski { 210107077deSPrzemyslaw Czarnowski nlohmann::json item; 2112dfd18efSEd Tanous std::string path = object.first.filename(); 2122dfd18efSEd Tanous if (path.empty()) 213107077deSPrzemyslaw Czarnowski { 214107077deSPrzemyslaw Czarnowski continue; 215107077deSPrzemyslaw Czarnowski } 216107077deSPrzemyslaw Czarnowski 217*22db1728SEd Tanous std::string id = "/redfish/v1/Managers/"; 218*22db1728SEd Tanous id += name; 219*22db1728SEd Tanous id += "/VirtualMedia/"; 220*22db1728SEd Tanous id += path; 221107077deSPrzemyslaw Czarnowski 222*22db1728SEd Tanous item["@odata.id"] = std::move(id); 223107077deSPrzemyslaw Czarnowski members.emplace_back(std::move(item)); 224107077deSPrzemyslaw Czarnowski } 225107077deSPrzemyslaw Czarnowski aResp->res.jsonValue["Members@odata.count"] = members.size(); 226107077deSPrzemyslaw Czarnowski }, 227107077deSPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia", 228107077deSPrzemyslaw Czarnowski "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 229107077deSPrzemyslaw Czarnowski } 230107077deSPrzemyslaw Czarnowski 231107077deSPrzemyslaw Czarnowski /** 232107077deSPrzemyslaw Czarnowski * @brief Fills data for specific resource 233107077deSPrzemyslaw Czarnowski */ 234*22db1728SEd Tanous inline void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 235107077deSPrzemyslaw Czarnowski const std::string& service, const std::string& name, 236107077deSPrzemyslaw Czarnowski const std::string& resName) 237107077deSPrzemyslaw Czarnowski { 238107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "Get Virtual Media resource data."; 239107077deSPrzemyslaw Czarnowski 240107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 241107077deSPrzemyslaw Czarnowski [resName, name, aResp](const boost::system::error_code ec, 242107077deSPrzemyslaw Czarnowski ManagedObjectType& subtree) { 243107077deSPrzemyslaw Czarnowski if (ec) 244107077deSPrzemyslaw Czarnowski { 245107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "DBUS response error"; 246e13c2760SPrzemyslaw Czarnowski 247107077deSPrzemyslaw Czarnowski return; 248107077deSPrzemyslaw Czarnowski } 249107077deSPrzemyslaw Czarnowski 250107077deSPrzemyslaw Czarnowski for (auto& item : subtree) 251107077deSPrzemyslaw Czarnowski { 2522dfd18efSEd Tanous std::string thispath = item.first.filename(); 2532dfd18efSEd Tanous if (thispath.empty()) 254107077deSPrzemyslaw Czarnowski { 255107077deSPrzemyslaw Czarnowski continue; 256107077deSPrzemyslaw Czarnowski } 257107077deSPrzemyslaw Czarnowski 2582dfd18efSEd Tanous if (thispath != resName) 259107077deSPrzemyslaw Czarnowski { 260107077deSPrzemyslaw Czarnowski continue; 261107077deSPrzemyslaw Czarnowski } 262107077deSPrzemyslaw Czarnowski 2631a6258dcSPrzemyslaw Czarnowski // "Legacy"/"Proxy" 2641a6258dcSPrzemyslaw Czarnowski auto mode = item.first.parent_path(); 2651a6258dcSPrzemyslaw Czarnowski // "VirtualMedia" 2661a6258dcSPrzemyslaw Czarnowski auto type = mode.parent_path(); 2671a6258dcSPrzemyslaw Czarnowski if (mode.filename().empty() || type.filename().empty()) 2681a6258dcSPrzemyslaw Czarnowski { 2691a6258dcSPrzemyslaw Czarnowski continue; 2701a6258dcSPrzemyslaw Czarnowski } 2711a6258dcSPrzemyslaw Czarnowski 2721a6258dcSPrzemyslaw Czarnowski if (type.filename() != "VirtualMedia") 2731a6258dcSPrzemyslaw Czarnowski { 2741a6258dcSPrzemyslaw Czarnowski continue; 2751a6258dcSPrzemyslaw Czarnowski } 2761a6258dcSPrzemyslaw Czarnowski 277107077deSPrzemyslaw Czarnowski aResp->res.jsonValue = vmItemTemplate(name, resName); 278*22db1728SEd Tanous std::string actionsId = "/redfish/v1/Managers/"; 279*22db1728SEd Tanous actionsId += name; 280*22db1728SEd Tanous actionsId += "/VirtualMedia/"; 281*22db1728SEd Tanous actionsId += resName; 282*22db1728SEd Tanous actionsId += "/Actions"; 283107077deSPrzemyslaw Czarnowski 284e13c2760SPrzemyslaw Czarnowski // Check if dbus path is Legacy type 2851a6258dcSPrzemyslaw Czarnowski if (mode.filename() == "Legacy") 286e13c2760SPrzemyslaw Czarnowski { 287e13c2760SPrzemyslaw Czarnowski aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"] 288e13c2760SPrzemyslaw Czarnowski ["target"] = 289*22db1728SEd Tanous actionsId + "/VirtualMedia.InsertMedia"; 290e13c2760SPrzemyslaw Czarnowski } 291e13c2760SPrzemyslaw Czarnowski 292107077deSPrzemyslaw Czarnowski vmParseInterfaceObject(item.second, aResp); 293107077deSPrzemyslaw Czarnowski 294e13c2760SPrzemyslaw Czarnowski aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"] 295e13c2760SPrzemyslaw Czarnowski ["target"] = 296*22db1728SEd Tanous actionsId + "/VirtualMedia.EjectMedia"; 297e13c2760SPrzemyslaw Czarnowski 298107077deSPrzemyslaw Czarnowski return; 299107077deSPrzemyslaw Czarnowski } 300107077deSPrzemyslaw Czarnowski 301107077deSPrzemyslaw Czarnowski messages::resourceNotFound( 302d04ba325SPrzemyslaw Czarnowski aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName); 303107077deSPrzemyslaw Czarnowski }, 304107077deSPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia", 305107077deSPrzemyslaw Czarnowski "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 306107077deSPrzemyslaw Czarnowski } 307107077deSPrzemyslaw Czarnowski 308e13c2760SPrzemyslaw Czarnowski /** 309c6f4e017SAgata Olender * @brief Transfer protocols supported for InsertMedia action. 310c6f4e017SAgata Olender * 311c6f4e017SAgata Olender */ 312c6f4e017SAgata Olender enum class TransferProtocol 313c6f4e017SAgata Olender { 314c6f4e017SAgata Olender https, 315c6f4e017SAgata Olender smb, 316c6f4e017SAgata Olender invalid 317c6f4e017SAgata Olender }; 318c6f4e017SAgata Olender 319c6f4e017SAgata Olender /** 320c6f4e017SAgata Olender * @brief Function extracts transfer protocol type from URI. 321c6f4e017SAgata Olender * 322c6f4e017SAgata Olender */ 323*22db1728SEd Tanous inline std::optional<TransferProtocol> 324c6f4e017SAgata Olender getTransferProtocolFromUri(const std::string& imageUri) 325c6f4e017SAgata Olender { 3269e319cf0SAnna Platash try 3279e319cf0SAnna Platash { 3289e319cf0SAnna Platash std::string_view scheme = boost::urls::url_view(imageUri).scheme(); 3299e319cf0SAnna Platash if (scheme == "smb") 330c6f4e017SAgata Olender { 331c6f4e017SAgata Olender return TransferProtocol::smb; 332c6f4e017SAgata Olender } 33381ce609eSEd Tanous if (scheme == "https") 334c6f4e017SAgata Olender { 335c6f4e017SAgata Olender return TransferProtocol::https; 336c6f4e017SAgata Olender } 337*22db1728SEd Tanous if (!scheme.empty()) 338c6f4e017SAgata Olender { 339c6f4e017SAgata Olender return TransferProtocol::invalid; 340c6f4e017SAgata Olender } 341c6f4e017SAgata Olender } 3429e319cf0SAnna Platash catch (std::exception& p) 3439e319cf0SAnna Platash { 3449e319cf0SAnna Platash BMCWEB_LOG_ERROR << p.what(); 3459e319cf0SAnna Platash } 3469e319cf0SAnna Platash 3479e319cf0SAnna Platash return {}; 348c6f4e017SAgata Olender } 349c6f4e017SAgata Olender 350c6f4e017SAgata Olender /** 351c6f4e017SAgata Olender * @brief Function convert transfer protocol from string param. 352c6f4e017SAgata Olender * 353c6f4e017SAgata Olender */ 354*22db1728SEd Tanous inline std::optional<TransferProtocol> getTransferProtocolFromParam( 355c6f4e017SAgata Olender const std::optional<std::string>& transferProtocolType) 356c6f4e017SAgata Olender { 357c6f4e017SAgata Olender if (transferProtocolType == std::nullopt) 358c6f4e017SAgata Olender { 359c6f4e017SAgata Olender return {}; 360c6f4e017SAgata Olender } 361c6f4e017SAgata Olender 362c6f4e017SAgata Olender if (*transferProtocolType == "CIFS") 363c6f4e017SAgata Olender { 364c6f4e017SAgata Olender return TransferProtocol::smb; 365c6f4e017SAgata Olender } 366c6f4e017SAgata Olender 367c6f4e017SAgata Olender if (*transferProtocolType == "HTTPS") 368c6f4e017SAgata Olender { 369c6f4e017SAgata Olender return TransferProtocol::https; 370c6f4e017SAgata Olender } 371c6f4e017SAgata Olender 372c6f4e017SAgata Olender return TransferProtocol::invalid; 373c6f4e017SAgata Olender } 374c6f4e017SAgata Olender 375c6f4e017SAgata Olender /** 376c6f4e017SAgata Olender * @brief Function extends URI with transfer protocol type. 377c6f4e017SAgata Olender * 378c6f4e017SAgata Olender */ 379*22db1728SEd Tanous inline std::string 380c6f4e017SAgata Olender getUriWithTransferProtocol(const std::string& imageUri, 381c6f4e017SAgata Olender const TransferProtocol& transferProtocol) 382c6f4e017SAgata Olender { 383c6f4e017SAgata Olender if (transferProtocol == TransferProtocol::smb) 384c6f4e017SAgata Olender { 385c6f4e017SAgata Olender return "smb://" + imageUri; 386c6f4e017SAgata Olender } 387c6f4e017SAgata Olender 388c6f4e017SAgata Olender if (transferProtocol == TransferProtocol::https) 389c6f4e017SAgata Olender { 390c6f4e017SAgata Olender return "https://" + imageUri; 391c6f4e017SAgata Olender } 392c6f4e017SAgata Olender 393c6f4e017SAgata Olender return imageUri; 394c6f4e017SAgata Olender } 395c6f4e017SAgata Olender 396c6f4e017SAgata Olender /** 397c6f4e017SAgata Olender * @brief Function validate parameters of insert media request. 398c6f4e017SAgata Olender * 399c6f4e017SAgata Olender */ 400*22db1728SEd Tanous inline bool 401*22db1728SEd Tanous validateParams(crow::Response& res, std::string& imageUrl, 402c6f4e017SAgata Olender const std::optional<bool>& inserted, 403c6f4e017SAgata Olender const std::optional<std::string>& transferMethod, 404c6f4e017SAgata Olender const std::optional<std::string>& transferProtocolType) 405c6f4e017SAgata Olender { 406c6f4e017SAgata Olender BMCWEB_LOG_DEBUG << "Validation started"; 407c6f4e017SAgata Olender // required param imageUrl must not be empty 408c6f4e017SAgata Olender if (imageUrl.empty()) 409c6f4e017SAgata Olender { 410c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter Image is empty."; 411c6f4e017SAgata Olender 412*22db1728SEd Tanous messages::propertyValueFormatError(res, "<empty>", "Image"); 413c6f4e017SAgata Olender 414c6f4e017SAgata Olender return false; 415c6f4e017SAgata Olender } 416c6f4e017SAgata Olender 417c6f4e017SAgata Olender // optional param inserted must be true 418c6f4e017SAgata Olender if ((inserted != std::nullopt) && (*inserted != true)) 419c6f4e017SAgata Olender { 420c6f4e017SAgata Olender BMCWEB_LOG_ERROR 421c6f4e017SAgata Olender << "Request action optional parameter Inserted must be true."; 422c6f4e017SAgata Olender 423*22db1728SEd Tanous messages::actionParameterNotSupported(res, "Inserted", "InsertMedia"); 424c6f4e017SAgata Olender 425c6f4e017SAgata Olender return false; 426c6f4e017SAgata Olender } 427c6f4e017SAgata Olender 428c6f4e017SAgata Olender // optional param transferMethod must be stream 429c6f4e017SAgata Olender if ((transferMethod != std::nullopt) && (*transferMethod != "Stream")) 430c6f4e017SAgata Olender { 431c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action optional parameter " 432c6f4e017SAgata Olender "TransferMethod must be Stream."; 433c6f4e017SAgata Olender 434*22db1728SEd Tanous messages::actionParameterNotSupported(res, "TransferMethod", 435*22db1728SEd Tanous "InsertMedia"); 436c6f4e017SAgata Olender 437c6f4e017SAgata Olender return false; 438c6f4e017SAgata Olender } 439c6f4e017SAgata Olender 440c6f4e017SAgata Olender std::optional<TransferProtocol> uriTransferProtocolType = 441c6f4e017SAgata Olender getTransferProtocolFromUri(imageUrl); 442c6f4e017SAgata Olender 443c6f4e017SAgata Olender std::optional<TransferProtocol> paramTransferProtocolType = 444c6f4e017SAgata Olender getTransferProtocolFromParam(transferProtocolType); 445c6f4e017SAgata Olender 446c6f4e017SAgata Olender // ImageUrl does not contain valid protocol type 447c6f4e017SAgata Olender if (*uriTransferProtocolType == TransferProtocol::invalid) 448c6f4e017SAgata Olender { 449c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must " 450c6f4e017SAgata Olender "contain specified protocol type from list: " 451c6f4e017SAgata Olender "(smb, https)."; 452c6f4e017SAgata Olender 453*22db1728SEd Tanous messages::resourceAtUriInUnknownFormat(res, imageUrl); 454c6f4e017SAgata Olender 455c6f4e017SAgata Olender return false; 456c6f4e017SAgata Olender } 457c6f4e017SAgata Olender 458c6f4e017SAgata Olender // transferProtocolType should contain value from list 459c6f4e017SAgata Olender if (*paramTransferProtocolType == TransferProtocol::invalid) 460c6f4e017SAgata Olender { 461c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType " 462c6f4e017SAgata Olender "must be provided with value from list: " 463c6f4e017SAgata Olender "(CIFS, HTTPS)."; 464c6f4e017SAgata Olender 465*22db1728SEd Tanous messages::propertyValueNotInList(res, *transferProtocolType, 466*22db1728SEd Tanous "TransferProtocolType"); 467c6f4e017SAgata Olender return false; 468c6f4e017SAgata Olender } 469c6f4e017SAgata Olender 470c6f4e017SAgata Olender // valid transfer protocol not provided either with URI nor param 471c6f4e017SAgata Olender if ((uriTransferProtocolType == std::nullopt) && 472c6f4e017SAgata Olender (paramTransferProtocolType == std::nullopt)) 473c6f4e017SAgata Olender { 474c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must " 475c6f4e017SAgata Olender "contain specified protocol type or param " 476c6f4e017SAgata Olender "TransferProtocolType must be provided."; 477c6f4e017SAgata Olender 478*22db1728SEd Tanous messages::resourceAtUriInUnknownFormat(res, imageUrl); 479c6f4e017SAgata Olender 480c6f4e017SAgata Olender return false; 481c6f4e017SAgata Olender } 482c6f4e017SAgata Olender 483c6f4e017SAgata Olender // valid transfer protocol provided both with URI and param 484c6f4e017SAgata Olender if ((paramTransferProtocolType != std::nullopt) && 485c6f4e017SAgata Olender (uriTransferProtocolType != std::nullopt)) 486c6f4e017SAgata Olender { 487c6f4e017SAgata Olender // check if protocol is the same for URI and param 488c6f4e017SAgata Olender if (*paramTransferProtocolType != *uriTransferProtocolType) 489c6f4e017SAgata Olender { 490c6f4e017SAgata Olender BMCWEB_LOG_ERROR << "Request action parameter " 491c6f4e017SAgata Olender "TransferProtocolType must contain the " 492c6f4e017SAgata Olender "same protocol type as protocol type " 493c6f4e017SAgata Olender "provided with param imageUrl."; 494c6f4e017SAgata Olender 495*22db1728SEd Tanous messages::actionParameterValueTypeError(res, *transferProtocolType, 496*22db1728SEd Tanous "TransferProtocolType", 497*22db1728SEd Tanous "InsertMedia"); 498c6f4e017SAgata Olender 499c6f4e017SAgata Olender return false; 500c6f4e017SAgata Olender } 501c6f4e017SAgata Olender } 502c6f4e017SAgata Olender 503c6f4e017SAgata Olender // validation passed 504c6f4e017SAgata Olender // add protocol to URI if needed 505c6f4e017SAgata Olender if (uriTransferProtocolType == std::nullopt) 506c6f4e017SAgata Olender { 507*22db1728SEd Tanous imageUrl = 508*22db1728SEd Tanous getUriWithTransferProtocol(imageUrl, *paramTransferProtocolType); 509c6f4e017SAgata Olender } 510c6f4e017SAgata Olender 511c6f4e017SAgata Olender return true; 512c6f4e017SAgata Olender } 513c6f4e017SAgata Olender 5141214b7e7SGunnar Mills template <typename T> 5151214b7e7SGunnar Mills static void secureCleanup(T& value) 516988fb7b2SAdrian Ambrożewicz { 517988fb7b2SAdrian Ambrożewicz auto raw = const_cast<typename T::value_type*>(value.data()); 518988fb7b2SAdrian Ambrożewicz explicit_bzero(raw, value.size() * sizeof(*raw)); 519988fb7b2SAdrian Ambrożewicz } 520988fb7b2SAdrian Ambrożewicz 521988fb7b2SAdrian Ambrożewicz class Credentials 522988fb7b2SAdrian Ambrożewicz { 523988fb7b2SAdrian Ambrożewicz public: 524988fb7b2SAdrian Ambrożewicz Credentials(std::string&& user, std::string&& password) : 525988fb7b2SAdrian Ambrożewicz userBuf(std::move(user)), passBuf(std::move(password)) 5261214b7e7SGunnar Mills {} 527988fb7b2SAdrian Ambrożewicz 528988fb7b2SAdrian Ambrożewicz ~Credentials() 529988fb7b2SAdrian Ambrożewicz { 530988fb7b2SAdrian Ambrożewicz secureCleanup(userBuf); 531988fb7b2SAdrian Ambrożewicz secureCleanup(passBuf); 532988fb7b2SAdrian Ambrożewicz } 533988fb7b2SAdrian Ambrożewicz 534988fb7b2SAdrian Ambrożewicz const std::string& user() 535988fb7b2SAdrian Ambrożewicz { 536988fb7b2SAdrian Ambrożewicz return userBuf; 537988fb7b2SAdrian Ambrożewicz } 538988fb7b2SAdrian Ambrożewicz 539988fb7b2SAdrian Ambrożewicz const std::string& password() 540988fb7b2SAdrian Ambrożewicz { 541988fb7b2SAdrian Ambrożewicz return passBuf; 542988fb7b2SAdrian Ambrożewicz } 543988fb7b2SAdrian Ambrożewicz 544988fb7b2SAdrian Ambrożewicz Credentials() = delete; 545988fb7b2SAdrian Ambrożewicz Credentials(const Credentials&) = delete; 546988fb7b2SAdrian Ambrożewicz Credentials& operator=(const Credentials&) = delete; 547988fb7b2SAdrian Ambrożewicz 548*22db1728SEd Tanous private: 549988fb7b2SAdrian Ambrożewicz std::string userBuf; 550988fb7b2SAdrian Ambrożewicz std::string passBuf; 551988fb7b2SAdrian Ambrożewicz }; 552988fb7b2SAdrian Ambrożewicz 553988fb7b2SAdrian Ambrożewicz class CredentialsProvider 554988fb7b2SAdrian Ambrożewicz { 555988fb7b2SAdrian Ambrożewicz public: 5561214b7e7SGunnar Mills template <typename T> 5571214b7e7SGunnar Mills struct Deleter 558988fb7b2SAdrian Ambrożewicz { 559988fb7b2SAdrian Ambrożewicz void operator()(T* buff) const 560988fb7b2SAdrian Ambrożewicz { 561988fb7b2SAdrian Ambrożewicz if (buff) 562988fb7b2SAdrian Ambrożewicz { 563988fb7b2SAdrian Ambrożewicz secureCleanup(*buff); 564988fb7b2SAdrian Ambrożewicz delete buff; 565988fb7b2SAdrian Ambrożewicz } 566988fb7b2SAdrian Ambrożewicz } 567988fb7b2SAdrian Ambrożewicz }; 568988fb7b2SAdrian Ambrożewicz 569988fb7b2SAdrian Ambrożewicz using Buffer = std::vector<char>; 570988fb7b2SAdrian Ambrożewicz using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>; 571988fb7b2SAdrian Ambrożewicz // Using explicit definition instead of std::function to avoid implicit 572988fb7b2SAdrian Ambrożewicz // conversions eg. stack copy instead of reference 573988fb7b2SAdrian Ambrożewicz using FormatterFunc = void(const std::string& username, 574988fb7b2SAdrian Ambrożewicz const std::string& password, Buffer& dest); 575988fb7b2SAdrian Ambrożewicz 576988fb7b2SAdrian Ambrożewicz CredentialsProvider(std::string&& user, std::string&& password) : 577988fb7b2SAdrian Ambrożewicz credentials(std::move(user), std::move(password)) 5781214b7e7SGunnar Mills {} 579988fb7b2SAdrian Ambrożewicz 580988fb7b2SAdrian Ambrożewicz const std::string& user() 581988fb7b2SAdrian Ambrożewicz { 582988fb7b2SAdrian Ambrożewicz return credentials.user(); 583988fb7b2SAdrian Ambrożewicz } 584988fb7b2SAdrian Ambrożewicz 585988fb7b2SAdrian Ambrożewicz const std::string& password() 586988fb7b2SAdrian Ambrożewicz { 587988fb7b2SAdrian Ambrożewicz return credentials.password(); 588988fb7b2SAdrian Ambrożewicz } 589988fb7b2SAdrian Ambrożewicz 59081ce609eSEd Tanous SecureBuffer pack(FormatterFunc formatter) 591988fb7b2SAdrian Ambrożewicz { 592988fb7b2SAdrian Ambrożewicz SecureBuffer packed{new Buffer{}}; 593988fb7b2SAdrian Ambrożewicz if (formatter) 594988fb7b2SAdrian Ambrożewicz { 595988fb7b2SAdrian Ambrożewicz formatter(credentials.user(), credentials.password(), *packed); 596988fb7b2SAdrian Ambrożewicz } 597988fb7b2SAdrian Ambrożewicz 598988fb7b2SAdrian Ambrożewicz return packed; 599988fb7b2SAdrian Ambrożewicz } 600988fb7b2SAdrian Ambrożewicz 601988fb7b2SAdrian Ambrożewicz private: 602988fb7b2SAdrian Ambrożewicz Credentials credentials; 603988fb7b2SAdrian Ambrożewicz }; 604988fb7b2SAdrian Ambrożewicz 605988fb7b2SAdrian Ambrożewicz // Wrapper for boost::async_pipe ensuring proper pipe cleanup 6061214b7e7SGunnar Mills template <typename Buffer> 6071214b7e7SGunnar Mills class Pipe 608988fb7b2SAdrian Ambrożewicz { 609988fb7b2SAdrian Ambrożewicz public: 610988fb7b2SAdrian Ambrożewicz using unix_fd = sdbusplus::message::unix_fd; 611988fb7b2SAdrian Ambrożewicz 612988fb7b2SAdrian Ambrożewicz Pipe(boost::asio::io_context& io, Buffer&& buffer) : 613988fb7b2SAdrian Ambrożewicz impl(io), buffer{std::move(buffer)} 6141214b7e7SGunnar Mills {} 615988fb7b2SAdrian Ambrożewicz 616988fb7b2SAdrian Ambrożewicz ~Pipe() 617988fb7b2SAdrian Ambrożewicz { 618988fb7b2SAdrian Ambrożewicz // Named pipe needs to be explicitly removed 619988fb7b2SAdrian Ambrożewicz impl.close(); 620988fb7b2SAdrian Ambrożewicz } 621988fb7b2SAdrian Ambrożewicz 622988fb7b2SAdrian Ambrożewicz unix_fd fd() 623988fb7b2SAdrian Ambrożewicz { 624988fb7b2SAdrian Ambrożewicz return unix_fd{impl.native_source()}; 625988fb7b2SAdrian Ambrożewicz } 626988fb7b2SAdrian Ambrożewicz 627988fb7b2SAdrian Ambrożewicz template <typename WriteHandler> 62881ce609eSEd Tanous void asyncWrite(WriteHandler&& handler) 629988fb7b2SAdrian Ambrożewicz { 630988fb7b2SAdrian Ambrożewicz impl.async_write_some(data(), std::forward<WriteHandler>(handler)); 631988fb7b2SAdrian Ambrożewicz } 632988fb7b2SAdrian Ambrożewicz 633988fb7b2SAdrian Ambrożewicz private: 634988fb7b2SAdrian Ambrożewicz // Specialization for pointer types 635988fb7b2SAdrian Ambrożewicz template <typename B = Buffer> 636988fb7b2SAdrian Ambrożewicz typename std::enable_if<boost::has_dereference<B>::value, 637988fb7b2SAdrian Ambrożewicz boost::asio::const_buffer>::type 638988fb7b2SAdrian Ambrożewicz data() 639988fb7b2SAdrian Ambrożewicz { 640988fb7b2SAdrian Ambrożewicz return boost::asio::buffer(*buffer); 641988fb7b2SAdrian Ambrożewicz } 642988fb7b2SAdrian Ambrożewicz 643988fb7b2SAdrian Ambrożewicz template <typename B = Buffer> 644988fb7b2SAdrian Ambrożewicz typename std::enable_if<!boost::has_dereference<B>::value, 645988fb7b2SAdrian Ambrożewicz boost::asio::const_buffer>::type 646988fb7b2SAdrian Ambrożewicz data() 647988fb7b2SAdrian Ambrożewicz { 648988fb7b2SAdrian Ambrożewicz return boost::asio::buffer(buffer); 649988fb7b2SAdrian Ambrożewicz } 650988fb7b2SAdrian Ambrożewicz 651988fb7b2SAdrian Ambrożewicz const std::string name; 652988fb7b2SAdrian Ambrożewicz boost::process::async_pipe impl; 653988fb7b2SAdrian Ambrożewicz Buffer buffer; 654988fb7b2SAdrian Ambrożewicz }; 655988fb7b2SAdrian Ambrożewicz 656e13c2760SPrzemyslaw Czarnowski /** 657e13c2760SPrzemyslaw Czarnowski * @brief Function transceives data with dbus directly. 658e13c2760SPrzemyslaw Czarnowski * 659e13c2760SPrzemyslaw Czarnowski * All BMC state properties will be retrieved before sending reset request. 660e13c2760SPrzemyslaw Czarnowski */ 661*22db1728SEd Tanous inline void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 662e13c2760SPrzemyslaw Czarnowski const std::string& service, const std::string& name, 663988fb7b2SAdrian Ambrożewicz const std::string& imageUrl, const bool rw, 664988fb7b2SAdrian Ambrożewicz std::string&& userName, std::string&& password) 665e13c2760SPrzemyslaw Czarnowski { 666988fb7b2SAdrian Ambrożewicz using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>; 667988fb7b2SAdrian Ambrożewicz constexpr const size_t secretLimit = 1024; 668988fb7b2SAdrian Ambrożewicz 669988fb7b2SAdrian Ambrożewicz std::shared_ptr<SecurePipe> secretPipe; 670988fb7b2SAdrian Ambrożewicz std::variant<int, SecurePipe::unix_fd> unixFd = -1; 671988fb7b2SAdrian Ambrożewicz 672988fb7b2SAdrian Ambrożewicz if (!userName.empty() || !password.empty()) 673988fb7b2SAdrian Ambrożewicz { 674988fb7b2SAdrian Ambrożewicz // Encapsulate in safe buffer 675988fb7b2SAdrian Ambrożewicz CredentialsProvider credentials(std::move(userName), 676988fb7b2SAdrian Ambrożewicz std::move(password)); 677988fb7b2SAdrian Ambrożewicz 678988fb7b2SAdrian Ambrożewicz // Payload must contain data + NULL delimiters 679988fb7b2SAdrian Ambrożewicz if (credentials.user().size() + credentials.password().size() + 2 > 680988fb7b2SAdrian Ambrożewicz secretLimit) 681988fb7b2SAdrian Ambrożewicz { 682988fb7b2SAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Credentials too long to handle"; 683988fb7b2SAdrian Ambrożewicz messages::unrecognizedRequestBody(asyncResp->res); 684988fb7b2SAdrian Ambrożewicz return; 685988fb7b2SAdrian Ambrożewicz } 686988fb7b2SAdrian Ambrożewicz 687988fb7b2SAdrian Ambrożewicz // Pack secret 688*22db1728SEd Tanous auto secret = credentials.pack( 689*22db1728SEd Tanous [](const auto& user, const auto& pass, auto& buff) { 690988fb7b2SAdrian Ambrożewicz std::copy(user.begin(), user.end(), std::back_inserter(buff)); 691988fb7b2SAdrian Ambrożewicz buff.push_back('\0'); 692988fb7b2SAdrian Ambrożewicz std::copy(pass.begin(), pass.end(), std::back_inserter(buff)); 693988fb7b2SAdrian Ambrożewicz buff.push_back('\0'); 694988fb7b2SAdrian Ambrożewicz }); 695988fb7b2SAdrian Ambrożewicz 696988fb7b2SAdrian Ambrożewicz // Open pipe 697988fb7b2SAdrian Ambrożewicz secretPipe = std::make_shared<SecurePipe>( 698*22db1728SEd Tanous crow::connections::systemBus->get_io_context(), std::move(secret)); 699988fb7b2SAdrian Ambrożewicz unixFd = secretPipe->fd(); 700988fb7b2SAdrian Ambrożewicz 701988fb7b2SAdrian Ambrożewicz // Pass secret over pipe 70281ce609eSEd Tanous secretPipe->asyncWrite( 703f5b16f03SVikram Bodireddy [asyncResp](const boost::system::error_code& ec, std::size_t) { 704988fb7b2SAdrian Ambrożewicz if (ec) 705988fb7b2SAdrian Ambrożewicz { 706988fb7b2SAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec; 707988fb7b2SAdrian Ambrożewicz messages::internalError(asyncResp->res); 708988fb7b2SAdrian Ambrożewicz } 709988fb7b2SAdrian Ambrożewicz }); 710988fb7b2SAdrian Ambrożewicz } 711988fb7b2SAdrian Ambrożewicz 712e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 713988fb7b2SAdrian Ambrożewicz [asyncResp, secretPipe](const boost::system::error_code ec, 714988fb7b2SAdrian Ambrożewicz bool success) { 715e13c2760SPrzemyslaw Czarnowski if (ec) 716e13c2760SPrzemyslaw Czarnowski { 717e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 718e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 719d6da5bebSAdrian Ambrożewicz } 720d6da5bebSAdrian Ambrożewicz else if (!success) 721d6da5bebSAdrian Ambrożewicz { 722d6da5bebSAdrian Ambrożewicz BMCWEB_LOG_ERROR << "Service responded with error"; 723d6da5bebSAdrian Ambrożewicz messages::generalError(asyncResp->res); 724e13c2760SPrzemyslaw Czarnowski } 725e13c2760SPrzemyslaw Czarnowski }, 726e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, 727988fb7b2SAdrian Ambrożewicz "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw, 728988fb7b2SAdrian Ambrożewicz unixFd); 729e13c2760SPrzemyslaw Czarnowski } 730e13c2760SPrzemyslaw Czarnowski 731e13c2760SPrzemyslaw Czarnowski /** 732e13c2760SPrzemyslaw Czarnowski * @brief Function transceives data with dbus directly. 733e13c2760SPrzemyslaw Czarnowski * 734e13c2760SPrzemyslaw Czarnowski * All BMC state properties will be retrieved before sending reset request. 735e13c2760SPrzemyslaw Czarnowski */ 736*22db1728SEd Tanous inline void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 737e13c2760SPrzemyslaw Czarnowski const std::string& service, const std::string& name, 738e13c2760SPrzemyslaw Czarnowski bool legacy) 739e13c2760SPrzemyslaw Czarnowski { 740e13c2760SPrzemyslaw Czarnowski 741e13c2760SPrzemyslaw Czarnowski // Legacy mount requires parameter with image 742e13c2760SPrzemyslaw Czarnowski if (legacy) 743e13c2760SPrzemyslaw Czarnowski { 744e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 745e13c2760SPrzemyslaw Czarnowski [asyncResp](const boost::system::error_code ec) { 746e13c2760SPrzemyslaw Czarnowski if (ec) 747e13c2760SPrzemyslaw Czarnowski { 748e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 749e13c2760SPrzemyslaw Czarnowski 750e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 751e13c2760SPrzemyslaw Czarnowski return; 752e13c2760SPrzemyslaw Czarnowski } 753e13c2760SPrzemyslaw Czarnowski }, 754e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name, 755e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount"); 756e13c2760SPrzemyslaw Czarnowski } 757e13c2760SPrzemyslaw Czarnowski else // proxy 758e13c2760SPrzemyslaw Czarnowski { 759e13c2760SPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 760e13c2760SPrzemyslaw Czarnowski [asyncResp](const boost::system::error_code ec) { 761e13c2760SPrzemyslaw Czarnowski if (ec) 762e13c2760SPrzemyslaw Czarnowski { 763e13c2760SPrzemyslaw Czarnowski BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec; 764e13c2760SPrzemyslaw Czarnowski 765e13c2760SPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 766e13c2760SPrzemyslaw Czarnowski return; 767e13c2760SPrzemyslaw Czarnowski } 768e13c2760SPrzemyslaw Czarnowski }, 769e13c2760SPrzemyslaw Czarnowski service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name, 770e13c2760SPrzemyslaw Czarnowski "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount"); 771e13c2760SPrzemyslaw Czarnowski } 772e13c2760SPrzemyslaw Czarnowski } 773e13c2760SPrzemyslaw Czarnowski 774*22db1728SEd Tanous inline void requestNBDVirtualMediaRoutes(App& app) 775107077deSPrzemyslaw Czarnowski { 776*22db1728SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/" 777*22db1728SEd Tanous "VirtualMedia.InsertMedia") 778*22db1728SEd Tanous .privileges({"ConfigureManager"}) 779*22db1728SEd Tanous .methods(boost::beast::http::verb::post)( 780*22db1728SEd Tanous [](const crow::Request& req, 781*22db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 782*22db1728SEd Tanous const std::string& name, const std::string& resName) { 783*22db1728SEd Tanous if (name != "bmc") 784107077deSPrzemyslaw Czarnowski { 785*22db1728SEd Tanous messages::resourceNotFound(asyncResp->res, 786*22db1728SEd Tanous "VirtualMedia.Insert", resName); 787107077deSPrzemyslaw Czarnowski 788107077deSPrzemyslaw Czarnowski return; 789107077deSPrzemyslaw Czarnowski } 790107077deSPrzemyslaw Czarnowski 791*22db1728SEd Tanous crow::connections::systemBus->async_method_call( 792*22db1728SEd Tanous [asyncResp, req, 793*22db1728SEd Tanous resName](const boost::system::error_code ec, 794*22db1728SEd Tanous const GetObjectType& getObjectType) { 795*22db1728SEd Tanous if (ec) 796*22db1728SEd Tanous { 797*22db1728SEd Tanous BMCWEB_LOG_ERROR 798*22db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 799*22db1728SEd Tanous << ec; 800*22db1728SEd Tanous messages::internalError(asyncResp->res); 801107077deSPrzemyslaw Czarnowski 802*22db1728SEd Tanous return; 803*22db1728SEd Tanous } 804*22db1728SEd Tanous std::string service = getObjectType.begin()->first; 805*22db1728SEd Tanous BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 806*22db1728SEd Tanous 807*22db1728SEd Tanous crow::connections::systemBus->async_method_call( 808*22db1728SEd Tanous [service, resName, req, 809*22db1728SEd Tanous asyncResp](const boost::system::error_code ec, 810*22db1728SEd Tanous ManagedObjectType& subtree) { 811*22db1728SEd Tanous if (ec) 812*22db1728SEd Tanous { 813*22db1728SEd Tanous BMCWEB_LOG_DEBUG << "DBUS response error"; 814*22db1728SEd Tanous 815*22db1728SEd Tanous return; 816*22db1728SEd Tanous } 817*22db1728SEd Tanous 818*22db1728SEd Tanous for (const auto& object : subtree) 819*22db1728SEd Tanous { 820*22db1728SEd Tanous const std::string& path = 821*22db1728SEd Tanous static_cast<const std::string&>( 822*22db1728SEd Tanous object.first); 823*22db1728SEd Tanous 824*22db1728SEd Tanous std::size_t lastIndex = path.rfind('/'); 825*22db1728SEd Tanous if (lastIndex == std::string::npos) 826*22db1728SEd Tanous { 827*22db1728SEd Tanous continue; 828*22db1728SEd Tanous } 829*22db1728SEd Tanous 830*22db1728SEd Tanous lastIndex += 1; 831*22db1728SEd Tanous 832*22db1728SEd Tanous if (path.substr(lastIndex) == resName) 833*22db1728SEd Tanous { 834*22db1728SEd Tanous lastIndex = path.rfind("Proxy"); 835*22db1728SEd Tanous if (lastIndex != std::string::npos) 836*22db1728SEd Tanous { 837*22db1728SEd Tanous // Not possible in proxy mode 838*22db1728SEd Tanous BMCWEB_LOG_DEBUG 839*22db1728SEd Tanous << "InsertMedia not " 840*22db1728SEd Tanous "allowed in proxy mode"; 841*22db1728SEd Tanous messages::resourceNotFound( 842*22db1728SEd Tanous asyncResp->res, 843*22db1728SEd Tanous "VirtualMedia.InsertMedia", 844*22db1728SEd Tanous resName); 845*22db1728SEd Tanous 846*22db1728SEd Tanous return; 847*22db1728SEd Tanous } 848*22db1728SEd Tanous 849*22db1728SEd Tanous lastIndex = path.rfind("Legacy"); 850*22db1728SEd Tanous if (lastIndex == std::string::npos) 851*22db1728SEd Tanous { 852*22db1728SEd Tanous continue; 853*22db1728SEd Tanous } 854*22db1728SEd Tanous 855*22db1728SEd Tanous // Legacy mode 856*22db1728SEd Tanous std::string imageUrl; 857*22db1728SEd Tanous std::optional<std::string> userName; 858*22db1728SEd Tanous std::optional<std::string> password; 859*22db1728SEd Tanous std::optional<std::string> 860*22db1728SEd Tanous transferMethod; 861*22db1728SEd Tanous std::optional<std::string> 862*22db1728SEd Tanous transferProtocolType; 863*22db1728SEd Tanous std::optional<bool> writeProtected = 864*22db1728SEd Tanous true; 865*22db1728SEd Tanous std::optional<bool> inserted; 866*22db1728SEd Tanous 867*22db1728SEd Tanous // Read obligatory parameters (url of 868*22db1728SEd Tanous // image) 869*22db1728SEd Tanous if (!json_util::readJson( 870*22db1728SEd Tanous req, asyncResp->res, "Image", 871*22db1728SEd Tanous imageUrl, "WriteProtected", 872*22db1728SEd Tanous writeProtected, "UserName", 873*22db1728SEd Tanous userName, "Password", password, 874*22db1728SEd Tanous "Inserted", inserted, 875*22db1728SEd Tanous "TransferMethod", 876*22db1728SEd Tanous transferMethod, 877*22db1728SEd Tanous "TransferProtocolType", 878*22db1728SEd Tanous transferProtocolType)) 879*22db1728SEd Tanous { 880*22db1728SEd Tanous BMCWEB_LOG_DEBUG 881*22db1728SEd Tanous << "Image is not provided"; 882*22db1728SEd Tanous return; 883*22db1728SEd Tanous } 884*22db1728SEd Tanous 885*22db1728SEd Tanous bool paramsValid = validateParams( 886*22db1728SEd Tanous asyncResp->res, imageUrl, inserted, 887*22db1728SEd Tanous transferMethod, 888*22db1728SEd Tanous transferProtocolType); 889*22db1728SEd Tanous 890*22db1728SEd Tanous if (paramsValid == false) 891*22db1728SEd Tanous { 892*22db1728SEd Tanous return; 893*22db1728SEd Tanous } 894*22db1728SEd Tanous 895*22db1728SEd Tanous // manager is irrelevant for 896*22db1728SEd Tanous // VirtualMedia dbus calls 897*22db1728SEd Tanous doMountVmLegacy(asyncResp, service, 898*22db1728SEd Tanous resName, imageUrl, 899*22db1728SEd Tanous !(*writeProtected), 900*22db1728SEd Tanous std::move(*userName), 901*22db1728SEd Tanous std::move(*password)); 902*22db1728SEd Tanous 903*22db1728SEd Tanous return; 904*22db1728SEd Tanous } 905*22db1728SEd Tanous } 906*22db1728SEd Tanous BMCWEB_LOG_DEBUG << "Parent item not found"; 907*22db1728SEd Tanous messages::resourceNotFound( 908*22db1728SEd Tanous asyncResp->res, "VirtualMedia", resName); 909*22db1728SEd Tanous }, 910*22db1728SEd Tanous service, "/xyz/openbmc_project/VirtualMedia", 911*22db1728SEd Tanous "org.freedesktop.DBus.ObjectManager", 912*22db1728SEd Tanous "GetManagedObjects"); 913*22db1728SEd Tanous }, 914*22db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", 915*22db1728SEd Tanous "/xyz/openbmc_project/object_mapper", 916*22db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", 917*22db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 918*22db1728SEd Tanous std::array<const char*, 0>()); 919*22db1728SEd Tanous }); 920*22db1728SEd Tanous 921*22db1728SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/" 922*22db1728SEd Tanous "VirtualMedia.EjectMedia") 923*22db1728SEd Tanous .privileges({"ConfigureManager"}) 924*22db1728SEd Tanous .methods(boost::beast::http::verb::post)( 925*22db1728SEd Tanous [](const crow::Request& req, 926*22db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 927*22db1728SEd Tanous const std::string& name, const std::string& resName) { 928107077deSPrzemyslaw Czarnowski if (name != "bmc") 929107077deSPrzemyslaw Czarnowski { 930*22db1728SEd Tanous messages::resourceNotFound(asyncResp->res, 931*22db1728SEd Tanous "VirtualMedia.Eject", resName); 932*22db1728SEd Tanous 933*22db1728SEd Tanous return; 934*22db1728SEd Tanous } 935*22db1728SEd Tanous 936*22db1728SEd Tanous crow::connections::systemBus->async_method_call( 937*22db1728SEd Tanous [asyncResp, req, 938*22db1728SEd Tanous resName](const boost::system::error_code ec, 939*22db1728SEd Tanous const GetObjectType& getObjectType) { 940*22db1728SEd Tanous if (ec) 941*22db1728SEd Tanous { 942*22db1728SEd Tanous BMCWEB_LOG_ERROR 943*22db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 944*22db1728SEd Tanous << ec; 945*22db1728SEd Tanous messages::internalError(asyncResp->res); 946*22db1728SEd Tanous 947*22db1728SEd Tanous return; 948*22db1728SEd Tanous } 949*22db1728SEd Tanous std::string service = getObjectType.begin()->first; 950*22db1728SEd Tanous BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 951*22db1728SEd Tanous 952*22db1728SEd Tanous crow::connections::systemBus->async_method_call( 953*22db1728SEd Tanous [resName, service, req, asyncResp{asyncResp}]( 954*22db1728SEd Tanous const boost::system::error_code ec, 955*22db1728SEd Tanous ManagedObjectType& subtree) { 956*22db1728SEd Tanous if (ec) 957*22db1728SEd Tanous { 958*22db1728SEd Tanous BMCWEB_LOG_DEBUG << "DBUS response error"; 959*22db1728SEd Tanous 960*22db1728SEd Tanous return; 961*22db1728SEd Tanous } 962*22db1728SEd Tanous 963*22db1728SEd Tanous for (const auto& object : subtree) 964*22db1728SEd Tanous { 965*22db1728SEd Tanous const std::string& path = 966*22db1728SEd Tanous static_cast<const std::string&>( 967*22db1728SEd Tanous object.first); 968*22db1728SEd Tanous 969*22db1728SEd Tanous std::size_t lastIndex = path.rfind('/'); 970*22db1728SEd Tanous if (lastIndex == std::string::npos) 971*22db1728SEd Tanous { 972*22db1728SEd Tanous continue; 973*22db1728SEd Tanous } 974*22db1728SEd Tanous 975*22db1728SEd Tanous lastIndex += 1; 976*22db1728SEd Tanous 977*22db1728SEd Tanous if (path.substr(lastIndex) == resName) 978*22db1728SEd Tanous { 979*22db1728SEd Tanous lastIndex = path.rfind("Proxy"); 980*22db1728SEd Tanous if (lastIndex != std::string::npos) 981*22db1728SEd Tanous { 982*22db1728SEd Tanous // Proxy mode 983*22db1728SEd Tanous doVmAction(asyncResp, service, 984*22db1728SEd Tanous resName, false); 985*22db1728SEd Tanous } 986*22db1728SEd Tanous 987*22db1728SEd Tanous lastIndex = path.rfind("Legacy"); 988*22db1728SEd Tanous if (lastIndex != std::string::npos) 989*22db1728SEd Tanous { 990*22db1728SEd Tanous // Legacy mode 991*22db1728SEd Tanous doVmAction(asyncResp, service, 992*22db1728SEd Tanous resName, true); 993*22db1728SEd Tanous } 994*22db1728SEd Tanous 995*22db1728SEd Tanous return; 996*22db1728SEd Tanous } 997*22db1728SEd Tanous } 998*22db1728SEd Tanous BMCWEB_LOG_DEBUG << "Parent item not found"; 999*22db1728SEd Tanous messages::resourceNotFound( 1000*22db1728SEd Tanous asyncResp->res, "VirtualMedia", resName); 1001*22db1728SEd Tanous }, 1002*22db1728SEd Tanous service, "/xyz/openbmc_project/VirtualMedia", 1003*22db1728SEd Tanous "org.freedesktop.DBus.ObjectManager", 1004*22db1728SEd Tanous "GetManagedObjects"); 1005*22db1728SEd Tanous }, 1006*22db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", 1007*22db1728SEd Tanous "/xyz/openbmc_project/object_mapper", 1008*22db1728SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetObject", 1009*22db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 1010*22db1728SEd Tanous std::array<const char*, 0>()); 1011*22db1728SEd Tanous }); 1012*22db1728SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/") 1013*22db1728SEd Tanous .privileges({"Login"}) 1014*22db1728SEd Tanous .methods(boost::beast::http::verb::get)( 1015*22db1728SEd Tanous [](const crow::Request& /* req */, 1016*22db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1017*22db1728SEd Tanous const std::string& name) { 1018*22db1728SEd Tanous if (name != "bmc") 1019*22db1728SEd Tanous { 1020*22db1728SEd Tanous messages::resourceNotFound(asyncResp->res, "VirtualMedia", 1021*22db1728SEd Tanous name); 1022107077deSPrzemyslaw Czarnowski 1023107077deSPrzemyslaw Czarnowski return; 1024107077deSPrzemyslaw Czarnowski } 1025107077deSPrzemyslaw Czarnowski 10268d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 1027107077deSPrzemyslaw Czarnowski "#VirtualMediaCollection.VirtualMediaCollection"; 10288d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Virtual Media Services"; 10298d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = 1030d6c414f3SPrzemyslaw Czarnowski "/redfish/v1/Managers/" + name + "/VirtualMedia"; 1031107077deSPrzemyslaw Czarnowski 1032107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 1033107077deSPrzemyslaw Czarnowski [asyncResp, name](const boost::system::error_code ec, 1034107077deSPrzemyslaw Czarnowski const GetObjectType& getObjectType) { 1035107077deSPrzemyslaw Czarnowski if (ec) 1036107077deSPrzemyslaw Czarnowski { 1037*22db1728SEd Tanous BMCWEB_LOG_ERROR 1038*22db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 1039107077deSPrzemyslaw Czarnowski << ec; 1040107077deSPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 1041107077deSPrzemyslaw Czarnowski 1042107077deSPrzemyslaw Czarnowski return; 1043107077deSPrzemyslaw Czarnowski } 1044107077deSPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 1045107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 1046107077deSPrzemyslaw Czarnowski 1047107077deSPrzemyslaw Czarnowski getVmResourceList(asyncResp, service, name); 1048107077deSPrzemyslaw Czarnowski }, 1049107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 1050107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 1051107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 1052*22db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 1053*22db1728SEd Tanous std::array<const char*, 0>()); 1054*22db1728SEd Tanous }); 1055107077deSPrzemyslaw Czarnowski 1056*22db1728SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/") 1057*22db1728SEd Tanous .privileges({"Login"}) 1058*22db1728SEd Tanous .methods(boost::beast::http::verb::get)( 1059*22db1728SEd Tanous [](const crow::Request& /* req */, 1060*22db1728SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1061*22db1728SEd Tanous const std::string& name, const std::string& resName) { 1062107077deSPrzemyslaw Czarnowski if (name != "bmc") 1063107077deSPrzemyslaw Czarnowski { 1064*22db1728SEd Tanous messages::resourceNotFound(asyncResp->res, "VirtualMedia", 1065*22db1728SEd Tanous resName); 1066107077deSPrzemyslaw Czarnowski 1067107077deSPrzemyslaw Czarnowski return; 1068107077deSPrzemyslaw Czarnowski } 1069107077deSPrzemyslaw Czarnowski 1070107077deSPrzemyslaw Czarnowski crow::connections::systemBus->async_method_call( 1071*22db1728SEd Tanous [asyncResp, name, 1072*22db1728SEd Tanous resName](const boost::system::error_code ec, 1073107077deSPrzemyslaw Czarnowski const GetObjectType& getObjectType) { 1074107077deSPrzemyslaw Czarnowski if (ec) 1075107077deSPrzemyslaw Czarnowski { 1076*22db1728SEd Tanous BMCWEB_LOG_ERROR 1077*22db1728SEd Tanous << "ObjectMapper::GetObject call failed: " 1078107077deSPrzemyslaw Czarnowski << ec; 1079107077deSPrzemyslaw Czarnowski messages::internalError(asyncResp->res); 1080107077deSPrzemyslaw Czarnowski 1081107077deSPrzemyslaw Czarnowski return; 1082107077deSPrzemyslaw Czarnowski } 1083107077deSPrzemyslaw Czarnowski std::string service = getObjectType.begin()->first; 1084107077deSPrzemyslaw Czarnowski BMCWEB_LOG_DEBUG << "GetObjectType: " << service; 1085107077deSPrzemyslaw Czarnowski 1086107077deSPrzemyslaw Czarnowski getVmData(asyncResp, service, name, resName); 1087107077deSPrzemyslaw Czarnowski }, 1088107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", 1089107077deSPrzemyslaw Czarnowski "/xyz/openbmc_project/object_mapper", 1090107077deSPrzemyslaw Czarnowski "xyz.openbmc_project.ObjectMapper", "GetObject", 1091*22db1728SEd Tanous "/xyz/openbmc_project/VirtualMedia", 1092*22db1728SEd Tanous std::array<const char*, 0>()); 1093*22db1728SEd Tanous }); 1094107077deSPrzemyslaw Czarnowski } 1095107077deSPrzemyslaw Czarnowski 1096107077deSPrzemyslaw Czarnowski } // namespace redfish 1097