xref: /openbmc/bmcweb/features/redfish/lib/virtual_media.hpp (revision 1a6258dc985cde406d9098130e4a2d683e82beb2)
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 
18107077deSPrzemyslaw Czarnowski #include <boost/container/flat_map.hpp>
19988fb7b2SAdrian Ambrożewicz #include <boost/process/async_pipe.hpp>
20988fb7b2SAdrian Ambrożewicz #include <boost/type_traits/has_dereference.hpp>
21107077deSPrzemyslaw Czarnowski #include <node.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 
29107077deSPrzemyslaw Czarnowski {
309e319cf0SAnna Platash /**
319e319cf0SAnna Platash  * @brief Function extracts transfer protocol name from URI.
329e319cf0SAnna Platash  */
339e319cf0SAnna Platash static std::string getTransferProtocolTypeFromUri(const std::string& imageUri)
349e319cf0SAnna Platash {
359e319cf0SAnna Platash     try
369e319cf0SAnna Platash     {
379e319cf0SAnna Platash         std::string_view scheme = boost::urls::url_view(imageUri).scheme();
389e319cf0SAnna Platash         if (scheme == "smb")
399e319cf0SAnna Platash         {
409e319cf0SAnna Platash             return "CIFS";
419e319cf0SAnna Platash         }
429e319cf0SAnna Platash         else if (scheme == "https")
439e319cf0SAnna Platash         {
449e319cf0SAnna Platash             return "HTTPS";
459e319cf0SAnna Platash         }
469e319cf0SAnna Platash     }
479e319cf0SAnna Platash     catch (std::exception& p)
489e319cf0SAnna Platash     {
499e319cf0SAnna Platash         BMCWEB_LOG_ERROR << p.what();
509e319cf0SAnna Platash     }
519e319cf0SAnna Platash     return "None";
529e319cf0SAnna Platash }
53107077deSPrzemyslaw Czarnowski 
54107077deSPrzemyslaw Czarnowski /**
55107077deSPrzemyslaw Czarnowski  * @brief Read all known properties from VM object interfaces
56107077deSPrzemyslaw Czarnowski  */
578d1b46d7Szhanghch05 static void
588d1b46d7Szhanghch05     vmParseInterfaceObject(const DbusInterfaceType& interface,
598d1b46d7Szhanghch05                            const std::shared_ptr<bmcweb::AsyncResp>& aResp)
60107077deSPrzemyslaw Czarnowski {
61107077deSPrzemyslaw Czarnowski     const auto mountPointIface =
62107077deSPrzemyslaw Czarnowski         interface.find("xyz.openbmc_project.VirtualMedia.MountPoint");
63107077deSPrzemyslaw Czarnowski     if (mountPointIface == interface.cend())
64107077deSPrzemyslaw Czarnowski     {
65107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Interface MountPoint not found";
66107077deSPrzemyslaw Czarnowski         return;
67107077deSPrzemyslaw Czarnowski     }
68107077deSPrzemyslaw Czarnowski 
69107077deSPrzemyslaw Czarnowski     const auto processIface =
70107077deSPrzemyslaw Czarnowski         interface.find("xyz.openbmc_project.VirtualMedia.Process");
71107077deSPrzemyslaw Czarnowski     if (processIface == interface.cend())
72107077deSPrzemyslaw Czarnowski     {
73107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Interface Process not found";
74107077deSPrzemyslaw Czarnowski         return;
75107077deSPrzemyslaw Czarnowski     }
76107077deSPrzemyslaw Czarnowski 
77107077deSPrzemyslaw Czarnowski     const auto endpointIdProperty = mountPointIface->second.find("EndpointId");
78107077deSPrzemyslaw Czarnowski     if (endpointIdProperty == mountPointIface->second.cend())
79107077deSPrzemyslaw Czarnowski     {
80107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Property EndpointId not found";
81107077deSPrzemyslaw Czarnowski         return;
82107077deSPrzemyslaw Czarnowski     }
83107077deSPrzemyslaw Czarnowski 
84107077deSPrzemyslaw Czarnowski     const auto activeProperty = processIface->second.find("Active");
85107077deSPrzemyslaw Czarnowski     if (activeProperty == processIface->second.cend())
86107077deSPrzemyslaw Czarnowski     {
87107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Property Active not found";
88107077deSPrzemyslaw Czarnowski         return;
89107077deSPrzemyslaw Czarnowski     }
90107077deSPrzemyslaw Czarnowski 
91107077deSPrzemyslaw Czarnowski     const bool* activeValue = std::get_if<bool>(&activeProperty->second);
92107077deSPrzemyslaw Czarnowski     if (!activeValue)
93107077deSPrzemyslaw Czarnowski     {
94107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Value Active not found";
95107077deSPrzemyslaw Czarnowski         return;
96107077deSPrzemyslaw Czarnowski     }
97107077deSPrzemyslaw Czarnowski 
98107077deSPrzemyslaw Czarnowski     const std::string* endpointIdValue =
99107077deSPrzemyslaw Czarnowski         std::get_if<std::string>(&endpointIdProperty->second);
100107077deSPrzemyslaw Czarnowski     if (endpointIdValue)
101107077deSPrzemyslaw Czarnowski     {
102107077deSPrzemyslaw Czarnowski         if (!endpointIdValue->empty())
103107077deSPrzemyslaw Czarnowski         {
104107077deSPrzemyslaw Czarnowski             // Proxy mode
105d04ba325SPrzemyslaw Czarnowski             aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
106d04ba325SPrzemyslaw Czarnowski                 *endpointIdValue;
107107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["TransferProtocolType"] = "OEM";
108107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["Inserted"] = *activeValue;
109107077deSPrzemyslaw Czarnowski             if (*activeValue == true)
110107077deSPrzemyslaw Czarnowski             {
111107077deSPrzemyslaw Czarnowski                 aResp->res.jsonValue["ConnectedVia"] = "Applet";
112107077deSPrzemyslaw Czarnowski             }
113107077deSPrzemyslaw Czarnowski         }
114107077deSPrzemyslaw Czarnowski         else
115107077deSPrzemyslaw Czarnowski         {
116107077deSPrzemyslaw Czarnowski             // Legacy mode
1179e319cf0SAnna Platash             for (const auto& property : mountPointIface->second)
1189e319cf0SAnna Platash             {
1199e319cf0SAnna Platash                 if (property.first == "ImageURL")
120107077deSPrzemyslaw Czarnowski                 {
121107077deSPrzemyslaw Czarnowski                     const std::string* imageUrlValue =
1229e319cf0SAnna Platash                         std::get_if<std::string>(&property.second);
123107077deSPrzemyslaw Czarnowski                     if (imageUrlValue && !imageUrlValue->empty())
124107077deSPrzemyslaw Czarnowski                     {
125da4784d8SPrzemyslaw Czarnowski                         std::filesystem::path filePath = *imageUrlValue;
126da4784d8SPrzemyslaw Czarnowski                         if (!filePath.has_filename())
127da4784d8SPrzemyslaw Czarnowski                         {
1289e319cf0SAnna Platash                             // this will handle https share, which not
1299e319cf0SAnna Platash                             // necessarily has to have filename given.
130da4784d8SPrzemyslaw Czarnowski                             aResp->res.jsonValue["ImageName"] = "";
131da4784d8SPrzemyslaw Czarnowski                         }
132da4784d8SPrzemyslaw Czarnowski                         else
133da4784d8SPrzemyslaw Czarnowski                         {
1349e319cf0SAnna Platash                             aResp->res.jsonValue["ImageName"] =
1359e319cf0SAnna Platash                                 filePath.filename();
136da4784d8SPrzemyslaw Czarnowski                         }
137da4784d8SPrzemyslaw Czarnowski 
138da4784d8SPrzemyslaw Czarnowski                         aResp->res.jsonValue["Image"] = *imageUrlValue;
139107077deSPrzemyslaw Czarnowski                         aResp->res.jsonValue["Inserted"] = *activeValue;
1409e319cf0SAnna Platash                         aResp->res.jsonValue["TransferProtocolType"] =
1419e319cf0SAnna Platash                             getTransferProtocolTypeFromUri(*imageUrlValue);
1429e319cf0SAnna Platash 
143107077deSPrzemyslaw Czarnowski                         if (*activeValue == true)
144107077deSPrzemyslaw Czarnowski                         {
145107077deSPrzemyslaw Czarnowski                             aResp->res.jsonValue["ConnectedVia"] = "URI";
146107077deSPrzemyslaw Czarnowski                         }
147107077deSPrzemyslaw Czarnowski                     }
148107077deSPrzemyslaw Czarnowski                 }
1499e319cf0SAnna Platash                 else if (property.first == "WriteProtected")
1509e319cf0SAnna Platash                 {
1519e319cf0SAnna Platash                     const bool* writeProtectedValue =
1529e319cf0SAnna Platash                         std::get_if<bool>(&property.second);
1539e319cf0SAnna Platash                     if (writeProtectedValue)
1549e319cf0SAnna Platash                     {
1559e319cf0SAnna Platash                         aResp->res.jsonValue["WriteProtected"] =
1569e319cf0SAnna Platash                             *writeProtectedValue;
1579e319cf0SAnna Platash                     }
1589e319cf0SAnna Platash                 }
1599e319cf0SAnna Platash             }
160107077deSPrzemyslaw Czarnowski         }
161107077deSPrzemyslaw Czarnowski     }
162107077deSPrzemyslaw Czarnowski }
163107077deSPrzemyslaw Czarnowski 
164107077deSPrzemyslaw Czarnowski /**
165107077deSPrzemyslaw Czarnowski  * @brief Fill template for Virtual Media Item.
166107077deSPrzemyslaw Czarnowski  */
167107077deSPrzemyslaw Czarnowski static nlohmann::json vmItemTemplate(const std::string& name,
168107077deSPrzemyslaw Czarnowski                                      const std::string& resName)
169107077deSPrzemyslaw Czarnowski {
170107077deSPrzemyslaw Czarnowski     nlohmann::json item;
171107077deSPrzemyslaw Czarnowski     item["@odata.id"] =
172107077deSPrzemyslaw Czarnowski         "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
173d04ba325SPrzemyslaw Czarnowski     item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
174107077deSPrzemyslaw Czarnowski     item["Name"] = "Virtual Removable Media";
175107077deSPrzemyslaw Czarnowski     item["Id"] = resName;
176107077deSPrzemyslaw Czarnowski     item["WriteProtected"] = true;
177107077deSPrzemyslaw Czarnowski     item["MediaTypes"] = {"CD", "USBStick"};
178107077deSPrzemyslaw Czarnowski     item["TransferMethod"] = "Stream";
179d04ba325SPrzemyslaw Czarnowski     item["Oem"]["OpenBMC"]["@odata.type"] =
180d04ba325SPrzemyslaw Czarnowski         "#OemVirtualMedia.v1_0_0.VirtualMedia";
181107077deSPrzemyslaw Czarnowski 
182107077deSPrzemyslaw Czarnowski     return item;
183107077deSPrzemyslaw Czarnowski }
184107077deSPrzemyslaw Czarnowski 
185107077deSPrzemyslaw Czarnowski /**
186107077deSPrzemyslaw Czarnowski  *  @brief Fills collection data
187107077deSPrzemyslaw Czarnowski  */
1888d1b46d7Szhanghch05 static void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> aResp,
189107077deSPrzemyslaw Czarnowski                               const std::string& service,
190107077deSPrzemyslaw Czarnowski                               const std::string& name)
191107077deSPrzemyslaw Czarnowski {
192107077deSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
193107077deSPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
194107077deSPrzemyslaw Czarnowski         [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
195107077deSPrzemyslaw Czarnowski                                         ManagedObjectType& subtree) {
196107077deSPrzemyslaw Czarnowski             if (ec)
197107077deSPrzemyslaw Czarnowski             {
198107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "DBUS response error";
199107077deSPrzemyslaw Czarnowski                 return;
200107077deSPrzemyslaw Czarnowski             }
201107077deSPrzemyslaw Czarnowski             nlohmann::json& members = aResp->res.jsonValue["Members"];
202107077deSPrzemyslaw Czarnowski             members = nlohmann::json::array();
203107077deSPrzemyslaw Czarnowski 
204107077deSPrzemyslaw Czarnowski             for (const auto& object : subtree)
205107077deSPrzemyslaw Czarnowski             {
206107077deSPrzemyslaw Czarnowski                 nlohmann::json item;
2072dfd18efSEd Tanous                 std::string path = object.first.filename();
2082dfd18efSEd Tanous                 if (path.empty())
209107077deSPrzemyslaw Czarnowski                 {
210107077deSPrzemyslaw Czarnowski                     continue;
211107077deSPrzemyslaw Czarnowski                 }
212107077deSPrzemyslaw Czarnowski 
2132dfd18efSEd Tanous                 item["@odata.id"] =
214788ca507SAppaRao Puli                     "/redfish/v1/Managers/" + name + "/VirtualMedia/" + path;
215107077deSPrzemyslaw Czarnowski 
216107077deSPrzemyslaw Czarnowski                 members.emplace_back(std::move(item));
217107077deSPrzemyslaw Czarnowski             }
218107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["Members@odata.count"] = members.size();
219107077deSPrzemyslaw Czarnowski         },
220107077deSPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia",
221107077deSPrzemyslaw Czarnowski         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
222107077deSPrzemyslaw Czarnowski }
223107077deSPrzemyslaw Czarnowski 
224107077deSPrzemyslaw Czarnowski /**
225107077deSPrzemyslaw Czarnowski  *  @brief Fills data for specific resource
226107077deSPrzemyslaw Czarnowski  */
2278d1b46d7Szhanghch05 static void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
228107077deSPrzemyslaw Czarnowski                       const std::string& service, const std::string& name,
229107077deSPrzemyslaw Czarnowski                       const std::string& resName)
230107077deSPrzemyslaw Czarnowski {
231107077deSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
232107077deSPrzemyslaw Czarnowski 
233107077deSPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
234107077deSPrzemyslaw Czarnowski         [resName, name, aResp](const boost::system::error_code ec,
235107077deSPrzemyslaw Czarnowski                                ManagedObjectType& subtree) {
236107077deSPrzemyslaw Czarnowski             if (ec)
237107077deSPrzemyslaw Czarnowski             {
238107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "DBUS response error";
239e13c2760SPrzemyslaw Czarnowski 
240107077deSPrzemyslaw Czarnowski                 return;
241107077deSPrzemyslaw Czarnowski             }
242107077deSPrzemyslaw Czarnowski 
243107077deSPrzemyslaw Czarnowski             for (auto& item : subtree)
244107077deSPrzemyslaw Czarnowski             {
2452dfd18efSEd Tanous                 std::string thispath = item.first.filename();
2462dfd18efSEd Tanous                 if (thispath.empty())
247107077deSPrzemyslaw Czarnowski                 {
248107077deSPrzemyslaw Czarnowski                     continue;
249107077deSPrzemyslaw Czarnowski                 }
250107077deSPrzemyslaw Czarnowski 
2512dfd18efSEd Tanous                 if (thispath != resName)
252107077deSPrzemyslaw Czarnowski                 {
253107077deSPrzemyslaw Czarnowski                     continue;
254107077deSPrzemyslaw Czarnowski                 }
255107077deSPrzemyslaw Czarnowski 
256*1a6258dcSPrzemyslaw Czarnowski                 // "Legacy"/"Proxy"
257*1a6258dcSPrzemyslaw Czarnowski                 auto mode = item.first.parent_path();
258*1a6258dcSPrzemyslaw Czarnowski                 // "VirtualMedia"
259*1a6258dcSPrzemyslaw Czarnowski                 auto type = mode.parent_path();
260*1a6258dcSPrzemyslaw Czarnowski                 if (mode.filename().empty() || type.filename().empty())
261*1a6258dcSPrzemyslaw Czarnowski                 {
262*1a6258dcSPrzemyslaw Czarnowski                     continue;
263*1a6258dcSPrzemyslaw Czarnowski                 }
264*1a6258dcSPrzemyslaw Czarnowski 
265*1a6258dcSPrzemyslaw Czarnowski                 if (type.filename() != "VirtualMedia")
266*1a6258dcSPrzemyslaw Czarnowski                 {
267*1a6258dcSPrzemyslaw Czarnowski                     continue;
268*1a6258dcSPrzemyslaw Czarnowski                 }
269*1a6258dcSPrzemyslaw Czarnowski 
270107077deSPrzemyslaw Czarnowski                 aResp->res.jsonValue = vmItemTemplate(name, resName);
271107077deSPrzemyslaw Czarnowski 
272e13c2760SPrzemyslaw Czarnowski                 // Check if dbus path is Legacy type
273*1a6258dcSPrzemyslaw Czarnowski                 if (mode.filename() == "Legacy")
274e13c2760SPrzemyslaw Czarnowski                 {
275e13c2760SPrzemyslaw Czarnowski                     aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
276e13c2760SPrzemyslaw Czarnowski                                         ["target"] =
277e13c2760SPrzemyslaw Czarnowski                         "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
278e13c2760SPrzemyslaw Czarnowski                         resName + "/Actions/VirtualMedia.InsertMedia";
279e13c2760SPrzemyslaw Czarnowski                 }
280e13c2760SPrzemyslaw Czarnowski 
281107077deSPrzemyslaw Czarnowski                 vmParseInterfaceObject(item.second, aResp);
282107077deSPrzemyslaw Czarnowski 
283e13c2760SPrzemyslaw Czarnowski                 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
284e13c2760SPrzemyslaw Czarnowski                                     ["target"] =
285e13c2760SPrzemyslaw Czarnowski                     "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
286e13c2760SPrzemyslaw Czarnowski                     resName + "/Actions/VirtualMedia.EjectMedia";
287e13c2760SPrzemyslaw Czarnowski 
288107077deSPrzemyslaw Czarnowski                 return;
289107077deSPrzemyslaw Czarnowski             }
290107077deSPrzemyslaw Czarnowski 
291107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(
292d04ba325SPrzemyslaw Czarnowski                 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
293107077deSPrzemyslaw Czarnowski         },
294107077deSPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia",
295107077deSPrzemyslaw Czarnowski         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
296107077deSPrzemyslaw Czarnowski }
297107077deSPrzemyslaw Czarnowski 
298e13c2760SPrzemyslaw Czarnowski /**
299e13c2760SPrzemyslaw Czarnowski    @brief InsertMedia action class
300e13c2760SPrzemyslaw Czarnowski  */
301e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionInsertMedia : public Node
302e13c2760SPrzemyslaw Czarnowski {
303e13c2760SPrzemyslaw Czarnowski   public:
30452cc112dSEd Tanous     VirtualMediaActionInsertMedia(App& app) :
305e13c2760SPrzemyslaw Czarnowski         Node(app,
306e13c2760SPrzemyslaw Czarnowski              "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
307e13c2760SPrzemyslaw Czarnowski              "VirtualMedia.InsertMedia",
308e13c2760SPrzemyslaw Czarnowski              std::string(), std::string())
309e13c2760SPrzemyslaw Czarnowski     {
310e13c2760SPrzemyslaw Czarnowski         entityPrivileges = {
311e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
312e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
313e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
314e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
315e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
316e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
317e13c2760SPrzemyslaw Czarnowski     }
318e13c2760SPrzemyslaw Czarnowski 
319e13c2760SPrzemyslaw Czarnowski   private:
320e13c2760SPrzemyslaw Czarnowski     /**
321c6f4e017SAgata Olender      * @brief Transfer protocols supported for InsertMedia action.
322c6f4e017SAgata Olender      *
323c6f4e017SAgata Olender      */
324c6f4e017SAgata Olender     enum class TransferProtocol
325c6f4e017SAgata Olender     {
326c6f4e017SAgata Olender         https,
327c6f4e017SAgata Olender         smb,
328c6f4e017SAgata Olender         invalid
329c6f4e017SAgata Olender     };
330c6f4e017SAgata Olender 
331c6f4e017SAgata Olender     /**
332c6f4e017SAgata Olender      * @brief Function extracts transfer protocol type from URI.
333c6f4e017SAgata Olender      *
334c6f4e017SAgata Olender      */
335c6f4e017SAgata Olender     std::optional<TransferProtocol>
336c6f4e017SAgata Olender         getTransferProtocolFromUri(const std::string& imageUri)
337c6f4e017SAgata Olender     {
3389e319cf0SAnna Platash         try
3399e319cf0SAnna Platash         {
3409e319cf0SAnna Platash             std::string_view scheme = boost::urls::url_view(imageUri).scheme();
3419e319cf0SAnna Platash             if (scheme == "smb")
342c6f4e017SAgata Olender             {
343c6f4e017SAgata Olender                 return TransferProtocol::smb;
344c6f4e017SAgata Olender             }
34581ce609eSEd Tanous             if (scheme == "https")
346c6f4e017SAgata Olender             {
347c6f4e017SAgata Olender                 return TransferProtocol::https;
348c6f4e017SAgata Olender             }
3499e319cf0SAnna Platash             else if (!scheme.empty())
350c6f4e017SAgata Olender             {
351c6f4e017SAgata Olender                 return TransferProtocol::invalid;
352c6f4e017SAgata Olender             }
353c6f4e017SAgata Olender         }
3549e319cf0SAnna Platash         catch (std::exception& p)
3559e319cf0SAnna Platash         {
3569e319cf0SAnna Platash             BMCWEB_LOG_ERROR << p.what();
3579e319cf0SAnna Platash         }
3589e319cf0SAnna Platash 
3599e319cf0SAnna Platash         return {};
360c6f4e017SAgata Olender     }
361c6f4e017SAgata Olender 
362c6f4e017SAgata Olender     /**
363c6f4e017SAgata Olender      * @brief Function convert transfer protocol from string param.
364c6f4e017SAgata Olender      *
365c6f4e017SAgata Olender      */
366c6f4e017SAgata Olender     std::optional<TransferProtocol> getTransferProtocolFromParam(
367c6f4e017SAgata Olender         const std::optional<std::string>& transferProtocolType)
368c6f4e017SAgata Olender     {
369c6f4e017SAgata Olender         if (transferProtocolType == std::nullopt)
370c6f4e017SAgata Olender         {
371c6f4e017SAgata Olender             return {};
372c6f4e017SAgata Olender         }
373c6f4e017SAgata Olender 
374c6f4e017SAgata Olender         if (*transferProtocolType == "CIFS")
375c6f4e017SAgata Olender         {
376c6f4e017SAgata Olender             return TransferProtocol::smb;
377c6f4e017SAgata Olender         }
378c6f4e017SAgata Olender 
379c6f4e017SAgata Olender         if (*transferProtocolType == "HTTPS")
380c6f4e017SAgata Olender         {
381c6f4e017SAgata Olender             return TransferProtocol::https;
382c6f4e017SAgata Olender         }
383c6f4e017SAgata Olender 
384c6f4e017SAgata Olender         return TransferProtocol::invalid;
385c6f4e017SAgata Olender     }
386c6f4e017SAgata Olender 
387c6f4e017SAgata Olender     /**
388c6f4e017SAgata Olender      * @brief Function extends URI with transfer protocol type.
389c6f4e017SAgata Olender      *
390c6f4e017SAgata Olender      */
39181ce609eSEd Tanous     std::string
392c6f4e017SAgata Olender         getUriWithTransferProtocol(const std::string& imageUri,
393c6f4e017SAgata Olender                                    const TransferProtocol& transferProtocol)
394c6f4e017SAgata Olender     {
395c6f4e017SAgata Olender         if (transferProtocol == TransferProtocol::smb)
396c6f4e017SAgata Olender         {
397c6f4e017SAgata Olender             return "smb://" + imageUri;
398c6f4e017SAgata Olender         }
399c6f4e017SAgata Olender 
400c6f4e017SAgata Olender         if (transferProtocol == TransferProtocol::https)
401c6f4e017SAgata Olender         {
402c6f4e017SAgata Olender             return "https://" + imageUri;
403c6f4e017SAgata Olender         }
404c6f4e017SAgata Olender 
405c6f4e017SAgata Olender         return imageUri;
406c6f4e017SAgata Olender     }
407c6f4e017SAgata Olender 
408c6f4e017SAgata Olender     /**
409c6f4e017SAgata Olender      * @brief Function validate parameters of insert media request.
410c6f4e017SAgata Olender      *
411c6f4e017SAgata Olender      */
4128d1b46d7Szhanghch05     bool validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4138d1b46d7Szhanghch05                         std::string& imageUrl,
414c6f4e017SAgata Olender                         const std::optional<bool>& inserted,
415c6f4e017SAgata Olender                         const std::optional<std::string>& transferMethod,
416c6f4e017SAgata Olender                         const std::optional<std::string>& transferProtocolType)
417c6f4e017SAgata Olender     {
418c6f4e017SAgata Olender         BMCWEB_LOG_DEBUG << "Validation started";
419c6f4e017SAgata Olender         // required param imageUrl must not be empty
420c6f4e017SAgata Olender         if (imageUrl.empty())
421c6f4e017SAgata Olender         {
422c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
423c6f4e017SAgata Olender 
4248d1b46d7Szhanghch05             messages::propertyValueFormatError(asyncResp->res, "<empty>",
4258d1b46d7Szhanghch05                                                "Image");
426c6f4e017SAgata Olender 
427c6f4e017SAgata Olender             return false;
428c6f4e017SAgata Olender         }
429c6f4e017SAgata Olender 
430c6f4e017SAgata Olender         // optional param inserted must be true
431c6f4e017SAgata Olender         if ((inserted != std::nullopt) && (*inserted != true))
432c6f4e017SAgata Olender         {
433c6f4e017SAgata Olender             BMCWEB_LOG_ERROR
434c6f4e017SAgata Olender                 << "Request action optional parameter Inserted must be true.";
435c6f4e017SAgata Olender 
4368d1b46d7Szhanghch05             messages::actionParameterNotSupported(asyncResp->res, "Inserted",
437c6f4e017SAgata Olender                                                   "InsertMedia");
438c6f4e017SAgata Olender 
439c6f4e017SAgata Olender             return false;
440c6f4e017SAgata Olender         }
441c6f4e017SAgata Olender 
442c6f4e017SAgata Olender         // optional param transferMethod must be stream
443c6f4e017SAgata Olender         if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
444c6f4e017SAgata Olender         {
445c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action optional parameter "
446c6f4e017SAgata Olender                                 "TransferMethod must be Stream.";
447c6f4e017SAgata Olender 
4488d1b46d7Szhanghch05             messages::actionParameterNotSupported(
4498d1b46d7Szhanghch05                 asyncResp->res, "TransferMethod", "InsertMedia");
450c6f4e017SAgata Olender 
451c6f4e017SAgata Olender             return false;
452c6f4e017SAgata Olender         }
453c6f4e017SAgata Olender 
454c6f4e017SAgata Olender         std::optional<TransferProtocol> uriTransferProtocolType =
455c6f4e017SAgata Olender             getTransferProtocolFromUri(imageUrl);
456c6f4e017SAgata Olender 
457c6f4e017SAgata Olender         std::optional<TransferProtocol> paramTransferProtocolType =
458c6f4e017SAgata Olender             getTransferProtocolFromParam(transferProtocolType);
459c6f4e017SAgata Olender 
460c6f4e017SAgata Olender         // ImageUrl does not contain valid protocol type
461c6f4e017SAgata Olender         if (*uriTransferProtocolType == TransferProtocol::invalid)
462c6f4e017SAgata Olender         {
463c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
464c6f4e017SAgata Olender                                 "contain specified protocol type from list: "
465c6f4e017SAgata Olender                                 "(smb, https).";
466c6f4e017SAgata Olender 
4678d1b46d7Szhanghch05             messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
468c6f4e017SAgata Olender 
469c6f4e017SAgata Olender             return false;
470c6f4e017SAgata Olender         }
471c6f4e017SAgata Olender 
472c6f4e017SAgata Olender         // transferProtocolType should contain value from list
473c6f4e017SAgata Olender         if (*paramTransferProtocolType == TransferProtocol::invalid)
474c6f4e017SAgata Olender         {
475c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
476c6f4e017SAgata Olender                                 "must be provided with value from list: "
477c6f4e017SAgata Olender                                 "(CIFS, HTTPS).";
478c6f4e017SAgata Olender 
4798d1b46d7Szhanghch05             messages::propertyValueNotInList(
4808d1b46d7Szhanghch05                 asyncResp->res, *transferProtocolType, "TransferProtocolType");
481c6f4e017SAgata Olender             return false;
482c6f4e017SAgata Olender         }
483c6f4e017SAgata Olender 
484c6f4e017SAgata Olender         // valid transfer protocol not provided either with URI nor param
485c6f4e017SAgata Olender         if ((uriTransferProtocolType == std::nullopt) &&
486c6f4e017SAgata Olender             (paramTransferProtocolType == std::nullopt))
487c6f4e017SAgata Olender         {
488c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
489c6f4e017SAgata Olender                                 "contain specified protocol type or param "
490c6f4e017SAgata Olender                                 "TransferProtocolType must be provided.";
491c6f4e017SAgata Olender 
4928d1b46d7Szhanghch05             messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
493c6f4e017SAgata Olender 
494c6f4e017SAgata Olender             return false;
495c6f4e017SAgata Olender         }
496c6f4e017SAgata Olender 
497c6f4e017SAgata Olender         // valid transfer protocol provided both with URI and param
498c6f4e017SAgata Olender         if ((paramTransferProtocolType != std::nullopt) &&
499c6f4e017SAgata Olender             (uriTransferProtocolType != std::nullopt))
500c6f4e017SAgata Olender         {
501c6f4e017SAgata Olender             // check if protocol is the same for URI and param
502c6f4e017SAgata Olender             if (*paramTransferProtocolType != *uriTransferProtocolType)
503c6f4e017SAgata Olender             {
504c6f4e017SAgata Olender                 BMCWEB_LOG_ERROR << "Request action parameter "
505c6f4e017SAgata Olender                                     "TransferProtocolType must  contain the "
506c6f4e017SAgata Olender                                     "same protocol type as protocol type "
507c6f4e017SAgata Olender                                     "provided with param imageUrl.";
508c6f4e017SAgata Olender 
509c6f4e017SAgata Olender                 messages::actionParameterValueTypeError(
5108d1b46d7Szhanghch05                     asyncResp->res, *transferProtocolType,
5118d1b46d7Szhanghch05                     "TransferProtocolType", "InsertMedia");
512c6f4e017SAgata Olender 
513c6f4e017SAgata Olender                 return false;
514c6f4e017SAgata Olender             }
515c6f4e017SAgata Olender         }
516c6f4e017SAgata Olender 
517c6f4e017SAgata Olender         // validation passed
518c6f4e017SAgata Olender         // add protocol to URI if needed
519c6f4e017SAgata Olender         if (uriTransferProtocolType == std::nullopt)
520c6f4e017SAgata Olender         {
521c6f4e017SAgata Olender             imageUrl = getUriWithTransferProtocol(imageUrl,
522c6f4e017SAgata Olender                                                   *paramTransferProtocolType);
523c6f4e017SAgata Olender         }
524c6f4e017SAgata Olender 
525c6f4e017SAgata Olender         return true;
526c6f4e017SAgata Olender     }
527c6f4e017SAgata Olender 
528c6f4e017SAgata Olender     /**
529e13c2760SPrzemyslaw Czarnowski      * @brief Function handles POST method request.
530e13c2760SPrzemyslaw Czarnowski      *
531e13c2760SPrzemyslaw Czarnowski      * Analyzes POST body message before sends Reset request data to dbus.
532e13c2760SPrzemyslaw Czarnowski      */
5338d1b46d7Szhanghch05     void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5348d1b46d7Szhanghch05                 const crow::Request& req,
535e13c2760SPrzemyslaw Czarnowski                 const std::vector<std::string>& params) override
536e13c2760SPrzemyslaw Czarnowski     {
537e13c2760SPrzemyslaw Czarnowski         if (params.size() != 2)
538e13c2760SPrzemyslaw Czarnowski         {
5398d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
540e13c2760SPrzemyslaw Czarnowski             return;
541e13c2760SPrzemyslaw Czarnowski         }
542e13c2760SPrzemyslaw Czarnowski 
543e13c2760SPrzemyslaw Czarnowski         // take resource name from URL
544e13c2760SPrzemyslaw Czarnowski         const std::string& resName = params[1];
545e13c2760SPrzemyslaw Czarnowski 
546e13c2760SPrzemyslaw Czarnowski         if (params[0] != "bmc")
547e13c2760SPrzemyslaw Czarnowski         {
5488d1b46d7Szhanghch05             messages::resourceNotFound(asyncResp->res, "VirtualMedia.Insert",
5498d1b46d7Szhanghch05                                        resName);
550e13c2760SPrzemyslaw Czarnowski 
551e13c2760SPrzemyslaw Czarnowski             return;
552e13c2760SPrzemyslaw Czarnowski         }
553e13c2760SPrzemyslaw Czarnowski 
554e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
5558d1b46d7Szhanghch05             [this, asyncResp, req,
556e13c2760SPrzemyslaw Czarnowski              resName](const boost::system::error_code ec,
557e13c2760SPrzemyslaw Czarnowski                       const GetObjectType& getObjectType) {
558e13c2760SPrzemyslaw Czarnowski                 if (ec)
559e13c2760SPrzemyslaw Czarnowski                 {
560e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
561e13c2760SPrzemyslaw Czarnowski                                      << ec;
5628d1b46d7Szhanghch05                     messages::internalError(asyncResp->res);
563e13c2760SPrzemyslaw Czarnowski 
564e13c2760SPrzemyslaw Czarnowski                     return;
565e13c2760SPrzemyslaw Czarnowski                 }
566e13c2760SPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
567e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
568e13c2760SPrzemyslaw Czarnowski 
569e13c2760SPrzemyslaw Czarnowski                 crow::connections::systemBus->async_method_call(
57081ce609eSEd Tanous                     [this, service, resName, req,
5718d1b46d7Szhanghch05                      asyncResp](const boost::system::error_code ec,
572e13c2760SPrzemyslaw Czarnowski                                 ManagedObjectType& subtree) {
573e13c2760SPrzemyslaw Czarnowski                         if (ec)
574e13c2760SPrzemyslaw Czarnowski                         {
575e13c2760SPrzemyslaw Czarnowski                             BMCWEB_LOG_DEBUG << "DBUS response error";
576e13c2760SPrzemyslaw Czarnowski 
577e13c2760SPrzemyslaw Czarnowski                             return;
578e13c2760SPrzemyslaw Czarnowski                         }
579e13c2760SPrzemyslaw Czarnowski 
580e13c2760SPrzemyslaw Czarnowski                         for (const auto& object : subtree)
581e13c2760SPrzemyslaw Czarnowski                         {
582e13c2760SPrzemyslaw Czarnowski                             const std::string& path =
583e13c2760SPrzemyslaw Czarnowski                                 static_cast<const std::string&>(object.first);
584e13c2760SPrzemyslaw Czarnowski 
585f23b7296SEd Tanous                             std::size_t lastIndex = path.rfind('/');
586e13c2760SPrzemyslaw Czarnowski                             if (lastIndex == std::string::npos)
587e13c2760SPrzemyslaw Czarnowski                             {
588e13c2760SPrzemyslaw Czarnowski                                 continue;
589e13c2760SPrzemyslaw Czarnowski                             }
590e13c2760SPrzemyslaw Czarnowski 
591e13c2760SPrzemyslaw Czarnowski                             lastIndex += 1;
592e13c2760SPrzemyslaw Czarnowski 
593e13c2760SPrzemyslaw Czarnowski                             if (path.substr(lastIndex) == resName)
594e13c2760SPrzemyslaw Czarnowski                             {
595e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Proxy");
596e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
597e13c2760SPrzemyslaw Czarnowski                                 {
598e13c2760SPrzemyslaw Czarnowski                                     // Not possible in proxy mode
599e13c2760SPrzemyslaw Czarnowski                                     BMCWEB_LOG_DEBUG << "InsertMedia not "
600e13c2760SPrzemyslaw Czarnowski                                                         "allowed in proxy mode";
601e13c2760SPrzemyslaw Czarnowski                                     messages::resourceNotFound(
6028d1b46d7Szhanghch05                                         asyncResp->res,
6038d1b46d7Szhanghch05                                         "VirtualMedia.InsertMedia", resName);
604e13c2760SPrzemyslaw Czarnowski 
605e13c2760SPrzemyslaw Czarnowski                                     return;
606e13c2760SPrzemyslaw Czarnowski                                 }
607e13c2760SPrzemyslaw Czarnowski 
608e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Legacy");
609c6f4e017SAgata Olender                                 if (lastIndex == std::string::npos)
610e13c2760SPrzemyslaw Czarnowski                                 {
611c6f4e017SAgata Olender                                     continue;
612c6f4e017SAgata Olender                                 }
613c6f4e017SAgata Olender 
614e13c2760SPrzemyslaw Czarnowski                                 // Legacy mode
615e13c2760SPrzemyslaw Czarnowski                                 std::string imageUrl;
616c6f4e017SAgata Olender                                 std::optional<std::string> userName;
617c6f4e017SAgata Olender                                 std::optional<std::string> password;
618c6f4e017SAgata Olender                                 std::optional<std::string> transferMethod;
619c6f4e017SAgata Olender                                 std::optional<std::string> transferProtocolType;
620c6f4e017SAgata Olender                                 std::optional<bool> writeProtected = true;
621c6f4e017SAgata Olender                                 std::optional<bool> inserted;
622e13c2760SPrzemyslaw Czarnowski 
6234e0453b1SGunnar Mills                                 // Read obligatory parameters (url of image)
624d6da5bebSAdrian Ambrożewicz                                 if (!json_util::readJson(
6258d1b46d7Szhanghch05                                         req, asyncResp->res, "Image", imageUrl,
626988fb7b2SAdrian Ambrożewicz                                         "WriteProtected", writeProtected,
627988fb7b2SAdrian Ambrożewicz                                         "UserName", userName, "Password",
628c6f4e017SAgata Olender                                         password, "Inserted", inserted,
629c6f4e017SAgata Olender                                         "TransferMethod", transferMethod,
630c6f4e017SAgata Olender                                         "TransferProtocolType",
631c6f4e017SAgata Olender                                         transferProtocolType))
632e13c2760SPrzemyslaw Czarnowski                                 {
633c6f4e017SAgata Olender                                     BMCWEB_LOG_DEBUG << "Image is not provided";
634e13c2760SPrzemyslaw Czarnowski                                     return;
635e13c2760SPrzemyslaw Czarnowski                                 }
636e13c2760SPrzemyslaw Czarnowski 
637c6f4e017SAgata Olender                                 bool paramsValid = validateParams(
6388d1b46d7Szhanghch05                                     asyncResp->res, imageUrl, inserted,
639c6f4e017SAgata Olender                                     transferMethod, transferProtocolType);
640c6f4e017SAgata Olender 
641c6f4e017SAgata Olender                                 if (paramsValid == false)
642e13c2760SPrzemyslaw Czarnowski                                 {
643e13c2760SPrzemyslaw Czarnowski                                     return;
644e13c2760SPrzemyslaw Czarnowski                                 }
645e13c2760SPrzemyslaw Czarnowski 
646c6f4e017SAgata Olender                                 // manager is irrelevant for VirtualMedia dbus
647c6f4e017SAgata Olender                                 // calls
6488d1b46d7Szhanghch05                                 doMountVmLegacy(asyncResp, service, resName,
649c6f4e017SAgata Olender                                                 imageUrl, !(*writeProtected),
65081ce609eSEd Tanous                                                 std::move(*userName),
65181ce609eSEd Tanous                                                 std::move(*password));
652e13c2760SPrzemyslaw Czarnowski 
653e13c2760SPrzemyslaw Czarnowski                                 return;
654e13c2760SPrzemyslaw Czarnowski                             }
655e13c2760SPrzemyslaw Czarnowski                         }
656e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_DEBUG << "Parent item not found";
6578d1b46d7Szhanghch05                         messages::resourceNotFound(asyncResp->res,
6588d1b46d7Szhanghch05                                                    "VirtualMedia", resName);
659e13c2760SPrzemyslaw Czarnowski                     },
660e13c2760SPrzemyslaw Czarnowski                     service, "/xyz/openbmc_project/VirtualMedia",
661e13c2760SPrzemyslaw Czarnowski                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
662e13c2760SPrzemyslaw Czarnowski             },
663e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
664e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
665e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
666e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
667e13c2760SPrzemyslaw Czarnowski     }
668e13c2760SPrzemyslaw Czarnowski 
6691214b7e7SGunnar Mills     template <typename T>
6701214b7e7SGunnar Mills     static void secureCleanup(T& value)
671988fb7b2SAdrian Ambrożewicz     {
672988fb7b2SAdrian Ambrożewicz         auto raw = const_cast<typename T::value_type*>(value.data());
673988fb7b2SAdrian Ambrożewicz         explicit_bzero(raw, value.size() * sizeof(*raw));
674988fb7b2SAdrian Ambrożewicz     }
675988fb7b2SAdrian Ambrożewicz 
676988fb7b2SAdrian Ambrożewicz     class Credentials
677988fb7b2SAdrian Ambrożewicz     {
678988fb7b2SAdrian Ambrożewicz       public:
679988fb7b2SAdrian Ambrożewicz         Credentials(std::string&& user, std::string&& password) :
680988fb7b2SAdrian Ambrożewicz             userBuf(std::move(user)), passBuf(std::move(password))
6811214b7e7SGunnar Mills         {}
682988fb7b2SAdrian Ambrożewicz 
683988fb7b2SAdrian Ambrożewicz         ~Credentials()
684988fb7b2SAdrian Ambrożewicz         {
685988fb7b2SAdrian Ambrożewicz             secureCleanup(userBuf);
686988fb7b2SAdrian Ambrożewicz             secureCleanup(passBuf);
687988fb7b2SAdrian Ambrożewicz         }
688988fb7b2SAdrian Ambrożewicz 
689988fb7b2SAdrian Ambrożewicz         const std::string& user()
690988fb7b2SAdrian Ambrożewicz         {
691988fb7b2SAdrian Ambrożewicz             return userBuf;
692988fb7b2SAdrian Ambrożewicz         }
693988fb7b2SAdrian Ambrożewicz 
694988fb7b2SAdrian Ambrożewicz         const std::string& password()
695988fb7b2SAdrian Ambrożewicz         {
696988fb7b2SAdrian Ambrożewicz             return passBuf;
697988fb7b2SAdrian Ambrożewicz         }
698988fb7b2SAdrian Ambrożewicz 
699988fb7b2SAdrian Ambrożewicz       private:
700988fb7b2SAdrian Ambrożewicz         Credentials() = delete;
701988fb7b2SAdrian Ambrożewicz         Credentials(const Credentials&) = delete;
702988fb7b2SAdrian Ambrożewicz         Credentials& operator=(const Credentials&) = delete;
703988fb7b2SAdrian Ambrożewicz 
704988fb7b2SAdrian Ambrożewicz         std::string userBuf;
705988fb7b2SAdrian Ambrożewicz         std::string passBuf;
706988fb7b2SAdrian Ambrożewicz     };
707988fb7b2SAdrian Ambrożewicz 
708988fb7b2SAdrian Ambrożewicz     class CredentialsProvider
709988fb7b2SAdrian Ambrożewicz     {
710988fb7b2SAdrian Ambrożewicz       public:
7111214b7e7SGunnar Mills         template <typename T>
7121214b7e7SGunnar Mills         struct Deleter
713988fb7b2SAdrian Ambrożewicz         {
714988fb7b2SAdrian Ambrożewicz             void operator()(T* buff) const
715988fb7b2SAdrian Ambrożewicz             {
716988fb7b2SAdrian Ambrożewicz                 if (buff)
717988fb7b2SAdrian Ambrożewicz                 {
718988fb7b2SAdrian Ambrożewicz                     secureCleanup(*buff);
719988fb7b2SAdrian Ambrożewicz                     delete buff;
720988fb7b2SAdrian Ambrożewicz                 }
721988fb7b2SAdrian Ambrożewicz             }
722988fb7b2SAdrian Ambrożewicz         };
723988fb7b2SAdrian Ambrożewicz 
724988fb7b2SAdrian Ambrożewicz         using Buffer = std::vector<char>;
725988fb7b2SAdrian Ambrożewicz         using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
726988fb7b2SAdrian Ambrożewicz         // Using explicit definition instead of std::function to avoid implicit
727988fb7b2SAdrian Ambrożewicz         // conversions eg. stack copy instead of reference
728988fb7b2SAdrian Ambrożewicz         using FormatterFunc = void(const std::string& username,
729988fb7b2SAdrian Ambrożewicz                                    const std::string& password, Buffer& dest);
730988fb7b2SAdrian Ambrożewicz 
731988fb7b2SAdrian Ambrożewicz         CredentialsProvider(std::string&& user, std::string&& password) :
732988fb7b2SAdrian Ambrożewicz             credentials(std::move(user), std::move(password))
7331214b7e7SGunnar Mills         {}
734988fb7b2SAdrian Ambrożewicz 
735988fb7b2SAdrian Ambrożewicz         const std::string& user()
736988fb7b2SAdrian Ambrożewicz         {
737988fb7b2SAdrian Ambrożewicz             return credentials.user();
738988fb7b2SAdrian Ambrożewicz         }
739988fb7b2SAdrian Ambrożewicz 
740988fb7b2SAdrian Ambrożewicz         const std::string& password()
741988fb7b2SAdrian Ambrożewicz         {
742988fb7b2SAdrian Ambrożewicz             return credentials.password();
743988fb7b2SAdrian Ambrożewicz         }
744988fb7b2SAdrian Ambrożewicz 
74581ce609eSEd Tanous         SecureBuffer pack(FormatterFunc formatter)
746988fb7b2SAdrian Ambrożewicz         {
747988fb7b2SAdrian Ambrożewicz             SecureBuffer packed{new Buffer{}};
748988fb7b2SAdrian Ambrożewicz             if (formatter)
749988fb7b2SAdrian Ambrożewicz             {
750988fb7b2SAdrian Ambrożewicz                 formatter(credentials.user(), credentials.password(), *packed);
751988fb7b2SAdrian Ambrożewicz             }
752988fb7b2SAdrian Ambrożewicz 
753988fb7b2SAdrian Ambrożewicz             return packed;
754988fb7b2SAdrian Ambrożewicz         }
755988fb7b2SAdrian Ambrożewicz 
756988fb7b2SAdrian Ambrożewicz       private:
757988fb7b2SAdrian Ambrożewicz         Credentials credentials;
758988fb7b2SAdrian Ambrożewicz     };
759988fb7b2SAdrian Ambrożewicz 
760988fb7b2SAdrian Ambrożewicz     // Wrapper for boost::async_pipe ensuring proper pipe cleanup
7611214b7e7SGunnar Mills     template <typename Buffer>
7621214b7e7SGunnar Mills     class Pipe
763988fb7b2SAdrian Ambrożewicz     {
764988fb7b2SAdrian Ambrożewicz       public:
765988fb7b2SAdrian Ambrożewicz         using unix_fd = sdbusplus::message::unix_fd;
766988fb7b2SAdrian Ambrożewicz 
767988fb7b2SAdrian Ambrożewicz         Pipe(boost::asio::io_context& io, Buffer&& buffer) :
768988fb7b2SAdrian Ambrożewicz             impl(io), buffer{std::move(buffer)}
7691214b7e7SGunnar Mills         {}
770988fb7b2SAdrian Ambrożewicz 
771988fb7b2SAdrian Ambrożewicz         ~Pipe()
772988fb7b2SAdrian Ambrożewicz         {
773988fb7b2SAdrian Ambrożewicz             // Named pipe needs to be explicitly removed
774988fb7b2SAdrian Ambrożewicz             impl.close();
775988fb7b2SAdrian Ambrożewicz         }
776988fb7b2SAdrian Ambrożewicz 
777988fb7b2SAdrian Ambrożewicz         unix_fd fd()
778988fb7b2SAdrian Ambrożewicz         {
779988fb7b2SAdrian Ambrożewicz             return unix_fd{impl.native_source()};
780988fb7b2SAdrian Ambrożewicz         }
781988fb7b2SAdrian Ambrożewicz 
782988fb7b2SAdrian Ambrożewicz         template <typename WriteHandler>
78381ce609eSEd Tanous         void asyncWrite(WriteHandler&& handler)
784988fb7b2SAdrian Ambrożewicz         {
785988fb7b2SAdrian Ambrożewicz             impl.async_write_some(data(), std::forward<WriteHandler>(handler));
786988fb7b2SAdrian Ambrożewicz         }
787988fb7b2SAdrian Ambrożewicz 
788988fb7b2SAdrian Ambrożewicz       private:
789988fb7b2SAdrian Ambrożewicz         // Specialization for pointer types
790988fb7b2SAdrian Ambrożewicz         template <typename B = Buffer>
791988fb7b2SAdrian Ambrożewicz         typename std::enable_if<boost::has_dereference<B>::value,
792988fb7b2SAdrian Ambrożewicz                                 boost::asio::const_buffer>::type
793988fb7b2SAdrian Ambrożewicz             data()
794988fb7b2SAdrian Ambrożewicz         {
795988fb7b2SAdrian Ambrożewicz             return boost::asio::buffer(*buffer);
796988fb7b2SAdrian Ambrożewicz         }
797988fb7b2SAdrian Ambrożewicz 
798988fb7b2SAdrian Ambrożewicz         template <typename B = Buffer>
799988fb7b2SAdrian Ambrożewicz         typename std::enable_if<!boost::has_dereference<B>::value,
800988fb7b2SAdrian Ambrożewicz                                 boost::asio::const_buffer>::type
801988fb7b2SAdrian Ambrożewicz             data()
802988fb7b2SAdrian Ambrożewicz         {
803988fb7b2SAdrian Ambrożewicz             return boost::asio::buffer(buffer);
804988fb7b2SAdrian Ambrożewicz         }
805988fb7b2SAdrian Ambrożewicz 
806988fb7b2SAdrian Ambrożewicz         const std::string name;
807988fb7b2SAdrian Ambrożewicz         boost::process::async_pipe impl;
808988fb7b2SAdrian Ambrożewicz         Buffer buffer;
809988fb7b2SAdrian Ambrożewicz     };
810988fb7b2SAdrian Ambrożewicz 
811e13c2760SPrzemyslaw Czarnowski     /**
812e13c2760SPrzemyslaw Czarnowski      * @brief Function transceives data with dbus directly.
813e13c2760SPrzemyslaw Czarnowski      *
814e13c2760SPrzemyslaw Czarnowski      * All BMC state properties will be retrieved before sending reset request.
815e13c2760SPrzemyslaw Czarnowski      */
8168d1b46d7Szhanghch05     void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
817e13c2760SPrzemyslaw Czarnowski                          const std::string& service, const std::string& name,
818988fb7b2SAdrian Ambrożewicz                          const std::string& imageUrl, const bool rw,
819988fb7b2SAdrian Ambrożewicz                          std::string&& userName, std::string&& password)
820e13c2760SPrzemyslaw Czarnowski     {
821988fb7b2SAdrian Ambrożewicz         using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
822988fb7b2SAdrian Ambrożewicz         constexpr const size_t secretLimit = 1024;
823988fb7b2SAdrian Ambrożewicz 
824988fb7b2SAdrian Ambrożewicz         std::shared_ptr<SecurePipe> secretPipe;
825988fb7b2SAdrian Ambrożewicz         std::variant<int, SecurePipe::unix_fd> unixFd = -1;
826988fb7b2SAdrian Ambrożewicz 
827988fb7b2SAdrian Ambrożewicz         if (!userName.empty() || !password.empty())
828988fb7b2SAdrian Ambrożewicz         {
829988fb7b2SAdrian Ambrożewicz             // Encapsulate in safe buffer
830988fb7b2SAdrian Ambrożewicz             CredentialsProvider credentials(std::move(userName),
831988fb7b2SAdrian Ambrożewicz                                             std::move(password));
832988fb7b2SAdrian Ambrożewicz 
833988fb7b2SAdrian Ambrożewicz             // Payload must contain data + NULL delimiters
834988fb7b2SAdrian Ambrożewicz             if (credentials.user().size() + credentials.password().size() + 2 >
835988fb7b2SAdrian Ambrożewicz                 secretLimit)
836988fb7b2SAdrian Ambrożewicz             {
837988fb7b2SAdrian Ambrożewicz                 BMCWEB_LOG_ERROR << "Credentials too long to handle";
838988fb7b2SAdrian Ambrożewicz                 messages::unrecognizedRequestBody(asyncResp->res);
839988fb7b2SAdrian Ambrożewicz                 return;
840988fb7b2SAdrian Ambrożewicz             }
841988fb7b2SAdrian Ambrożewicz 
842988fb7b2SAdrian Ambrożewicz             // Pack secret
843988fb7b2SAdrian Ambrożewicz             auto secret = credentials.pack([](const auto& user,
844988fb7b2SAdrian Ambrożewicz                                               const auto& pass, auto& buff) {
845988fb7b2SAdrian Ambrożewicz                 std::copy(user.begin(), user.end(), std::back_inserter(buff));
846988fb7b2SAdrian Ambrożewicz                 buff.push_back('\0');
847988fb7b2SAdrian Ambrożewicz                 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
848988fb7b2SAdrian Ambrożewicz                 buff.push_back('\0');
849988fb7b2SAdrian Ambrożewicz             });
850988fb7b2SAdrian Ambrożewicz 
851988fb7b2SAdrian Ambrożewicz             // Open pipe
852988fb7b2SAdrian Ambrożewicz             secretPipe = std::make_shared<SecurePipe>(
853988fb7b2SAdrian Ambrożewicz                 crow::connections::systemBus->get_io_context(),
854988fb7b2SAdrian Ambrożewicz                 std::move(secret));
855988fb7b2SAdrian Ambrożewicz             unixFd = secretPipe->fd();
856988fb7b2SAdrian Ambrożewicz 
857988fb7b2SAdrian Ambrożewicz             // Pass secret over pipe
85881ce609eSEd Tanous             secretPipe->asyncWrite(
859f5b16f03SVikram Bodireddy                 [asyncResp](const boost::system::error_code& ec, std::size_t) {
860988fb7b2SAdrian Ambrożewicz                     if (ec)
861988fb7b2SAdrian Ambrożewicz                     {
862988fb7b2SAdrian Ambrożewicz                         BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
863988fb7b2SAdrian Ambrożewicz                         messages::internalError(asyncResp->res);
864988fb7b2SAdrian Ambrożewicz                     }
865988fb7b2SAdrian Ambrożewicz                 });
866988fb7b2SAdrian Ambrożewicz         }
867988fb7b2SAdrian Ambrożewicz 
868e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
869988fb7b2SAdrian Ambrożewicz             [asyncResp, secretPipe](const boost::system::error_code ec,
870988fb7b2SAdrian Ambrożewicz                                     bool success) {
871e13c2760SPrzemyslaw Czarnowski                 if (ec)
872e13c2760SPrzemyslaw Czarnowski                 {
873e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
874e13c2760SPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
875d6da5bebSAdrian Ambrożewicz                 }
876d6da5bebSAdrian Ambrożewicz                 else if (!success)
877d6da5bebSAdrian Ambrożewicz                 {
878d6da5bebSAdrian Ambrożewicz                     BMCWEB_LOG_ERROR << "Service responded with error";
879d6da5bebSAdrian Ambrożewicz                     messages::generalError(asyncResp->res);
880e13c2760SPrzemyslaw Czarnowski                 }
881e13c2760SPrzemyslaw Czarnowski             },
882e13c2760SPrzemyslaw Czarnowski             service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
883988fb7b2SAdrian Ambrożewicz             "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
884988fb7b2SAdrian Ambrożewicz             unixFd);
885e13c2760SPrzemyslaw Czarnowski     }
886e13c2760SPrzemyslaw Czarnowski };
887e13c2760SPrzemyslaw Czarnowski 
888e13c2760SPrzemyslaw Czarnowski /**
889e13c2760SPrzemyslaw Czarnowski    @brief EjectMedia action class
890e13c2760SPrzemyslaw Czarnowski  */
891e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionEjectMedia : public Node
892e13c2760SPrzemyslaw Czarnowski {
893e13c2760SPrzemyslaw Czarnowski   public:
89452cc112dSEd Tanous     VirtualMediaActionEjectMedia(App& app) :
895e13c2760SPrzemyslaw Czarnowski         Node(app,
896e13c2760SPrzemyslaw Czarnowski              "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
897e13c2760SPrzemyslaw Czarnowski              "VirtualMedia.EjectMedia",
898e13c2760SPrzemyslaw Czarnowski              std::string(), std::string())
899e13c2760SPrzemyslaw Czarnowski     {
900e13c2760SPrzemyslaw Czarnowski         entityPrivileges = {
901e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
902e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
903e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
904e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
905e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
906e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
907e13c2760SPrzemyslaw Czarnowski     }
908e13c2760SPrzemyslaw Czarnowski 
909e13c2760SPrzemyslaw Czarnowski   private:
910e13c2760SPrzemyslaw Czarnowski     /**
911e13c2760SPrzemyslaw Czarnowski      * @brief Function handles POST method request.
912e13c2760SPrzemyslaw Czarnowski      *
913e13c2760SPrzemyslaw Czarnowski      * Analyzes POST body message before sends Reset request data to dbus.
914e13c2760SPrzemyslaw Czarnowski      */
9158d1b46d7Szhanghch05     void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9168d1b46d7Szhanghch05                 const crow::Request& req,
917e13c2760SPrzemyslaw Czarnowski                 const std::vector<std::string>& params) override
918e13c2760SPrzemyslaw Czarnowski     {
919e13c2760SPrzemyslaw Czarnowski         if (params.size() != 2)
920e13c2760SPrzemyslaw Czarnowski         {
9218d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
922e13c2760SPrzemyslaw Czarnowski             return;
923e13c2760SPrzemyslaw Czarnowski         }
924e13c2760SPrzemyslaw Czarnowski 
925e13c2760SPrzemyslaw Czarnowski         // take resource name from URL
926e13c2760SPrzemyslaw Czarnowski         const std::string& resName = params[1];
927e13c2760SPrzemyslaw Czarnowski 
928e13c2760SPrzemyslaw Czarnowski         if (params[0] != "bmc")
929e13c2760SPrzemyslaw Czarnowski         {
9308d1b46d7Szhanghch05             messages::resourceNotFound(asyncResp->res, "VirtualMedia.Eject",
9318d1b46d7Szhanghch05                                        resName);
932e13c2760SPrzemyslaw Czarnowski 
933e13c2760SPrzemyslaw Czarnowski             return;
934e13c2760SPrzemyslaw Czarnowski         }
935e13c2760SPrzemyslaw Czarnowski 
936e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
9378d1b46d7Szhanghch05             [this, asyncResp{std::move(asyncResp)}, req,
938e13c2760SPrzemyslaw Czarnowski              resName](const boost::system::error_code ec,
939e13c2760SPrzemyslaw Czarnowski                       const GetObjectType& getObjectType) {
940e13c2760SPrzemyslaw Czarnowski                 if (ec)
941e13c2760SPrzemyslaw Czarnowski                 {
942e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
943e13c2760SPrzemyslaw Czarnowski                                      << ec;
9448d1b46d7Szhanghch05                     messages::internalError(asyncResp->res);
945e13c2760SPrzemyslaw Czarnowski 
946e13c2760SPrzemyslaw Czarnowski                     return;
947e13c2760SPrzemyslaw Czarnowski                 }
948e13c2760SPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
949e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
950e13c2760SPrzemyslaw Czarnowski 
951e13c2760SPrzemyslaw Czarnowski                 crow::connections::systemBus->async_method_call(
95281ce609eSEd Tanous                     [this, resName, service, req,
9538d1b46d7Szhanghch05                      asyncResp{asyncResp}](const boost::system::error_code ec,
954e13c2760SPrzemyslaw Czarnowski                                            ManagedObjectType& subtree) {
955e13c2760SPrzemyslaw Czarnowski                         if (ec)
956e13c2760SPrzemyslaw Czarnowski                         {
957e13c2760SPrzemyslaw Czarnowski                             BMCWEB_LOG_DEBUG << "DBUS response error";
958e13c2760SPrzemyslaw Czarnowski 
959e13c2760SPrzemyslaw Czarnowski                             return;
960e13c2760SPrzemyslaw Czarnowski                         }
961e13c2760SPrzemyslaw Czarnowski 
962e13c2760SPrzemyslaw Czarnowski                         for (const auto& object : subtree)
963e13c2760SPrzemyslaw Czarnowski                         {
964e13c2760SPrzemyslaw Czarnowski                             const std::string& path =
965e13c2760SPrzemyslaw Czarnowski                                 static_cast<const std::string&>(object.first);
966e13c2760SPrzemyslaw Czarnowski 
967f23b7296SEd Tanous                             std::size_t lastIndex = path.rfind('/');
968e13c2760SPrzemyslaw Czarnowski                             if (lastIndex == std::string::npos)
969e13c2760SPrzemyslaw Czarnowski                             {
970e13c2760SPrzemyslaw Czarnowski                                 continue;
971e13c2760SPrzemyslaw Czarnowski                             }
972e13c2760SPrzemyslaw Czarnowski 
973e13c2760SPrzemyslaw Czarnowski                             lastIndex += 1;
974e13c2760SPrzemyslaw Czarnowski 
975e13c2760SPrzemyslaw Czarnowski                             if (path.substr(lastIndex) == resName)
976e13c2760SPrzemyslaw Czarnowski                             {
977e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Proxy");
978e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
979e13c2760SPrzemyslaw Czarnowski                                 {
980e13c2760SPrzemyslaw Czarnowski                                     // Proxy mode
9818d1b46d7Szhanghch05                                     doVmAction(asyncResp, service, resName,
9828d1b46d7Szhanghch05                                                false);
983e13c2760SPrzemyslaw Czarnowski                                 }
984e13c2760SPrzemyslaw Czarnowski 
985e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Legacy");
986e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
987e13c2760SPrzemyslaw Czarnowski                                 {
988e13c2760SPrzemyslaw Czarnowski                                     // Legacy mode
9898d1b46d7Szhanghch05                                     doVmAction(asyncResp, service, resName,
9908d1b46d7Szhanghch05                                                true);
991e13c2760SPrzemyslaw Czarnowski                                 }
992e13c2760SPrzemyslaw Czarnowski 
993e13c2760SPrzemyslaw Czarnowski                                 return;
994e13c2760SPrzemyslaw Czarnowski                             }
995e13c2760SPrzemyslaw Czarnowski                         }
996e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_DEBUG << "Parent item not found";
9978d1b46d7Szhanghch05                         messages::resourceNotFound(asyncResp->res,
9988d1b46d7Szhanghch05                                                    "VirtualMedia", resName);
999e13c2760SPrzemyslaw Czarnowski                     },
1000e13c2760SPrzemyslaw Czarnowski                     service, "/xyz/openbmc_project/VirtualMedia",
1001e13c2760SPrzemyslaw Czarnowski                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1002e13c2760SPrzemyslaw Czarnowski             },
1003e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
1004e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
1005e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
1006e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
1007e13c2760SPrzemyslaw Czarnowski     }
1008e13c2760SPrzemyslaw Czarnowski 
1009e13c2760SPrzemyslaw Czarnowski     /**
1010e13c2760SPrzemyslaw Czarnowski      * @brief Function transceives data with dbus directly.
1011e13c2760SPrzemyslaw Czarnowski      *
1012e13c2760SPrzemyslaw Czarnowski      * All BMC state properties will be retrieved before sending reset request.
1013e13c2760SPrzemyslaw Czarnowski      */
10148d1b46d7Szhanghch05     void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1015e13c2760SPrzemyslaw Czarnowski                     const std::string& service, const std::string& name,
1016e13c2760SPrzemyslaw Czarnowski                     bool legacy)
1017e13c2760SPrzemyslaw Czarnowski     {
1018e13c2760SPrzemyslaw Czarnowski 
1019e13c2760SPrzemyslaw Czarnowski         // Legacy mount requires parameter with image
1020e13c2760SPrzemyslaw Czarnowski         if (legacy)
1021e13c2760SPrzemyslaw Czarnowski         {
1022e13c2760SPrzemyslaw Czarnowski             crow::connections::systemBus->async_method_call(
1023e13c2760SPrzemyslaw Czarnowski                 [asyncResp](const boost::system::error_code ec) {
1024e13c2760SPrzemyslaw Czarnowski                     if (ec)
1025e13c2760SPrzemyslaw Czarnowski                     {
1026e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1027e13c2760SPrzemyslaw Czarnowski 
1028e13c2760SPrzemyslaw Czarnowski                         messages::internalError(asyncResp->res);
1029e13c2760SPrzemyslaw Czarnowski                         return;
1030e13c2760SPrzemyslaw Czarnowski                     }
1031e13c2760SPrzemyslaw Czarnowski                 },
1032e13c2760SPrzemyslaw Czarnowski                 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
1033e13c2760SPrzemyslaw Czarnowski                 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
1034e13c2760SPrzemyslaw Czarnowski         }
1035e13c2760SPrzemyslaw Czarnowski         else // proxy
1036e13c2760SPrzemyslaw Czarnowski         {
1037e13c2760SPrzemyslaw Czarnowski             crow::connections::systemBus->async_method_call(
1038e13c2760SPrzemyslaw Czarnowski                 [asyncResp](const boost::system::error_code ec) {
1039e13c2760SPrzemyslaw Czarnowski                     if (ec)
1040e13c2760SPrzemyslaw Czarnowski                     {
1041e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1042e13c2760SPrzemyslaw Czarnowski 
1043e13c2760SPrzemyslaw Czarnowski                         messages::internalError(asyncResp->res);
1044e13c2760SPrzemyslaw Czarnowski                         return;
1045e13c2760SPrzemyslaw Czarnowski                     }
1046e13c2760SPrzemyslaw Czarnowski                 },
1047e13c2760SPrzemyslaw Czarnowski                 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
1048e13c2760SPrzemyslaw Czarnowski                 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
1049e13c2760SPrzemyslaw Czarnowski         }
1050e13c2760SPrzemyslaw Czarnowski     }
1051e13c2760SPrzemyslaw Czarnowski };
1052e13c2760SPrzemyslaw Czarnowski 
1053107077deSPrzemyslaw Czarnowski class VirtualMediaCollection : public Node
1054107077deSPrzemyslaw Czarnowski {
1055107077deSPrzemyslaw Czarnowski   public:
1056107077deSPrzemyslaw Czarnowski     /*
1057107077deSPrzemyslaw Czarnowski      * Default Constructor
1058107077deSPrzemyslaw Czarnowski      */
105952cc112dSEd Tanous     VirtualMediaCollection(App& app) :
1060107077deSPrzemyslaw Czarnowski         Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
1061107077deSPrzemyslaw Czarnowski     {
1062107077deSPrzemyslaw Czarnowski         entityPrivileges = {
1063107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
1064107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
1065107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1066107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1067107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1068107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1069107077deSPrzemyslaw Czarnowski     }
1070107077deSPrzemyslaw Czarnowski 
1071107077deSPrzemyslaw Czarnowski   private:
1072107077deSPrzemyslaw Czarnowski     /**
1073107077deSPrzemyslaw Czarnowski      * Functions triggers appropriate requests on DBus
1074107077deSPrzemyslaw Czarnowski      */
10758d1b46d7Szhanghch05     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
10768d1b46d7Szhanghch05                const crow::Request&,
1077107077deSPrzemyslaw Czarnowski                const std::vector<std::string>& params) override
1078107077deSPrzemyslaw Czarnowski     {
1079107077deSPrzemyslaw Czarnowski 
1080107077deSPrzemyslaw Czarnowski         // Check if there is required param, truly entering this shall be
1081107077deSPrzemyslaw Czarnowski         // impossible
1082107077deSPrzemyslaw Czarnowski         if (params.size() != 1)
1083107077deSPrzemyslaw Czarnowski         {
10848d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
1085107077deSPrzemyslaw Czarnowski 
1086107077deSPrzemyslaw Czarnowski             return;
1087107077deSPrzemyslaw Czarnowski         }
1088107077deSPrzemyslaw Czarnowski 
1089107077deSPrzemyslaw Czarnowski         const std::string& name = params[0];
1090107077deSPrzemyslaw Czarnowski 
1091107077deSPrzemyslaw Czarnowski         if (name != "bmc")
1092107077deSPrzemyslaw Czarnowski         {
1093107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
1094107077deSPrzemyslaw Czarnowski 
1095107077deSPrzemyslaw Czarnowski             return;
1096107077deSPrzemyslaw Czarnowski         }
1097107077deSPrzemyslaw Czarnowski 
10988d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.type"] =
1099107077deSPrzemyslaw Czarnowski             "#VirtualMediaCollection.VirtualMediaCollection";
11008d1b46d7Szhanghch05         asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
11018d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.id"] =
1102d6c414f3SPrzemyslaw Czarnowski             "/redfish/v1/Managers/" + name + "/VirtualMedia";
1103107077deSPrzemyslaw Czarnowski 
1104107077deSPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
1105107077deSPrzemyslaw Czarnowski             [asyncResp, name](const boost::system::error_code ec,
1106107077deSPrzemyslaw Czarnowski                               const GetObjectType& getObjectType) {
1107107077deSPrzemyslaw Czarnowski                 if (ec)
1108107077deSPrzemyslaw Czarnowski                 {
1109107077deSPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1110107077deSPrzemyslaw Czarnowski                                      << ec;
1111107077deSPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
1112107077deSPrzemyslaw Czarnowski 
1113107077deSPrzemyslaw Czarnowski                     return;
1114107077deSPrzemyslaw Czarnowski                 }
1115107077deSPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
1116107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1117107077deSPrzemyslaw Czarnowski 
1118107077deSPrzemyslaw Czarnowski                 getVmResourceList(asyncResp, service, name);
1119107077deSPrzemyslaw Czarnowski             },
1120107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
1121107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
1122107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
1123107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
1124107077deSPrzemyslaw Czarnowski     }
1125107077deSPrzemyslaw Czarnowski };
1126107077deSPrzemyslaw Czarnowski 
1127107077deSPrzemyslaw Czarnowski class VirtualMedia : public Node
1128107077deSPrzemyslaw Czarnowski {
1129107077deSPrzemyslaw Czarnowski   public:
1130107077deSPrzemyslaw Czarnowski     /*
1131107077deSPrzemyslaw Czarnowski      * Default Constructor
1132107077deSPrzemyslaw Czarnowski      */
113352cc112dSEd Tanous     VirtualMedia(App& app) :
1134107077deSPrzemyslaw Czarnowski         Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
1135107077deSPrzemyslaw Czarnowski              std::string(), std::string())
1136107077deSPrzemyslaw Czarnowski     {
1137107077deSPrzemyslaw Czarnowski         entityPrivileges = {
1138107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
1139107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
1140107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1141107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1142107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1143107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1144107077deSPrzemyslaw Czarnowski     }
1145107077deSPrzemyslaw Czarnowski 
1146107077deSPrzemyslaw Czarnowski   private:
1147107077deSPrzemyslaw Czarnowski     /**
1148107077deSPrzemyslaw Czarnowski      * Functions triggers appropriate requests on DBus
1149107077deSPrzemyslaw Czarnowski      */
11508d1b46d7Szhanghch05     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11518d1b46d7Szhanghch05                const crow::Request&,
1152107077deSPrzemyslaw Czarnowski                const std::vector<std::string>& params) override
1153107077deSPrzemyslaw Czarnowski     {
1154107077deSPrzemyslaw Czarnowski         // Check if there is required param, truly entering this shall be
1155107077deSPrzemyslaw Czarnowski         // impossible
1156107077deSPrzemyslaw Czarnowski         if (params.size() != 2)
1157107077deSPrzemyslaw Czarnowski         {
11588d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
1159107077deSPrzemyslaw Czarnowski             return;
1160107077deSPrzemyslaw Czarnowski         }
1161107077deSPrzemyslaw Czarnowski         const std::string& name = params[0];
1162107077deSPrzemyslaw Czarnowski         const std::string& resName = params[1];
1163107077deSPrzemyslaw Czarnowski 
1164107077deSPrzemyslaw Czarnowski         if (name != "bmc")
1165107077deSPrzemyslaw Czarnowski         {
1166107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1167107077deSPrzemyslaw Czarnowski 
1168107077deSPrzemyslaw Czarnowski             return;
1169107077deSPrzemyslaw Czarnowski         }
1170107077deSPrzemyslaw Czarnowski 
1171107077deSPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
1172107077deSPrzemyslaw Czarnowski             [asyncResp, name, resName](const boost::system::error_code ec,
1173107077deSPrzemyslaw Czarnowski                                        const GetObjectType& getObjectType) {
1174107077deSPrzemyslaw Czarnowski                 if (ec)
1175107077deSPrzemyslaw Czarnowski                 {
1176107077deSPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1177107077deSPrzemyslaw Czarnowski                                      << ec;
1178107077deSPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
1179107077deSPrzemyslaw Czarnowski 
1180107077deSPrzemyslaw Czarnowski                     return;
1181107077deSPrzemyslaw Czarnowski                 }
1182107077deSPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
1183107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1184107077deSPrzemyslaw Czarnowski 
1185107077deSPrzemyslaw Czarnowski                 getVmData(asyncResp, service, name, resName);
1186107077deSPrzemyslaw Czarnowski             },
1187107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
1188107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
1189107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
1190107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
1191107077deSPrzemyslaw Czarnowski     }
1192107077deSPrzemyslaw Czarnowski };
1193107077deSPrzemyslaw Czarnowski 
1194107077deSPrzemyslaw Czarnowski } // namespace redfish
1195