xref: /openbmc/bmcweb/features/redfish/lib/virtual_media.hpp (revision c6f4e01779afb7a6eb25be15003829b46f81ba4c)
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>
25107077deSPrzemyslaw Czarnowski 
26107077deSPrzemyslaw Czarnowski namespace redfish
27107077deSPrzemyslaw Czarnowski 
28107077deSPrzemyslaw Czarnowski {
29107077deSPrzemyslaw Czarnowski 
30107077deSPrzemyslaw Czarnowski /**
31107077deSPrzemyslaw Czarnowski  * @brief Read all known properties from VM object interfaces
32107077deSPrzemyslaw Czarnowski  */
33107077deSPrzemyslaw Czarnowski static void vmParseInterfaceObject(const DbusInterfaceType &interface,
34107077deSPrzemyslaw Czarnowski                                    std::shared_ptr<AsyncResp> aResp)
35107077deSPrzemyslaw Czarnowski {
36107077deSPrzemyslaw Czarnowski     const auto mountPointIface =
37107077deSPrzemyslaw Czarnowski         interface.find("xyz.openbmc_project.VirtualMedia.MountPoint");
38107077deSPrzemyslaw Czarnowski     if (mountPointIface == interface.cend())
39107077deSPrzemyslaw Czarnowski     {
40107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Interface MountPoint not found";
41107077deSPrzemyslaw Czarnowski         return;
42107077deSPrzemyslaw Czarnowski     }
43107077deSPrzemyslaw Czarnowski 
44107077deSPrzemyslaw Czarnowski     const auto processIface =
45107077deSPrzemyslaw Czarnowski         interface.find("xyz.openbmc_project.VirtualMedia.Process");
46107077deSPrzemyslaw Czarnowski     if (processIface == interface.cend())
47107077deSPrzemyslaw Czarnowski     {
48107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Interface Process not found";
49107077deSPrzemyslaw Czarnowski         return;
50107077deSPrzemyslaw Czarnowski     }
51107077deSPrzemyslaw Czarnowski 
52107077deSPrzemyslaw Czarnowski     const auto endpointIdProperty = mountPointIface->second.find("EndpointId");
53107077deSPrzemyslaw Czarnowski     if (endpointIdProperty == mountPointIface->second.cend())
54107077deSPrzemyslaw Czarnowski     {
55107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Property EndpointId not found";
56107077deSPrzemyslaw Czarnowski         return;
57107077deSPrzemyslaw Czarnowski     }
58107077deSPrzemyslaw Czarnowski 
59107077deSPrzemyslaw Czarnowski     const auto activeProperty = processIface->second.find("Active");
60107077deSPrzemyslaw Czarnowski     if (activeProperty == processIface->second.cend())
61107077deSPrzemyslaw Czarnowski     {
62107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Property Active not found";
63107077deSPrzemyslaw Czarnowski         return;
64107077deSPrzemyslaw Czarnowski     }
65107077deSPrzemyslaw Czarnowski 
66107077deSPrzemyslaw Czarnowski     const bool *activeValue = std::get_if<bool>(&activeProperty->second);
67107077deSPrzemyslaw Czarnowski     if (!activeValue)
68107077deSPrzemyslaw Czarnowski     {
69107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Value Active not found";
70107077deSPrzemyslaw Czarnowski         return;
71107077deSPrzemyslaw Czarnowski     }
72107077deSPrzemyslaw Czarnowski 
73107077deSPrzemyslaw Czarnowski     const std::string *endpointIdValue =
74107077deSPrzemyslaw Czarnowski         std::get_if<std::string>(&endpointIdProperty->second);
75107077deSPrzemyslaw Czarnowski     if (endpointIdValue)
76107077deSPrzemyslaw Czarnowski     {
77107077deSPrzemyslaw Czarnowski         if (!endpointIdValue->empty())
78107077deSPrzemyslaw Czarnowski         {
79107077deSPrzemyslaw Czarnowski             // Proxy mode
80d04ba325SPrzemyslaw Czarnowski             aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
81d04ba325SPrzemyslaw Czarnowski                 *endpointIdValue;
82107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["TransferProtocolType"] = "OEM";
83107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["Inserted"] = *activeValue;
84107077deSPrzemyslaw Czarnowski             if (*activeValue == true)
85107077deSPrzemyslaw Czarnowski             {
86107077deSPrzemyslaw Czarnowski                 aResp->res.jsonValue["ConnectedVia"] = "Applet";
87107077deSPrzemyslaw Czarnowski             }
88107077deSPrzemyslaw Czarnowski         }
89107077deSPrzemyslaw Czarnowski         else
90107077deSPrzemyslaw Czarnowski         {
91107077deSPrzemyslaw Czarnowski             // Legacy mode
92107077deSPrzemyslaw Czarnowski             const auto imageUrlProperty =
93107077deSPrzemyslaw Czarnowski                 mountPointIface->second.find("ImageURL");
94107077deSPrzemyslaw Czarnowski             if (imageUrlProperty != processIface->second.cend())
95107077deSPrzemyslaw Czarnowski             {
96107077deSPrzemyslaw Czarnowski                 const std::string *imageUrlValue =
97107077deSPrzemyslaw Czarnowski                     std::get_if<std::string>(&imageUrlProperty->second);
98107077deSPrzemyslaw Czarnowski                 if (imageUrlValue && !imageUrlValue->empty())
99107077deSPrzemyslaw Czarnowski                 {
100107077deSPrzemyslaw Czarnowski                     aResp->res.jsonValue["ImageName"] = *imageUrlValue;
101107077deSPrzemyslaw Czarnowski                     aResp->res.jsonValue["Inserted"] = *activeValue;
102107077deSPrzemyslaw Czarnowski                     if (*activeValue == true)
103107077deSPrzemyslaw Czarnowski                     {
104107077deSPrzemyslaw Czarnowski                         aResp->res.jsonValue["ConnectedVia"] = "URI";
105107077deSPrzemyslaw Czarnowski                     }
106107077deSPrzemyslaw Czarnowski                 }
107107077deSPrzemyslaw Czarnowski             }
108107077deSPrzemyslaw Czarnowski         }
109107077deSPrzemyslaw Czarnowski     }
110107077deSPrzemyslaw Czarnowski }
111107077deSPrzemyslaw Czarnowski 
112107077deSPrzemyslaw Czarnowski /**
113107077deSPrzemyslaw Czarnowski  * @brief Fill template for Virtual Media Item.
114107077deSPrzemyslaw Czarnowski  */
115107077deSPrzemyslaw Czarnowski static nlohmann::json vmItemTemplate(const std::string &name,
116107077deSPrzemyslaw Czarnowski                                      const std::string &resName)
117107077deSPrzemyslaw Czarnowski {
118107077deSPrzemyslaw Czarnowski     nlohmann::json item;
119107077deSPrzemyslaw Czarnowski     item["@odata.id"] =
120107077deSPrzemyslaw Czarnowski         "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
121d04ba325SPrzemyslaw Czarnowski     item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
122107077deSPrzemyslaw Czarnowski     item["Name"] = "Virtual Removable Media";
123107077deSPrzemyslaw Czarnowski     item["Id"] = resName;
124107077deSPrzemyslaw Czarnowski     item["Image"] = nullptr;
125107077deSPrzemyslaw Czarnowski     item["Inserted"] = nullptr;
126107077deSPrzemyslaw Czarnowski     item["ImageName"] = nullptr;
127107077deSPrzemyslaw Czarnowski     item["WriteProtected"] = true;
128107077deSPrzemyslaw Czarnowski     item["ConnectedVia"] = "NotConnected";
129107077deSPrzemyslaw Czarnowski     item["MediaTypes"] = {"CD", "USBStick"};
130107077deSPrzemyslaw Czarnowski     item["TransferMethod"] = "Stream";
131107077deSPrzemyslaw Czarnowski     item["TransferProtocolType"] = nullptr;
132d04ba325SPrzemyslaw Czarnowski     item["Oem"]["OpenBmc"]["WebSocketEndpoint"] = nullptr;
133d04ba325SPrzemyslaw Czarnowski     item["Oem"]["OpenBMC"]["@odata.type"] =
134d04ba325SPrzemyslaw Czarnowski         "#OemVirtualMedia.v1_0_0.VirtualMedia";
135107077deSPrzemyslaw Czarnowski 
136107077deSPrzemyslaw Czarnowski     return item;
137107077deSPrzemyslaw Czarnowski }
138107077deSPrzemyslaw Czarnowski 
139107077deSPrzemyslaw Czarnowski /**
140107077deSPrzemyslaw Czarnowski  *  @brief Fills collection data
141107077deSPrzemyslaw Czarnowski  */
142107077deSPrzemyslaw Czarnowski static void getVmResourceList(std::shared_ptr<AsyncResp> aResp,
143107077deSPrzemyslaw Czarnowski                               const std::string &service,
144107077deSPrzemyslaw Czarnowski                               const std::string &name)
145107077deSPrzemyslaw Czarnowski {
146107077deSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
147107077deSPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
148107077deSPrzemyslaw Czarnowski         [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
149107077deSPrzemyslaw Czarnowski                                         ManagedObjectType &subtree) {
150107077deSPrzemyslaw Czarnowski             if (ec)
151107077deSPrzemyslaw Czarnowski             {
152107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "DBUS response error";
153107077deSPrzemyslaw Czarnowski                 return;
154107077deSPrzemyslaw Czarnowski             }
155107077deSPrzemyslaw Czarnowski             nlohmann::json &members = aResp->res.jsonValue["Members"];
156107077deSPrzemyslaw Czarnowski             members = nlohmann::json::array();
157107077deSPrzemyslaw Czarnowski 
158107077deSPrzemyslaw Czarnowski             for (const auto &object : subtree)
159107077deSPrzemyslaw Czarnowski             {
160107077deSPrzemyslaw Czarnowski                 nlohmann::json item;
161107077deSPrzemyslaw Czarnowski                 const std::string &path =
162107077deSPrzemyslaw Czarnowski                     static_cast<const std::string &>(object.first);
163107077deSPrzemyslaw Czarnowski                 std::size_t lastIndex = path.rfind("/");
164107077deSPrzemyslaw Czarnowski                 if (lastIndex == std::string::npos)
165107077deSPrzemyslaw Czarnowski                 {
166107077deSPrzemyslaw Czarnowski                     continue;
167107077deSPrzemyslaw Czarnowski                 }
168107077deSPrzemyslaw Czarnowski 
169107077deSPrzemyslaw Czarnowski                 lastIndex += 1;
170107077deSPrzemyslaw Czarnowski 
171107077deSPrzemyslaw Czarnowski                 item["@odata.id"] = "/redfish/v1/Managers/" + name +
172107077deSPrzemyslaw Czarnowski                                     "/VirtualMedia/" + path.substr(lastIndex);
173107077deSPrzemyslaw Czarnowski 
174107077deSPrzemyslaw Czarnowski                 members.emplace_back(std::move(item));
175107077deSPrzemyslaw Czarnowski             }
176107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["Members@odata.count"] = members.size();
177107077deSPrzemyslaw Czarnowski         },
178107077deSPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia",
179107077deSPrzemyslaw Czarnowski         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
180107077deSPrzemyslaw Czarnowski }
181107077deSPrzemyslaw Czarnowski 
182107077deSPrzemyslaw Czarnowski /**
183107077deSPrzemyslaw Czarnowski  *  @brief Fills data for specific resource
184107077deSPrzemyslaw Czarnowski  */
185107077deSPrzemyslaw Czarnowski static void getVmData(std::shared_ptr<AsyncResp> aResp,
186107077deSPrzemyslaw Czarnowski                       const std::string &service, const std::string &name,
187107077deSPrzemyslaw Czarnowski                       const std::string &resName)
188107077deSPrzemyslaw Czarnowski {
189107077deSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
190107077deSPrzemyslaw Czarnowski 
191107077deSPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
192107077deSPrzemyslaw Czarnowski         [resName, name, aResp](const boost::system::error_code ec,
193107077deSPrzemyslaw Czarnowski                                ManagedObjectType &subtree) {
194107077deSPrzemyslaw Czarnowski             if (ec)
195107077deSPrzemyslaw Czarnowski             {
196107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "DBUS response error";
197e13c2760SPrzemyslaw Czarnowski 
198107077deSPrzemyslaw Czarnowski                 return;
199107077deSPrzemyslaw Czarnowski             }
200107077deSPrzemyslaw Czarnowski 
201107077deSPrzemyslaw Czarnowski             for (auto &item : subtree)
202107077deSPrzemyslaw Czarnowski             {
203107077deSPrzemyslaw Czarnowski                 const std::string &path =
204107077deSPrzemyslaw Czarnowski                     static_cast<const std::string &>(item.first);
205107077deSPrzemyslaw Czarnowski 
206107077deSPrzemyslaw Czarnowski                 std::size_t lastItem = path.rfind("/");
207107077deSPrzemyslaw Czarnowski                 if (lastItem == std::string::npos)
208107077deSPrzemyslaw Czarnowski                 {
209107077deSPrzemyslaw Czarnowski                     continue;
210107077deSPrzemyslaw Czarnowski                 }
211107077deSPrzemyslaw Czarnowski 
212107077deSPrzemyslaw Czarnowski                 if (path.substr(lastItem + 1) != resName)
213107077deSPrzemyslaw Czarnowski                 {
214107077deSPrzemyslaw Czarnowski                     continue;
215107077deSPrzemyslaw Czarnowski                 }
216107077deSPrzemyslaw Czarnowski 
217107077deSPrzemyslaw Czarnowski                 aResp->res.jsonValue = vmItemTemplate(name, resName);
218107077deSPrzemyslaw Czarnowski 
219e13c2760SPrzemyslaw Czarnowski                 // Check if dbus path is Legacy type
220e13c2760SPrzemyslaw Czarnowski                 if (path.find("VirtualMedia/Legacy") != std::string::npos)
221e13c2760SPrzemyslaw Czarnowski                 {
222e13c2760SPrzemyslaw Czarnowski                     aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
223e13c2760SPrzemyslaw Czarnowski                                         ["target"] =
224e13c2760SPrzemyslaw Czarnowski                         "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
225e13c2760SPrzemyslaw Czarnowski                         resName + "/Actions/VirtualMedia.InsertMedia";
226e13c2760SPrzemyslaw Czarnowski                 }
227e13c2760SPrzemyslaw Czarnowski 
228107077deSPrzemyslaw Czarnowski                 vmParseInterfaceObject(item.second, aResp);
229107077deSPrzemyslaw Czarnowski 
230e13c2760SPrzemyslaw Czarnowski                 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
231e13c2760SPrzemyslaw Czarnowski                                     ["target"] =
232e13c2760SPrzemyslaw Czarnowski                     "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
233e13c2760SPrzemyslaw Czarnowski                     resName + "/Actions/VirtualMedia.EjectMedia";
234e13c2760SPrzemyslaw Czarnowski 
235107077deSPrzemyslaw Czarnowski                 return;
236107077deSPrzemyslaw Czarnowski             }
237107077deSPrzemyslaw Czarnowski 
238107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(
239d04ba325SPrzemyslaw Czarnowski                 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
240107077deSPrzemyslaw Czarnowski         },
241107077deSPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia",
242107077deSPrzemyslaw Czarnowski         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
243107077deSPrzemyslaw Czarnowski }
244107077deSPrzemyslaw Czarnowski 
245e13c2760SPrzemyslaw Czarnowski /**
246e13c2760SPrzemyslaw Czarnowski    @brief InsertMedia action class
247e13c2760SPrzemyslaw Czarnowski  */
248e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionInsertMedia : public Node
249e13c2760SPrzemyslaw Czarnowski {
250e13c2760SPrzemyslaw Czarnowski   public:
251e13c2760SPrzemyslaw Czarnowski     VirtualMediaActionInsertMedia(CrowApp &app) :
252e13c2760SPrzemyslaw Czarnowski         Node(app,
253e13c2760SPrzemyslaw Czarnowski              "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
254e13c2760SPrzemyslaw Czarnowski              "VirtualMedia.InsertMedia",
255e13c2760SPrzemyslaw Czarnowski              std::string(), std::string())
256e13c2760SPrzemyslaw Czarnowski     {
257e13c2760SPrzemyslaw Czarnowski         entityPrivileges = {
258e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
259e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
260e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
261e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
262e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
263e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
264e13c2760SPrzemyslaw Czarnowski     }
265e13c2760SPrzemyslaw Czarnowski 
266e13c2760SPrzemyslaw Czarnowski   private:
267e13c2760SPrzemyslaw Czarnowski     /**
268*c6f4e017SAgata Olender      * @brief Transfer protocols supported for InsertMedia action.
269*c6f4e017SAgata Olender      *
270*c6f4e017SAgata Olender      */
271*c6f4e017SAgata Olender     enum class TransferProtocol
272*c6f4e017SAgata Olender     {
273*c6f4e017SAgata Olender         https,
274*c6f4e017SAgata Olender         smb,
275*c6f4e017SAgata Olender         invalid
276*c6f4e017SAgata Olender     };
277*c6f4e017SAgata Olender 
278*c6f4e017SAgata Olender     /**
279*c6f4e017SAgata Olender      * @brief Function extracts transfer protocol type from URI.
280*c6f4e017SAgata Olender      *
281*c6f4e017SAgata Olender      */
282*c6f4e017SAgata Olender     std::optional<TransferProtocol>
283*c6f4e017SAgata Olender         getTransferProtocolFromUri(const std::string &imageUri)
284*c6f4e017SAgata Olender     {
285*c6f4e017SAgata Olender         if (imageUri.find("smb://") != std::string::npos)
286*c6f4e017SAgata Olender         {
287*c6f4e017SAgata Olender             return TransferProtocol::smb;
288*c6f4e017SAgata Olender         }
289*c6f4e017SAgata Olender         else if (imageUri.find("https://") != std::string::npos)
290*c6f4e017SAgata Olender         {
291*c6f4e017SAgata Olender             return TransferProtocol::https;
292*c6f4e017SAgata Olender         }
293*c6f4e017SAgata Olender         else if (imageUri.find("://") != std::string::npos)
294*c6f4e017SAgata Olender         {
295*c6f4e017SAgata Olender             return TransferProtocol::invalid;
296*c6f4e017SAgata Olender         }
297*c6f4e017SAgata Olender         else
298*c6f4e017SAgata Olender         {
299*c6f4e017SAgata Olender             return {};
300*c6f4e017SAgata Olender         }
301*c6f4e017SAgata Olender     }
302*c6f4e017SAgata Olender 
303*c6f4e017SAgata Olender     /**
304*c6f4e017SAgata Olender      * @brief Function convert transfer protocol from string param.
305*c6f4e017SAgata Olender      *
306*c6f4e017SAgata Olender      */
307*c6f4e017SAgata Olender     std::optional<TransferProtocol> getTransferProtocolFromParam(
308*c6f4e017SAgata Olender         const std::optional<std::string> &transferProtocolType)
309*c6f4e017SAgata Olender     {
310*c6f4e017SAgata Olender         if (transferProtocolType == std::nullopt)
311*c6f4e017SAgata Olender         {
312*c6f4e017SAgata Olender             return {};
313*c6f4e017SAgata Olender         }
314*c6f4e017SAgata Olender 
315*c6f4e017SAgata Olender         if (*transferProtocolType == "CIFS")
316*c6f4e017SAgata Olender         {
317*c6f4e017SAgata Olender             return TransferProtocol::smb;
318*c6f4e017SAgata Olender         }
319*c6f4e017SAgata Olender 
320*c6f4e017SAgata Olender         if (*transferProtocolType == "HTTPS")
321*c6f4e017SAgata Olender         {
322*c6f4e017SAgata Olender             return TransferProtocol::https;
323*c6f4e017SAgata Olender         }
324*c6f4e017SAgata Olender 
325*c6f4e017SAgata Olender         return TransferProtocol::invalid;
326*c6f4e017SAgata Olender     }
327*c6f4e017SAgata Olender 
328*c6f4e017SAgata Olender     /**
329*c6f4e017SAgata Olender      * @brief Function extends URI with transfer protocol type.
330*c6f4e017SAgata Olender      *
331*c6f4e017SAgata Olender      */
332*c6f4e017SAgata Olender     const std::string
333*c6f4e017SAgata Olender         getUriWithTransferProtocol(const std::string &imageUri,
334*c6f4e017SAgata Olender                                    const TransferProtocol &transferProtocol)
335*c6f4e017SAgata Olender     {
336*c6f4e017SAgata Olender         if (transferProtocol == TransferProtocol::smb)
337*c6f4e017SAgata Olender         {
338*c6f4e017SAgata Olender             return "smb://" + imageUri;
339*c6f4e017SAgata Olender         }
340*c6f4e017SAgata Olender 
341*c6f4e017SAgata Olender         if (transferProtocol == TransferProtocol::https)
342*c6f4e017SAgata Olender         {
343*c6f4e017SAgata Olender             return "https://" + imageUri;
344*c6f4e017SAgata Olender         }
345*c6f4e017SAgata Olender 
346*c6f4e017SAgata Olender         return imageUri;
347*c6f4e017SAgata Olender     }
348*c6f4e017SAgata Olender 
349*c6f4e017SAgata Olender     /**
350*c6f4e017SAgata Olender      * @brief Function validate parameters of insert media request.
351*c6f4e017SAgata Olender      *
352*c6f4e017SAgata Olender      */
353*c6f4e017SAgata Olender     bool validateParams(crow::Response &res, std::string &imageUrl,
354*c6f4e017SAgata Olender                         const std::optional<bool> &inserted,
355*c6f4e017SAgata Olender                         const std::optional<std::string> &transferMethod,
356*c6f4e017SAgata Olender                         const std::optional<std::string> &transferProtocolType)
357*c6f4e017SAgata Olender     {
358*c6f4e017SAgata Olender         BMCWEB_LOG_DEBUG << "Validation started";
359*c6f4e017SAgata Olender         // required param imageUrl must not be empty
360*c6f4e017SAgata Olender         if (imageUrl.empty())
361*c6f4e017SAgata Olender         {
362*c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
363*c6f4e017SAgata Olender 
364*c6f4e017SAgata Olender             messages::propertyValueFormatError(res, "<empty>", "Image");
365*c6f4e017SAgata Olender 
366*c6f4e017SAgata Olender             return false;
367*c6f4e017SAgata Olender         }
368*c6f4e017SAgata Olender 
369*c6f4e017SAgata Olender         // optional param inserted must be true
370*c6f4e017SAgata Olender         if ((inserted != std::nullopt) && (*inserted != true))
371*c6f4e017SAgata Olender         {
372*c6f4e017SAgata Olender             BMCWEB_LOG_ERROR
373*c6f4e017SAgata Olender                 << "Request action optional parameter Inserted must be true.";
374*c6f4e017SAgata Olender 
375*c6f4e017SAgata Olender             messages::actionParameterNotSupported(res, "Inserted",
376*c6f4e017SAgata Olender                                                   "InsertMedia");
377*c6f4e017SAgata Olender 
378*c6f4e017SAgata Olender             return false;
379*c6f4e017SAgata Olender         }
380*c6f4e017SAgata Olender 
381*c6f4e017SAgata Olender         // optional param transferMethod must be stream
382*c6f4e017SAgata Olender         if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
383*c6f4e017SAgata Olender         {
384*c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action optional parameter "
385*c6f4e017SAgata Olender                                 "TransferMethod must be Stream.";
386*c6f4e017SAgata Olender 
387*c6f4e017SAgata Olender             messages::actionParameterNotSupported(res, "TransferMethod",
388*c6f4e017SAgata Olender                                                   "InsertMedia");
389*c6f4e017SAgata Olender 
390*c6f4e017SAgata Olender             return false;
391*c6f4e017SAgata Olender         }
392*c6f4e017SAgata Olender 
393*c6f4e017SAgata Olender         std::optional<TransferProtocol> uriTransferProtocolType =
394*c6f4e017SAgata Olender             getTransferProtocolFromUri(imageUrl);
395*c6f4e017SAgata Olender 
396*c6f4e017SAgata Olender         std::optional<TransferProtocol> paramTransferProtocolType =
397*c6f4e017SAgata Olender             getTransferProtocolFromParam(transferProtocolType);
398*c6f4e017SAgata Olender 
399*c6f4e017SAgata Olender         // ImageUrl does not contain valid protocol type
400*c6f4e017SAgata Olender         if (*uriTransferProtocolType == TransferProtocol::invalid)
401*c6f4e017SAgata Olender         {
402*c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
403*c6f4e017SAgata Olender                                 "contain specified protocol type from list: "
404*c6f4e017SAgata Olender                                 "(smb, https).";
405*c6f4e017SAgata Olender 
406*c6f4e017SAgata Olender             messages::resourceAtUriInUnknownFormat(res, imageUrl);
407*c6f4e017SAgata Olender 
408*c6f4e017SAgata Olender             return false;
409*c6f4e017SAgata Olender         }
410*c6f4e017SAgata Olender 
411*c6f4e017SAgata Olender         // transferProtocolType should contain value from list
412*c6f4e017SAgata Olender         if (*paramTransferProtocolType == TransferProtocol::invalid)
413*c6f4e017SAgata Olender         {
414*c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
415*c6f4e017SAgata Olender                                 "must be provided with value from list: "
416*c6f4e017SAgata Olender                                 "(CIFS, HTTPS).";
417*c6f4e017SAgata Olender 
418*c6f4e017SAgata Olender             messages::propertyValueNotInList(res, *transferProtocolType,
419*c6f4e017SAgata Olender                                              "TransferProtocolType");
420*c6f4e017SAgata Olender             return false;
421*c6f4e017SAgata Olender         }
422*c6f4e017SAgata Olender 
423*c6f4e017SAgata Olender         // valid transfer protocol not provided either with URI nor param
424*c6f4e017SAgata Olender         if ((uriTransferProtocolType == std::nullopt) &&
425*c6f4e017SAgata Olender             (paramTransferProtocolType == std::nullopt))
426*c6f4e017SAgata Olender         {
427*c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
428*c6f4e017SAgata Olender                                 "contain specified protocol type or param "
429*c6f4e017SAgata Olender                                 "TransferProtocolType must be provided.";
430*c6f4e017SAgata Olender 
431*c6f4e017SAgata Olender             messages::resourceAtUriInUnknownFormat(res, imageUrl);
432*c6f4e017SAgata Olender 
433*c6f4e017SAgata Olender             return false;
434*c6f4e017SAgata Olender         }
435*c6f4e017SAgata Olender 
436*c6f4e017SAgata Olender         // valid transfer protocol provided both with URI and param
437*c6f4e017SAgata Olender         if ((paramTransferProtocolType != std::nullopt) &&
438*c6f4e017SAgata Olender             (uriTransferProtocolType != std::nullopt))
439*c6f4e017SAgata Olender         {
440*c6f4e017SAgata Olender             // check if protocol is the same for URI and param
441*c6f4e017SAgata Olender             if (*paramTransferProtocolType != *uriTransferProtocolType)
442*c6f4e017SAgata Olender             {
443*c6f4e017SAgata Olender                 BMCWEB_LOG_ERROR << "Request action parameter "
444*c6f4e017SAgata Olender                                     "TransferProtocolType must  contain the "
445*c6f4e017SAgata Olender                                     "same protocol type as protocol type "
446*c6f4e017SAgata Olender                                     "provided with param imageUrl.";
447*c6f4e017SAgata Olender 
448*c6f4e017SAgata Olender                 messages::actionParameterValueTypeError(
449*c6f4e017SAgata Olender                     res, *transferProtocolType, "TransferProtocolType",
450*c6f4e017SAgata Olender                     "InsertMedia");
451*c6f4e017SAgata Olender 
452*c6f4e017SAgata Olender                 return false;
453*c6f4e017SAgata Olender             }
454*c6f4e017SAgata Olender         }
455*c6f4e017SAgata Olender 
456*c6f4e017SAgata Olender         // validation passed
457*c6f4e017SAgata Olender         // add protocol to URI if needed
458*c6f4e017SAgata Olender         if (uriTransferProtocolType == std::nullopt)
459*c6f4e017SAgata Olender         {
460*c6f4e017SAgata Olender             imageUrl = getUriWithTransferProtocol(imageUrl,
461*c6f4e017SAgata Olender                                                   *paramTransferProtocolType);
462*c6f4e017SAgata Olender         }
463*c6f4e017SAgata Olender 
464*c6f4e017SAgata Olender         return true;
465*c6f4e017SAgata Olender     }
466*c6f4e017SAgata Olender 
467*c6f4e017SAgata Olender     /**
468e13c2760SPrzemyslaw Czarnowski      * @brief Function handles POST method request.
469e13c2760SPrzemyslaw Czarnowski      *
470e13c2760SPrzemyslaw Czarnowski      * Analyzes POST body message before sends Reset request data to dbus.
471e13c2760SPrzemyslaw Czarnowski      */
472e13c2760SPrzemyslaw Czarnowski     void doPost(crow::Response &res, const crow::Request &req,
473e13c2760SPrzemyslaw Czarnowski                 const std::vector<std::string> &params) override
474e13c2760SPrzemyslaw Czarnowski     {
475e13c2760SPrzemyslaw Czarnowski         auto aResp = std::make_shared<AsyncResp>(res);
476e13c2760SPrzemyslaw Czarnowski 
477e13c2760SPrzemyslaw Czarnowski         if (params.size() != 2)
478e13c2760SPrzemyslaw Czarnowski         {
479e13c2760SPrzemyslaw Czarnowski             messages::internalError(res);
480e13c2760SPrzemyslaw Czarnowski             return;
481e13c2760SPrzemyslaw Czarnowski         }
482e13c2760SPrzemyslaw Czarnowski 
483e13c2760SPrzemyslaw Czarnowski         // take resource name from URL
484e13c2760SPrzemyslaw Czarnowski         const std::string &resName = params[1];
485e13c2760SPrzemyslaw Czarnowski 
486e13c2760SPrzemyslaw Czarnowski         if (params[0] != "bmc")
487e13c2760SPrzemyslaw Czarnowski         {
488e13c2760SPrzemyslaw Czarnowski             messages::resourceNotFound(res, "VirtualMedia.Insert", resName);
489e13c2760SPrzemyslaw Czarnowski 
490e13c2760SPrzemyslaw Czarnowski             return;
491e13c2760SPrzemyslaw Czarnowski         }
492e13c2760SPrzemyslaw Czarnowski 
493e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
494e13c2760SPrzemyslaw Czarnowski             [this, aResp{std::move(aResp)}, req,
495e13c2760SPrzemyslaw Czarnowski              resName](const boost::system::error_code ec,
496e13c2760SPrzemyslaw Czarnowski                       const GetObjectType &getObjectType) {
497e13c2760SPrzemyslaw Czarnowski                 if (ec)
498e13c2760SPrzemyslaw Czarnowski                 {
499e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
500e13c2760SPrzemyslaw Czarnowski                                      << ec;
501e13c2760SPrzemyslaw Czarnowski                     messages::internalError(aResp->res);
502e13c2760SPrzemyslaw Czarnowski 
503e13c2760SPrzemyslaw Czarnowski                     return;
504e13c2760SPrzemyslaw Czarnowski                 }
505e13c2760SPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
506e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
507e13c2760SPrzemyslaw Czarnowski 
508e13c2760SPrzemyslaw Czarnowski                 crow::connections::systemBus->async_method_call(
509e13c2760SPrzemyslaw Czarnowski                     [this, service, resName, req, aResp{std::move(aResp)}](
510e13c2760SPrzemyslaw Czarnowski                         const boost::system::error_code ec,
511e13c2760SPrzemyslaw Czarnowski                         ManagedObjectType &subtree) {
512e13c2760SPrzemyslaw Czarnowski                         if (ec)
513e13c2760SPrzemyslaw Czarnowski                         {
514e13c2760SPrzemyslaw Czarnowski                             BMCWEB_LOG_DEBUG << "DBUS response error";
515e13c2760SPrzemyslaw Czarnowski 
516e13c2760SPrzemyslaw Czarnowski                             return;
517e13c2760SPrzemyslaw Czarnowski                         }
518e13c2760SPrzemyslaw Czarnowski 
519e13c2760SPrzemyslaw Czarnowski                         for (const auto &object : subtree)
520e13c2760SPrzemyslaw Czarnowski                         {
521e13c2760SPrzemyslaw Czarnowski                             const std::string &path =
522e13c2760SPrzemyslaw Czarnowski                                 static_cast<const std::string &>(object.first);
523e13c2760SPrzemyslaw Czarnowski 
524e13c2760SPrzemyslaw Czarnowski                             std::size_t lastIndex = path.rfind("/");
525e13c2760SPrzemyslaw Czarnowski                             if (lastIndex == std::string::npos)
526e13c2760SPrzemyslaw Czarnowski                             {
527e13c2760SPrzemyslaw Czarnowski                                 continue;
528e13c2760SPrzemyslaw Czarnowski                             }
529e13c2760SPrzemyslaw Czarnowski 
530e13c2760SPrzemyslaw Czarnowski                             lastIndex += 1;
531e13c2760SPrzemyslaw Czarnowski 
532e13c2760SPrzemyslaw Czarnowski                             if (path.substr(lastIndex) == resName)
533e13c2760SPrzemyslaw Czarnowski                             {
534e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Proxy");
535e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
536e13c2760SPrzemyslaw Czarnowski                                 {
537e13c2760SPrzemyslaw Czarnowski                                     // Not possible in proxy mode
538e13c2760SPrzemyslaw Czarnowski                                     BMCWEB_LOG_DEBUG << "InsertMedia not "
539e13c2760SPrzemyslaw Czarnowski                                                         "allowed in proxy mode";
540e13c2760SPrzemyslaw Czarnowski                                     messages::resourceNotFound(
541e13c2760SPrzemyslaw Czarnowski                                         aResp->res, "VirtualMedia.InsertMedia",
542e13c2760SPrzemyslaw Czarnowski                                         resName);
543e13c2760SPrzemyslaw Czarnowski 
544e13c2760SPrzemyslaw Czarnowski                                     return;
545e13c2760SPrzemyslaw Czarnowski                                 }
546e13c2760SPrzemyslaw Czarnowski 
547e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Legacy");
548*c6f4e017SAgata Olender                                 if (lastIndex == std::string::npos)
549e13c2760SPrzemyslaw Czarnowski                                 {
550*c6f4e017SAgata Olender                                     continue;
551*c6f4e017SAgata Olender                                 }
552*c6f4e017SAgata Olender 
553e13c2760SPrzemyslaw Czarnowski                                 // Legacy mode
554e13c2760SPrzemyslaw Czarnowski                                 std::string imageUrl;
555*c6f4e017SAgata Olender                                 std::optional<std::string> userName;
556*c6f4e017SAgata Olender                                 std::optional<std::string> password;
557*c6f4e017SAgata Olender                                 std::optional<std::string> transferMethod;
558*c6f4e017SAgata Olender                                 std::optional<std::string> transferProtocolType;
559*c6f4e017SAgata Olender                                 std::optional<bool> writeProtected = true;
560*c6f4e017SAgata Olender                                 std::optional<bool> inserted;
561e13c2760SPrzemyslaw Czarnowski 
562e13c2760SPrzemyslaw Czarnowski                                 // Read obligatory paramters (url of image)
563d6da5bebSAdrian Ambrożewicz                                 if (!json_util::readJson(
564d6da5bebSAdrian Ambrożewicz                                         req, aResp->res, "Image", imageUrl,
565988fb7b2SAdrian Ambrożewicz                                         "WriteProtected", writeProtected,
566988fb7b2SAdrian Ambrożewicz                                         "UserName", userName, "Password",
567*c6f4e017SAgata Olender                                         password, "Inserted", inserted,
568*c6f4e017SAgata Olender                                         "TransferMethod", transferMethod,
569*c6f4e017SAgata Olender                                         "TransferProtocolType",
570*c6f4e017SAgata Olender                                         transferProtocolType))
571e13c2760SPrzemyslaw Czarnowski                                 {
572*c6f4e017SAgata Olender                                     BMCWEB_LOG_DEBUG << "Image is not provided";
573e13c2760SPrzemyslaw Czarnowski                                     return;
574e13c2760SPrzemyslaw Czarnowski                                 }
575e13c2760SPrzemyslaw Czarnowski 
576*c6f4e017SAgata Olender                                 bool paramsValid = validateParams(
577*c6f4e017SAgata Olender                                     aResp->res, imageUrl, inserted,
578*c6f4e017SAgata Olender                                     transferMethod, transferProtocolType);
579*c6f4e017SAgata Olender 
580*c6f4e017SAgata Olender                                 if (paramsValid == false)
581e13c2760SPrzemyslaw Czarnowski                                 {
582e13c2760SPrzemyslaw Czarnowski                                     return;
583e13c2760SPrzemyslaw Czarnowski                                 }
584e13c2760SPrzemyslaw Czarnowski 
585*c6f4e017SAgata Olender                                 // manager is irrelevant for VirtualMedia dbus
586*c6f4e017SAgata Olender                                 // calls
587*c6f4e017SAgata Olender                                 doMountVmLegacy(
588*c6f4e017SAgata Olender                                     std::move(aResp), service, resName,
589*c6f4e017SAgata Olender                                     imageUrl, !(*writeProtected),
590*c6f4e017SAgata Olender                                     std::move(*userName), std::move(*password));
591e13c2760SPrzemyslaw Czarnowski 
592e13c2760SPrzemyslaw Czarnowski                                 return;
593e13c2760SPrzemyslaw Czarnowski                             }
594e13c2760SPrzemyslaw Czarnowski                         }
595e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_DEBUG << "Parent item not found";
596e13c2760SPrzemyslaw Czarnowski                         messages::resourceNotFound(aResp->res, "VirtualMedia",
597e13c2760SPrzemyslaw Czarnowski                                                    resName);
598e13c2760SPrzemyslaw Czarnowski                     },
599e13c2760SPrzemyslaw Czarnowski                     service, "/xyz/openbmc_project/VirtualMedia",
600e13c2760SPrzemyslaw Czarnowski                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
601e13c2760SPrzemyslaw Czarnowski             },
602e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
603e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
604e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
605e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
606e13c2760SPrzemyslaw Czarnowski     }
607e13c2760SPrzemyslaw Czarnowski 
608988fb7b2SAdrian Ambrożewicz     template <typename T> static void secureCleanup(T &value)
609988fb7b2SAdrian Ambrożewicz     {
610988fb7b2SAdrian Ambrożewicz         auto raw = const_cast<typename T::value_type *>(value.data());
611988fb7b2SAdrian Ambrożewicz         explicit_bzero(raw, value.size() * sizeof(*raw));
612988fb7b2SAdrian Ambrożewicz     }
613988fb7b2SAdrian Ambrożewicz 
614988fb7b2SAdrian Ambrożewicz     class Credentials
615988fb7b2SAdrian Ambrożewicz     {
616988fb7b2SAdrian Ambrożewicz       public:
617988fb7b2SAdrian Ambrożewicz         Credentials(std::string &&user, std::string &&password) :
618988fb7b2SAdrian Ambrożewicz             userBuf(std::move(user)), passBuf(std::move(password))
619988fb7b2SAdrian Ambrożewicz         {
620988fb7b2SAdrian Ambrożewicz         }
621988fb7b2SAdrian Ambrożewicz 
622988fb7b2SAdrian Ambrożewicz         ~Credentials()
623988fb7b2SAdrian Ambrożewicz         {
624988fb7b2SAdrian Ambrożewicz             secureCleanup(userBuf);
625988fb7b2SAdrian Ambrożewicz             secureCleanup(passBuf);
626988fb7b2SAdrian Ambrożewicz         }
627988fb7b2SAdrian Ambrożewicz 
628988fb7b2SAdrian Ambrożewicz         const std::string &user()
629988fb7b2SAdrian Ambrożewicz         {
630988fb7b2SAdrian Ambrożewicz             return userBuf;
631988fb7b2SAdrian Ambrożewicz         }
632988fb7b2SAdrian Ambrożewicz 
633988fb7b2SAdrian Ambrożewicz         const std::string &password()
634988fb7b2SAdrian Ambrożewicz         {
635988fb7b2SAdrian Ambrożewicz             return passBuf;
636988fb7b2SAdrian Ambrożewicz         }
637988fb7b2SAdrian Ambrożewicz 
638988fb7b2SAdrian Ambrożewicz       private:
639988fb7b2SAdrian Ambrożewicz         Credentials() = delete;
640988fb7b2SAdrian Ambrożewicz         Credentials(const Credentials &) = delete;
641988fb7b2SAdrian Ambrożewicz         Credentials &operator=(const Credentials &) = delete;
642988fb7b2SAdrian Ambrożewicz 
643988fb7b2SAdrian Ambrożewicz         std::string userBuf;
644988fb7b2SAdrian Ambrożewicz         std::string passBuf;
645988fb7b2SAdrian Ambrożewicz     };
646988fb7b2SAdrian Ambrożewicz 
647988fb7b2SAdrian Ambrożewicz     class CredentialsProvider
648988fb7b2SAdrian Ambrożewicz     {
649988fb7b2SAdrian Ambrożewicz       public:
650988fb7b2SAdrian Ambrożewicz         template <typename T> struct Deleter
651988fb7b2SAdrian Ambrożewicz         {
652988fb7b2SAdrian Ambrożewicz             void operator()(T *buff) const
653988fb7b2SAdrian Ambrożewicz             {
654988fb7b2SAdrian Ambrożewicz                 if (buff)
655988fb7b2SAdrian Ambrożewicz                 {
656988fb7b2SAdrian Ambrożewicz                     secureCleanup(*buff);
657988fb7b2SAdrian Ambrożewicz                     delete buff;
658988fb7b2SAdrian Ambrożewicz                 }
659988fb7b2SAdrian Ambrożewicz             }
660988fb7b2SAdrian Ambrożewicz         };
661988fb7b2SAdrian Ambrożewicz 
662988fb7b2SAdrian Ambrożewicz         using Buffer = std::vector<char>;
663988fb7b2SAdrian Ambrożewicz         using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
664988fb7b2SAdrian Ambrożewicz         // Using explicit definition instead of std::function to avoid implicit
665988fb7b2SAdrian Ambrożewicz         // conversions eg. stack copy instead of reference
666988fb7b2SAdrian Ambrożewicz         using FormatterFunc = void(const std::string &username,
667988fb7b2SAdrian Ambrożewicz                                    const std::string &password, Buffer &dest);
668988fb7b2SAdrian Ambrożewicz 
669988fb7b2SAdrian Ambrożewicz         CredentialsProvider(std::string &&user, std::string &&password) :
670988fb7b2SAdrian Ambrożewicz             credentials(std::move(user), std::move(password))
671988fb7b2SAdrian Ambrożewicz         {
672988fb7b2SAdrian Ambrożewicz         }
673988fb7b2SAdrian Ambrożewicz 
674988fb7b2SAdrian Ambrożewicz         const std::string &user()
675988fb7b2SAdrian Ambrożewicz         {
676988fb7b2SAdrian Ambrożewicz             return credentials.user();
677988fb7b2SAdrian Ambrożewicz         }
678988fb7b2SAdrian Ambrożewicz 
679988fb7b2SAdrian Ambrożewicz         const std::string &password()
680988fb7b2SAdrian Ambrożewicz         {
681988fb7b2SAdrian Ambrożewicz             return credentials.password();
682988fb7b2SAdrian Ambrożewicz         }
683988fb7b2SAdrian Ambrożewicz 
684988fb7b2SAdrian Ambrożewicz         SecureBuffer pack(const FormatterFunc formatter)
685988fb7b2SAdrian Ambrożewicz         {
686988fb7b2SAdrian Ambrożewicz             SecureBuffer packed{new Buffer{}};
687988fb7b2SAdrian Ambrożewicz             if (formatter)
688988fb7b2SAdrian Ambrożewicz             {
689988fb7b2SAdrian Ambrożewicz                 formatter(credentials.user(), credentials.password(), *packed);
690988fb7b2SAdrian Ambrożewicz             }
691988fb7b2SAdrian Ambrożewicz 
692988fb7b2SAdrian Ambrożewicz             return packed;
693988fb7b2SAdrian Ambrożewicz         }
694988fb7b2SAdrian Ambrożewicz 
695988fb7b2SAdrian Ambrożewicz       private:
696988fb7b2SAdrian Ambrożewicz         Credentials credentials;
697988fb7b2SAdrian Ambrożewicz     };
698988fb7b2SAdrian Ambrożewicz 
699988fb7b2SAdrian Ambrożewicz     // Wrapper for boost::async_pipe ensuring proper pipe cleanup
700988fb7b2SAdrian Ambrożewicz     template <typename Buffer> class Pipe
701988fb7b2SAdrian Ambrożewicz     {
702988fb7b2SAdrian Ambrożewicz       public:
703988fb7b2SAdrian Ambrożewicz         using unix_fd = sdbusplus::message::unix_fd;
704988fb7b2SAdrian Ambrożewicz 
705988fb7b2SAdrian Ambrożewicz         Pipe(boost::asio::io_context &io, Buffer &&buffer) :
706988fb7b2SAdrian Ambrożewicz             impl(io), buffer{std::move(buffer)}
707988fb7b2SAdrian Ambrożewicz         {
708988fb7b2SAdrian Ambrożewicz         }
709988fb7b2SAdrian Ambrożewicz 
710988fb7b2SAdrian Ambrożewicz         ~Pipe()
711988fb7b2SAdrian Ambrożewicz         {
712988fb7b2SAdrian Ambrożewicz             // Named pipe needs to be explicitly removed
713988fb7b2SAdrian Ambrożewicz             impl.close();
714988fb7b2SAdrian Ambrożewicz         }
715988fb7b2SAdrian Ambrożewicz 
716988fb7b2SAdrian Ambrożewicz         unix_fd fd()
717988fb7b2SAdrian Ambrożewicz         {
718988fb7b2SAdrian Ambrożewicz             return unix_fd{impl.native_source()};
719988fb7b2SAdrian Ambrożewicz         }
720988fb7b2SAdrian Ambrożewicz 
721988fb7b2SAdrian Ambrożewicz         template <typename WriteHandler>
722988fb7b2SAdrian Ambrożewicz         void async_write(WriteHandler &&handler)
723988fb7b2SAdrian Ambrożewicz         {
724988fb7b2SAdrian Ambrożewicz             impl.async_write_some(data(), std::forward<WriteHandler>(handler));
725988fb7b2SAdrian Ambrożewicz         }
726988fb7b2SAdrian Ambrożewicz 
727988fb7b2SAdrian Ambrożewicz       private:
728988fb7b2SAdrian Ambrożewicz         // Specialization for pointer types
729988fb7b2SAdrian Ambrożewicz         template <typename B = Buffer>
730988fb7b2SAdrian Ambrożewicz         typename std::enable_if<boost::has_dereference<B>::value,
731988fb7b2SAdrian Ambrożewicz                                 boost::asio::const_buffer>::type
732988fb7b2SAdrian Ambrożewicz             data()
733988fb7b2SAdrian Ambrożewicz         {
734988fb7b2SAdrian Ambrożewicz             return boost::asio::buffer(*buffer);
735988fb7b2SAdrian Ambrożewicz         }
736988fb7b2SAdrian Ambrożewicz 
737988fb7b2SAdrian Ambrożewicz         template <typename B = Buffer>
738988fb7b2SAdrian Ambrożewicz         typename std::enable_if<!boost::has_dereference<B>::value,
739988fb7b2SAdrian Ambrożewicz                                 boost::asio::const_buffer>::type
740988fb7b2SAdrian Ambrożewicz             data()
741988fb7b2SAdrian Ambrożewicz         {
742988fb7b2SAdrian Ambrożewicz             return boost::asio::buffer(buffer);
743988fb7b2SAdrian Ambrożewicz         }
744988fb7b2SAdrian Ambrożewicz 
745988fb7b2SAdrian Ambrożewicz         const std::string name;
746988fb7b2SAdrian Ambrożewicz         boost::process::async_pipe impl;
747988fb7b2SAdrian Ambrożewicz         Buffer buffer;
748988fb7b2SAdrian Ambrożewicz     };
749988fb7b2SAdrian Ambrożewicz 
750e13c2760SPrzemyslaw Czarnowski     /**
751e13c2760SPrzemyslaw Czarnowski      * @brief Function transceives data with dbus directly.
752e13c2760SPrzemyslaw Czarnowski      *
753e13c2760SPrzemyslaw Czarnowski      * All BMC state properties will be retrieved before sending reset request.
754e13c2760SPrzemyslaw Czarnowski      */
755d6da5bebSAdrian Ambrożewicz     void doMountVmLegacy(std::shared_ptr<AsyncResp> asyncResp,
756e13c2760SPrzemyslaw Czarnowski                          const std::string &service, const std::string &name,
757988fb7b2SAdrian Ambrożewicz                          const std::string &imageUrl, const bool rw,
758988fb7b2SAdrian Ambrożewicz                          std::string &&userName, std::string &&password)
759e13c2760SPrzemyslaw Czarnowski     {
760988fb7b2SAdrian Ambrożewicz         using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
761988fb7b2SAdrian Ambrożewicz         constexpr const size_t secretLimit = 1024;
762988fb7b2SAdrian Ambrożewicz 
763988fb7b2SAdrian Ambrożewicz         std::shared_ptr<SecurePipe> secretPipe;
764988fb7b2SAdrian Ambrożewicz         std::variant<int, SecurePipe::unix_fd> unixFd = -1;
765988fb7b2SAdrian Ambrożewicz 
766988fb7b2SAdrian Ambrożewicz         if (!userName.empty() || !password.empty())
767988fb7b2SAdrian Ambrożewicz         {
768988fb7b2SAdrian Ambrożewicz             // Encapsulate in safe buffer
769988fb7b2SAdrian Ambrożewicz             CredentialsProvider credentials(std::move(userName),
770988fb7b2SAdrian Ambrożewicz                                             std::move(password));
771988fb7b2SAdrian Ambrożewicz 
772988fb7b2SAdrian Ambrożewicz             // Payload must contain data + NULL delimiters
773988fb7b2SAdrian Ambrożewicz             if (credentials.user().size() + credentials.password().size() + 2 >
774988fb7b2SAdrian Ambrożewicz                 secretLimit)
775988fb7b2SAdrian Ambrożewicz             {
776988fb7b2SAdrian Ambrożewicz                 BMCWEB_LOG_ERROR << "Credentials too long to handle";
777988fb7b2SAdrian Ambrożewicz                 messages::unrecognizedRequestBody(asyncResp->res);
778988fb7b2SAdrian Ambrożewicz                 return;
779988fb7b2SAdrian Ambrożewicz             }
780988fb7b2SAdrian Ambrożewicz 
781988fb7b2SAdrian Ambrożewicz             // Pack secret
782988fb7b2SAdrian Ambrożewicz             auto secret = credentials.pack([](const auto &user,
783988fb7b2SAdrian Ambrożewicz                                               const auto &pass, auto &buff) {
784988fb7b2SAdrian Ambrożewicz                 std::copy(user.begin(), user.end(), std::back_inserter(buff));
785988fb7b2SAdrian Ambrożewicz                 buff.push_back('\0');
786988fb7b2SAdrian Ambrożewicz                 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
787988fb7b2SAdrian Ambrożewicz                 buff.push_back('\0');
788988fb7b2SAdrian Ambrożewicz             });
789988fb7b2SAdrian Ambrożewicz 
790988fb7b2SAdrian Ambrożewicz             // Open pipe
791988fb7b2SAdrian Ambrożewicz             secretPipe = std::make_shared<SecurePipe>(
792988fb7b2SAdrian Ambrożewicz                 crow::connections::systemBus->get_io_context(),
793988fb7b2SAdrian Ambrożewicz                 std::move(secret));
794988fb7b2SAdrian Ambrożewicz             unixFd = secretPipe->fd();
795988fb7b2SAdrian Ambrożewicz 
796988fb7b2SAdrian Ambrożewicz             // Pass secret over pipe
797988fb7b2SAdrian Ambrożewicz             secretPipe->async_write(
798988fb7b2SAdrian Ambrożewicz                 [asyncResp](const boost::system::error_code &ec,
799988fb7b2SAdrian Ambrożewicz                             std::size_t size) {
800988fb7b2SAdrian Ambrożewicz                     if (ec)
801988fb7b2SAdrian Ambrożewicz                     {
802988fb7b2SAdrian Ambrożewicz                         BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
803988fb7b2SAdrian Ambrożewicz                         messages::internalError(asyncResp->res);
804988fb7b2SAdrian Ambrożewicz                     }
805988fb7b2SAdrian Ambrożewicz                 });
806988fb7b2SAdrian Ambrożewicz         }
807988fb7b2SAdrian Ambrożewicz 
808e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
809988fb7b2SAdrian Ambrożewicz             [asyncResp, secretPipe](const boost::system::error_code ec,
810988fb7b2SAdrian Ambrożewicz                                     bool success) {
811e13c2760SPrzemyslaw Czarnowski                 if (ec)
812e13c2760SPrzemyslaw Czarnowski                 {
813e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
814e13c2760SPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
815d6da5bebSAdrian Ambrożewicz                 }
816d6da5bebSAdrian Ambrożewicz                 else if (!success)
817d6da5bebSAdrian Ambrożewicz                 {
818d6da5bebSAdrian Ambrożewicz                     BMCWEB_LOG_ERROR << "Service responded with error";
819d6da5bebSAdrian Ambrożewicz                     messages::generalError(asyncResp->res);
820e13c2760SPrzemyslaw Czarnowski                 }
821e13c2760SPrzemyslaw Czarnowski             },
822e13c2760SPrzemyslaw Czarnowski             service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
823988fb7b2SAdrian Ambrożewicz             "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
824988fb7b2SAdrian Ambrożewicz             unixFd);
825e13c2760SPrzemyslaw Czarnowski     }
826e13c2760SPrzemyslaw Czarnowski };
827e13c2760SPrzemyslaw Czarnowski 
828e13c2760SPrzemyslaw Czarnowski /**
829e13c2760SPrzemyslaw Czarnowski    @brief EjectMedia action class
830e13c2760SPrzemyslaw Czarnowski  */
831e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionEjectMedia : public Node
832e13c2760SPrzemyslaw Czarnowski {
833e13c2760SPrzemyslaw Czarnowski   public:
834e13c2760SPrzemyslaw Czarnowski     VirtualMediaActionEjectMedia(CrowApp &app) :
835e13c2760SPrzemyslaw Czarnowski         Node(app,
836e13c2760SPrzemyslaw Czarnowski              "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
837e13c2760SPrzemyslaw Czarnowski              "VirtualMedia.EjectMedia",
838e13c2760SPrzemyslaw Czarnowski              std::string(), std::string())
839e13c2760SPrzemyslaw Czarnowski     {
840e13c2760SPrzemyslaw Czarnowski         entityPrivileges = {
841e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
842e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
843e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
844e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
845e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
846e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
847e13c2760SPrzemyslaw Czarnowski     }
848e13c2760SPrzemyslaw Czarnowski 
849e13c2760SPrzemyslaw Czarnowski   private:
850e13c2760SPrzemyslaw Czarnowski     /**
851e13c2760SPrzemyslaw Czarnowski      * @brief Function handles POST method request.
852e13c2760SPrzemyslaw Czarnowski      *
853e13c2760SPrzemyslaw Czarnowski      * Analyzes POST body message before sends Reset request data to dbus.
854e13c2760SPrzemyslaw Czarnowski      */
855e13c2760SPrzemyslaw Czarnowski     void doPost(crow::Response &res, const crow::Request &req,
856e13c2760SPrzemyslaw Czarnowski                 const std::vector<std::string> &params) override
857e13c2760SPrzemyslaw Czarnowski     {
858e13c2760SPrzemyslaw Czarnowski         auto aResp = std::make_shared<AsyncResp>(res);
859e13c2760SPrzemyslaw Czarnowski 
860e13c2760SPrzemyslaw Czarnowski         if (params.size() != 2)
861e13c2760SPrzemyslaw Czarnowski         {
862e13c2760SPrzemyslaw Czarnowski             messages::internalError(res);
863e13c2760SPrzemyslaw Czarnowski             return;
864e13c2760SPrzemyslaw Czarnowski         }
865e13c2760SPrzemyslaw Czarnowski 
866e13c2760SPrzemyslaw Czarnowski         // take resource name from URL
867e13c2760SPrzemyslaw Czarnowski         const std::string &resName = params[1];
868e13c2760SPrzemyslaw Czarnowski 
869e13c2760SPrzemyslaw Czarnowski         if (params[0] != "bmc")
870e13c2760SPrzemyslaw Czarnowski         {
871e13c2760SPrzemyslaw Czarnowski             messages::resourceNotFound(res, "VirtualMedia.Eject", resName);
872e13c2760SPrzemyslaw Czarnowski 
873e13c2760SPrzemyslaw Czarnowski             return;
874e13c2760SPrzemyslaw Czarnowski         }
875e13c2760SPrzemyslaw Czarnowski 
876e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
877e13c2760SPrzemyslaw Czarnowski             [this, aResp{std::move(aResp)}, req,
878e13c2760SPrzemyslaw Czarnowski              resName](const boost::system::error_code ec,
879e13c2760SPrzemyslaw Czarnowski                       const GetObjectType &getObjectType) {
880e13c2760SPrzemyslaw Czarnowski                 if (ec)
881e13c2760SPrzemyslaw Czarnowski                 {
882e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
883e13c2760SPrzemyslaw Czarnowski                                      << ec;
884e13c2760SPrzemyslaw Czarnowski                     messages::internalError(aResp->res);
885e13c2760SPrzemyslaw Czarnowski 
886e13c2760SPrzemyslaw Czarnowski                     return;
887e13c2760SPrzemyslaw Czarnowski                 }
888e13c2760SPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
889e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
890e13c2760SPrzemyslaw Czarnowski 
891e13c2760SPrzemyslaw Czarnowski                 crow::connections::systemBus->async_method_call(
892e13c2760SPrzemyslaw Czarnowski                     [this, resName, service, req, aResp{std::move(aResp)}](
893e13c2760SPrzemyslaw Czarnowski                         const boost::system::error_code ec,
894e13c2760SPrzemyslaw Czarnowski                         ManagedObjectType &subtree) {
895e13c2760SPrzemyslaw Czarnowski                         if (ec)
896e13c2760SPrzemyslaw Czarnowski                         {
897e13c2760SPrzemyslaw Czarnowski                             BMCWEB_LOG_DEBUG << "DBUS response error";
898e13c2760SPrzemyslaw Czarnowski 
899e13c2760SPrzemyslaw Czarnowski                             return;
900e13c2760SPrzemyslaw Czarnowski                         }
901e13c2760SPrzemyslaw Czarnowski 
902e13c2760SPrzemyslaw Czarnowski                         for (const auto &object : subtree)
903e13c2760SPrzemyslaw Czarnowski                         {
904e13c2760SPrzemyslaw Czarnowski                             const std::string &path =
905e13c2760SPrzemyslaw Czarnowski                                 static_cast<const std::string &>(object.first);
906e13c2760SPrzemyslaw Czarnowski 
907e13c2760SPrzemyslaw Czarnowski                             std::size_t lastIndex = path.rfind("/");
908e13c2760SPrzemyslaw Czarnowski                             if (lastIndex == std::string::npos)
909e13c2760SPrzemyslaw Czarnowski                             {
910e13c2760SPrzemyslaw Czarnowski                                 continue;
911e13c2760SPrzemyslaw Czarnowski                             }
912e13c2760SPrzemyslaw Czarnowski 
913e13c2760SPrzemyslaw Czarnowski                             lastIndex += 1;
914e13c2760SPrzemyslaw Czarnowski 
915e13c2760SPrzemyslaw Czarnowski                             if (path.substr(lastIndex) == resName)
916e13c2760SPrzemyslaw Czarnowski                             {
917e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Proxy");
918e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
919e13c2760SPrzemyslaw Czarnowski                                 {
920e13c2760SPrzemyslaw Czarnowski                                     // Proxy mode
921e13c2760SPrzemyslaw Czarnowski                                     doVmAction(std::move(aResp), service,
922e13c2760SPrzemyslaw Czarnowski                                                resName, false);
923e13c2760SPrzemyslaw Czarnowski                                 }
924e13c2760SPrzemyslaw Czarnowski 
925e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Legacy");
926e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
927e13c2760SPrzemyslaw Czarnowski                                 {
928e13c2760SPrzemyslaw Czarnowski                                     // Legacy mode
929e13c2760SPrzemyslaw Czarnowski                                     doVmAction(std::move(aResp), service,
930e13c2760SPrzemyslaw Czarnowski                                                resName, true);
931e13c2760SPrzemyslaw Czarnowski                                 }
932e13c2760SPrzemyslaw Czarnowski 
933e13c2760SPrzemyslaw Czarnowski                                 return;
934e13c2760SPrzemyslaw Czarnowski                             }
935e13c2760SPrzemyslaw Czarnowski                         }
936e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_DEBUG << "Parent item not found";
937e13c2760SPrzemyslaw Czarnowski                         messages::resourceNotFound(aResp->res, "VirtualMedia",
938e13c2760SPrzemyslaw Czarnowski                                                    resName);
939e13c2760SPrzemyslaw Czarnowski                     },
940e13c2760SPrzemyslaw Czarnowski                     service, "/xyz/openbmc_project/VirtualMedia",
941e13c2760SPrzemyslaw Czarnowski                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
942e13c2760SPrzemyslaw Czarnowski             },
943e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
944e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
945e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
946e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
947e13c2760SPrzemyslaw Czarnowski     }
948e13c2760SPrzemyslaw Czarnowski 
949e13c2760SPrzemyslaw Czarnowski     /**
950e13c2760SPrzemyslaw Czarnowski      * @brief Function transceives data with dbus directly.
951e13c2760SPrzemyslaw Czarnowski      *
952e13c2760SPrzemyslaw Czarnowski      * All BMC state properties will be retrieved before sending reset request.
953e13c2760SPrzemyslaw Czarnowski      */
954e13c2760SPrzemyslaw Czarnowski     void doVmAction(std::shared_ptr<AsyncResp> asyncResp,
955e13c2760SPrzemyslaw Czarnowski                     const std::string &service, const std::string &name,
956e13c2760SPrzemyslaw Czarnowski                     bool legacy)
957e13c2760SPrzemyslaw Czarnowski     {
958e13c2760SPrzemyslaw Czarnowski 
959e13c2760SPrzemyslaw Czarnowski         // Legacy mount requires parameter with image
960e13c2760SPrzemyslaw Czarnowski         if (legacy)
961e13c2760SPrzemyslaw Czarnowski         {
962e13c2760SPrzemyslaw Czarnowski             crow::connections::systemBus->async_method_call(
963e13c2760SPrzemyslaw Czarnowski                 [asyncResp](const boost::system::error_code ec) {
964e13c2760SPrzemyslaw Czarnowski                     if (ec)
965e13c2760SPrzemyslaw Czarnowski                     {
966e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
967e13c2760SPrzemyslaw Czarnowski 
968e13c2760SPrzemyslaw Czarnowski                         messages::internalError(asyncResp->res);
969e13c2760SPrzemyslaw Czarnowski                         return;
970e13c2760SPrzemyslaw Czarnowski                     }
971e13c2760SPrzemyslaw Czarnowski                 },
972e13c2760SPrzemyslaw Czarnowski                 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
973e13c2760SPrzemyslaw Czarnowski                 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
974e13c2760SPrzemyslaw Czarnowski         }
975e13c2760SPrzemyslaw Czarnowski         else // proxy
976e13c2760SPrzemyslaw Czarnowski         {
977e13c2760SPrzemyslaw Czarnowski             crow::connections::systemBus->async_method_call(
978e13c2760SPrzemyslaw Czarnowski                 [asyncResp](const boost::system::error_code ec) {
979e13c2760SPrzemyslaw Czarnowski                     if (ec)
980e13c2760SPrzemyslaw Czarnowski                     {
981e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
982e13c2760SPrzemyslaw Czarnowski 
983e13c2760SPrzemyslaw Czarnowski                         messages::internalError(asyncResp->res);
984e13c2760SPrzemyslaw Czarnowski                         return;
985e13c2760SPrzemyslaw Czarnowski                     }
986e13c2760SPrzemyslaw Czarnowski                 },
987e13c2760SPrzemyslaw Czarnowski                 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
988e13c2760SPrzemyslaw Czarnowski                 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
989e13c2760SPrzemyslaw Czarnowski         }
990e13c2760SPrzemyslaw Czarnowski     }
991e13c2760SPrzemyslaw Czarnowski };
992e13c2760SPrzemyslaw Czarnowski 
993107077deSPrzemyslaw Czarnowski class VirtualMediaCollection : public Node
994107077deSPrzemyslaw Czarnowski {
995107077deSPrzemyslaw Czarnowski   public:
996107077deSPrzemyslaw Czarnowski     /*
997107077deSPrzemyslaw Czarnowski      * Default Constructor
998107077deSPrzemyslaw Czarnowski      */
999107077deSPrzemyslaw Czarnowski     VirtualMediaCollection(CrowApp &app) :
1000107077deSPrzemyslaw Czarnowski         Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
1001107077deSPrzemyslaw Czarnowski     {
1002107077deSPrzemyslaw Czarnowski         entityPrivileges = {
1003107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
1004107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
1005107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1006107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1007107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1008107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1009107077deSPrzemyslaw Czarnowski     }
1010107077deSPrzemyslaw Czarnowski 
1011107077deSPrzemyslaw Czarnowski   private:
1012107077deSPrzemyslaw Czarnowski     /**
1013107077deSPrzemyslaw Czarnowski      * Functions triggers appropriate requests on DBus
1014107077deSPrzemyslaw Czarnowski      */
1015107077deSPrzemyslaw Czarnowski     void doGet(crow::Response &res, const crow::Request &req,
1016107077deSPrzemyslaw Czarnowski                const std::vector<std::string> &params) override
1017107077deSPrzemyslaw Czarnowski     {
1018107077deSPrzemyslaw Czarnowski         auto asyncResp = std::make_shared<AsyncResp>(res);
1019107077deSPrzemyslaw Czarnowski 
1020107077deSPrzemyslaw Czarnowski         // Check if there is required param, truly entering this shall be
1021107077deSPrzemyslaw Czarnowski         // impossible
1022107077deSPrzemyslaw Czarnowski         if (params.size() != 1)
1023107077deSPrzemyslaw Czarnowski         {
1024107077deSPrzemyslaw Czarnowski             messages::internalError(res);
1025107077deSPrzemyslaw Czarnowski 
1026107077deSPrzemyslaw Czarnowski             return;
1027107077deSPrzemyslaw Czarnowski         }
1028107077deSPrzemyslaw Czarnowski 
1029107077deSPrzemyslaw Czarnowski         const std::string &name = params[0];
1030107077deSPrzemyslaw Czarnowski 
1031107077deSPrzemyslaw Czarnowski         if (name != "bmc")
1032107077deSPrzemyslaw Czarnowski         {
1033107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
1034107077deSPrzemyslaw Czarnowski 
1035107077deSPrzemyslaw Czarnowski             return;
1036107077deSPrzemyslaw Czarnowski         }
1037107077deSPrzemyslaw Czarnowski 
1038107077deSPrzemyslaw Czarnowski         res.jsonValue["@odata.type"] =
1039107077deSPrzemyslaw Czarnowski             "#VirtualMediaCollection.VirtualMediaCollection";
1040107077deSPrzemyslaw Czarnowski         res.jsonValue["Name"] = "Virtual Media Services";
1041107077deSPrzemyslaw Czarnowski         res.jsonValue["@odata.id"] =
1042107077deSPrzemyslaw Czarnowski             "/redfish/v1/Managers/" + name + "/VirtualMedia/";
1043107077deSPrzemyslaw Czarnowski 
1044107077deSPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
1045107077deSPrzemyslaw Czarnowski             [asyncResp, name](const boost::system::error_code ec,
1046107077deSPrzemyslaw Czarnowski                               const GetObjectType &getObjectType) {
1047107077deSPrzemyslaw Czarnowski                 if (ec)
1048107077deSPrzemyslaw Czarnowski                 {
1049107077deSPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1050107077deSPrzemyslaw Czarnowski                                      << ec;
1051107077deSPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
1052107077deSPrzemyslaw Czarnowski 
1053107077deSPrzemyslaw Czarnowski                     return;
1054107077deSPrzemyslaw Czarnowski                 }
1055107077deSPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
1056107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1057107077deSPrzemyslaw Czarnowski 
1058107077deSPrzemyslaw Czarnowski                 getVmResourceList(asyncResp, service, name);
1059107077deSPrzemyslaw Czarnowski             },
1060107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
1061107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
1062107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
1063107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
1064107077deSPrzemyslaw Czarnowski     }
1065107077deSPrzemyslaw Czarnowski };
1066107077deSPrzemyslaw Czarnowski 
1067107077deSPrzemyslaw Czarnowski class VirtualMedia : public Node
1068107077deSPrzemyslaw Czarnowski {
1069107077deSPrzemyslaw Czarnowski   public:
1070107077deSPrzemyslaw Czarnowski     /*
1071107077deSPrzemyslaw Czarnowski      * Default Constructor
1072107077deSPrzemyslaw Czarnowski      */
1073107077deSPrzemyslaw Czarnowski     VirtualMedia(CrowApp &app) :
1074107077deSPrzemyslaw Czarnowski         Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
1075107077deSPrzemyslaw Czarnowski              std::string(), std::string())
1076107077deSPrzemyslaw Czarnowski     {
1077107077deSPrzemyslaw Czarnowski         entityPrivileges = {
1078107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
1079107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
1080107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1081107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1082107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1083107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1084107077deSPrzemyslaw Czarnowski     }
1085107077deSPrzemyslaw Czarnowski 
1086107077deSPrzemyslaw Czarnowski   private:
1087107077deSPrzemyslaw Czarnowski     /**
1088107077deSPrzemyslaw Czarnowski      * Functions triggers appropriate requests on DBus
1089107077deSPrzemyslaw Czarnowski      */
1090107077deSPrzemyslaw Czarnowski     void doGet(crow::Response &res, const crow::Request &req,
1091107077deSPrzemyslaw Czarnowski                const std::vector<std::string> &params) override
1092107077deSPrzemyslaw Czarnowski     {
1093107077deSPrzemyslaw Czarnowski         // Check if there is required param, truly entering this shall be
1094107077deSPrzemyslaw Czarnowski         // impossible
1095107077deSPrzemyslaw Czarnowski         if (params.size() != 2)
1096107077deSPrzemyslaw Czarnowski         {
1097107077deSPrzemyslaw Czarnowski             messages::internalError(res);
1098107077deSPrzemyslaw Czarnowski 
1099107077deSPrzemyslaw Czarnowski             res.end();
1100107077deSPrzemyslaw Czarnowski             return;
1101107077deSPrzemyslaw Czarnowski         }
1102107077deSPrzemyslaw Czarnowski         const std::string &name = params[0];
1103107077deSPrzemyslaw Czarnowski         const std::string &resName = params[1];
1104107077deSPrzemyslaw Czarnowski 
1105107077deSPrzemyslaw Czarnowski         auto asyncResp = std::make_shared<AsyncResp>(res);
1106107077deSPrzemyslaw Czarnowski 
1107107077deSPrzemyslaw Czarnowski         if (name != "bmc")
1108107077deSPrzemyslaw Czarnowski         {
1109107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1110107077deSPrzemyslaw Czarnowski 
1111107077deSPrzemyslaw Czarnowski             return;
1112107077deSPrzemyslaw Czarnowski         }
1113107077deSPrzemyslaw Czarnowski 
1114107077deSPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
1115107077deSPrzemyslaw Czarnowski             [asyncResp, name, resName](const boost::system::error_code ec,
1116107077deSPrzemyslaw Czarnowski                                        const GetObjectType &getObjectType) {
1117107077deSPrzemyslaw Czarnowski                 if (ec)
1118107077deSPrzemyslaw Czarnowski                 {
1119107077deSPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1120107077deSPrzemyslaw Czarnowski                                      << ec;
1121107077deSPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
1122107077deSPrzemyslaw Czarnowski 
1123107077deSPrzemyslaw Czarnowski                     return;
1124107077deSPrzemyslaw Czarnowski                 }
1125107077deSPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
1126107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1127107077deSPrzemyslaw Czarnowski 
1128107077deSPrzemyslaw Czarnowski                 getVmData(asyncResp, service, name, resName);
1129107077deSPrzemyslaw Czarnowski             },
1130107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
1131107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
1132107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
1133107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
1134107077deSPrzemyslaw Czarnowski     }
1135107077deSPrzemyslaw Czarnowski };
1136107077deSPrzemyslaw Czarnowski 
1137107077deSPrzemyslaw Czarnowski } // namespace redfish
1138