xref: /openbmc/bmcweb/features/redfish/lib/virtual_media.hpp (revision 988fb7b26942a8ddbaa6be4ce34aa4efe4044b43)
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>
19*988fb7b2SAdrian Ambrożewicz #include <boost/process/async_pipe.hpp>
20*988fb7b2SAdrian 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     /**
268e13c2760SPrzemyslaw Czarnowski      * @brief Function handles POST method request.
269e13c2760SPrzemyslaw Czarnowski      *
270e13c2760SPrzemyslaw Czarnowski      * Analyzes POST body message before sends Reset request data to dbus.
271e13c2760SPrzemyslaw Czarnowski      */
272e13c2760SPrzemyslaw Czarnowski     void doPost(crow::Response &res, const crow::Request &req,
273e13c2760SPrzemyslaw Czarnowski                 const std::vector<std::string> &params) override
274e13c2760SPrzemyslaw Czarnowski     {
275e13c2760SPrzemyslaw Czarnowski         auto aResp = std::make_shared<AsyncResp>(res);
276e13c2760SPrzemyslaw Czarnowski 
277e13c2760SPrzemyslaw Czarnowski         if (params.size() != 2)
278e13c2760SPrzemyslaw Czarnowski         {
279e13c2760SPrzemyslaw Czarnowski             messages::internalError(res);
280e13c2760SPrzemyslaw Czarnowski             return;
281e13c2760SPrzemyslaw Czarnowski         }
282e13c2760SPrzemyslaw Czarnowski 
283e13c2760SPrzemyslaw Czarnowski         // take resource name from URL
284e13c2760SPrzemyslaw Czarnowski         const std::string &resName = params[1];
285e13c2760SPrzemyslaw Czarnowski 
286e13c2760SPrzemyslaw Czarnowski         if (params[0] != "bmc")
287e13c2760SPrzemyslaw Czarnowski         {
288e13c2760SPrzemyslaw Czarnowski             messages::resourceNotFound(res, "VirtualMedia.Insert", resName);
289e13c2760SPrzemyslaw Czarnowski 
290e13c2760SPrzemyslaw Czarnowski             return;
291e13c2760SPrzemyslaw Czarnowski         }
292e13c2760SPrzemyslaw Czarnowski 
293e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
294e13c2760SPrzemyslaw Czarnowski             [this, aResp{std::move(aResp)}, req,
295e13c2760SPrzemyslaw Czarnowski              resName](const boost::system::error_code ec,
296e13c2760SPrzemyslaw Czarnowski                       const GetObjectType &getObjectType) {
297e13c2760SPrzemyslaw Czarnowski                 if (ec)
298e13c2760SPrzemyslaw Czarnowski                 {
299e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
300e13c2760SPrzemyslaw Czarnowski                                      << ec;
301e13c2760SPrzemyslaw Czarnowski                     messages::internalError(aResp->res);
302e13c2760SPrzemyslaw Czarnowski 
303e13c2760SPrzemyslaw Czarnowski                     return;
304e13c2760SPrzemyslaw Czarnowski                 }
305e13c2760SPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
306e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
307e13c2760SPrzemyslaw Czarnowski 
308e13c2760SPrzemyslaw Czarnowski                 crow::connections::systemBus->async_method_call(
309e13c2760SPrzemyslaw Czarnowski                     [this, service, resName, req, aResp{std::move(aResp)}](
310e13c2760SPrzemyslaw Czarnowski                         const boost::system::error_code ec,
311e13c2760SPrzemyslaw Czarnowski                         ManagedObjectType &subtree) {
312e13c2760SPrzemyslaw Czarnowski                         if (ec)
313e13c2760SPrzemyslaw Czarnowski                         {
314e13c2760SPrzemyslaw Czarnowski                             BMCWEB_LOG_DEBUG << "DBUS response error";
315e13c2760SPrzemyslaw Czarnowski 
316e13c2760SPrzemyslaw Czarnowski                             return;
317e13c2760SPrzemyslaw Czarnowski                         }
318e13c2760SPrzemyslaw Czarnowski 
319e13c2760SPrzemyslaw Czarnowski                         for (const auto &object : subtree)
320e13c2760SPrzemyslaw Czarnowski                         {
321e13c2760SPrzemyslaw Czarnowski                             const std::string &path =
322e13c2760SPrzemyslaw Czarnowski                                 static_cast<const std::string &>(object.first);
323e13c2760SPrzemyslaw Czarnowski 
324e13c2760SPrzemyslaw Czarnowski                             std::size_t lastIndex = path.rfind("/");
325e13c2760SPrzemyslaw Czarnowski                             if (lastIndex == std::string::npos)
326e13c2760SPrzemyslaw Czarnowski                             {
327e13c2760SPrzemyslaw Czarnowski                                 continue;
328e13c2760SPrzemyslaw Czarnowski                             }
329e13c2760SPrzemyslaw Czarnowski 
330e13c2760SPrzemyslaw Czarnowski                             lastIndex += 1;
331e13c2760SPrzemyslaw Czarnowski 
332e13c2760SPrzemyslaw Czarnowski                             if (path.substr(lastIndex) == resName)
333e13c2760SPrzemyslaw Czarnowski                             {
334e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Proxy");
335e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
336e13c2760SPrzemyslaw Czarnowski                                 {
337e13c2760SPrzemyslaw Czarnowski                                     // Not possible in proxy mode
338e13c2760SPrzemyslaw Czarnowski                                     BMCWEB_LOG_DEBUG << "InsertMedia not "
339e13c2760SPrzemyslaw Czarnowski                                                         "allowed in proxy mode";
340e13c2760SPrzemyslaw Czarnowski                                     messages::resourceNotFound(
341e13c2760SPrzemyslaw Czarnowski                                         aResp->res, "VirtualMedia.InsertMedia",
342e13c2760SPrzemyslaw Czarnowski                                         resName);
343e13c2760SPrzemyslaw Czarnowski 
344e13c2760SPrzemyslaw Czarnowski                                     return;
345e13c2760SPrzemyslaw Czarnowski                                 }
346e13c2760SPrzemyslaw Czarnowski 
347e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Legacy");
348e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
349e13c2760SPrzemyslaw Czarnowski                                 {
350e13c2760SPrzemyslaw Czarnowski                                     // Legacy mode
351e13c2760SPrzemyslaw Czarnowski                                     std::string imageUrl;
352*988fb7b2SAdrian Ambrożewicz                                     std::string userName;
353*988fb7b2SAdrian Ambrożewicz                                     std::string password;
354d6da5bebSAdrian Ambrożewicz                                     bool writeProtected;
355e13c2760SPrzemyslaw Czarnowski 
356e13c2760SPrzemyslaw Czarnowski                                     // Read obligatory paramters (url of image)
357d6da5bebSAdrian Ambrożewicz                                     if (!json_util::readJson(
358d6da5bebSAdrian Ambrożewicz                                             req, aResp->res, "Image", imageUrl,
359*988fb7b2SAdrian Ambrożewicz                                             "WriteProtected", writeProtected,
360*988fb7b2SAdrian Ambrożewicz                                             "UserName", userName, "Password",
361*988fb7b2SAdrian Ambrożewicz                                             password))
362d6da5bebSAdrian Ambrożewicz 
363e13c2760SPrzemyslaw Czarnowski                                     {
364e13c2760SPrzemyslaw Czarnowski                                         BMCWEB_LOG_DEBUG
365e13c2760SPrzemyslaw Czarnowski                                             << "Image is not provided";
366e13c2760SPrzemyslaw Czarnowski                                         return;
367e13c2760SPrzemyslaw Czarnowski                                     }
368e13c2760SPrzemyslaw Czarnowski 
369e13c2760SPrzemyslaw Czarnowski                                     // must not be empty
370e13c2760SPrzemyslaw Czarnowski                                     if (imageUrl.size() == 0)
371e13c2760SPrzemyslaw Czarnowski                                     {
372e13c2760SPrzemyslaw Czarnowski                                         BMCWEB_LOG_ERROR
373e13c2760SPrzemyslaw Czarnowski                                             << "Request action parameter "
374e13c2760SPrzemyslaw Czarnowski                                                "Image is empty.";
375e13c2760SPrzemyslaw Czarnowski                                         messages::propertyValueFormatError(
376e13c2760SPrzemyslaw Czarnowski                                             aResp->res, "<empty>", "Image");
377e13c2760SPrzemyslaw Czarnowski 
378e13c2760SPrzemyslaw Czarnowski                                         return;
379e13c2760SPrzemyslaw Czarnowski                                     }
380e13c2760SPrzemyslaw Czarnowski 
381e13c2760SPrzemyslaw Czarnowski                                     // manager is irrelevant for VirtualMedia
382e13c2760SPrzemyslaw Czarnowski                                     // dbus calls
383d6da5bebSAdrian Ambrożewicz                                     doMountVmLegacy(std::move(aResp), service,
384d6da5bebSAdrian Ambrożewicz                                                     resName, imageUrl,
385*988fb7b2SAdrian Ambrożewicz                                                     !writeProtected,
386*988fb7b2SAdrian Ambrożewicz                                                     std::move(userName),
387*988fb7b2SAdrian Ambrożewicz                                                     std::move(password));
388e13c2760SPrzemyslaw Czarnowski 
389e13c2760SPrzemyslaw Czarnowski                                     return;
390e13c2760SPrzemyslaw Czarnowski                                 }
391e13c2760SPrzemyslaw Czarnowski                             }
392e13c2760SPrzemyslaw Czarnowski                         }
393e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_DEBUG << "Parent item not found";
394e13c2760SPrzemyslaw Czarnowski                         messages::resourceNotFound(aResp->res, "VirtualMedia",
395e13c2760SPrzemyslaw Czarnowski                                                    resName);
396e13c2760SPrzemyslaw Czarnowski                     },
397e13c2760SPrzemyslaw Czarnowski                     service, "/xyz/openbmc_project/VirtualMedia",
398e13c2760SPrzemyslaw Czarnowski                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
399e13c2760SPrzemyslaw Czarnowski             },
400e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
401e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
402e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
403e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
404e13c2760SPrzemyslaw Czarnowski     }
405e13c2760SPrzemyslaw Czarnowski 
406*988fb7b2SAdrian Ambrożewicz     template <typename T> static void secureCleanup(T &value)
407*988fb7b2SAdrian Ambrożewicz     {
408*988fb7b2SAdrian Ambrożewicz         auto raw = const_cast<typename T::value_type *>(value.data());
409*988fb7b2SAdrian Ambrożewicz         explicit_bzero(raw, value.size() * sizeof(*raw));
410*988fb7b2SAdrian Ambrożewicz     }
411*988fb7b2SAdrian Ambrożewicz 
412*988fb7b2SAdrian Ambrożewicz     class Credentials
413*988fb7b2SAdrian Ambrożewicz     {
414*988fb7b2SAdrian Ambrożewicz       public:
415*988fb7b2SAdrian Ambrożewicz         Credentials(std::string &&user, std::string &&password) :
416*988fb7b2SAdrian Ambrożewicz             userBuf(std::move(user)), passBuf(std::move(password))
417*988fb7b2SAdrian Ambrożewicz         {
418*988fb7b2SAdrian Ambrożewicz         }
419*988fb7b2SAdrian Ambrożewicz 
420*988fb7b2SAdrian Ambrożewicz         ~Credentials()
421*988fb7b2SAdrian Ambrożewicz         {
422*988fb7b2SAdrian Ambrożewicz             secureCleanup(userBuf);
423*988fb7b2SAdrian Ambrożewicz             secureCleanup(passBuf);
424*988fb7b2SAdrian Ambrożewicz         }
425*988fb7b2SAdrian Ambrożewicz 
426*988fb7b2SAdrian Ambrożewicz         const std::string &user()
427*988fb7b2SAdrian Ambrożewicz         {
428*988fb7b2SAdrian Ambrożewicz             return userBuf;
429*988fb7b2SAdrian Ambrożewicz         }
430*988fb7b2SAdrian Ambrożewicz 
431*988fb7b2SAdrian Ambrożewicz         const std::string &password()
432*988fb7b2SAdrian Ambrożewicz         {
433*988fb7b2SAdrian Ambrożewicz             return passBuf;
434*988fb7b2SAdrian Ambrożewicz         }
435*988fb7b2SAdrian Ambrożewicz 
436*988fb7b2SAdrian Ambrożewicz       private:
437*988fb7b2SAdrian Ambrożewicz         Credentials() = delete;
438*988fb7b2SAdrian Ambrożewicz         Credentials(const Credentials &) = delete;
439*988fb7b2SAdrian Ambrożewicz         Credentials &operator=(const Credentials &) = delete;
440*988fb7b2SAdrian Ambrożewicz 
441*988fb7b2SAdrian Ambrożewicz         std::string userBuf;
442*988fb7b2SAdrian Ambrożewicz         std::string passBuf;
443*988fb7b2SAdrian Ambrożewicz     };
444*988fb7b2SAdrian Ambrożewicz 
445*988fb7b2SAdrian Ambrożewicz     class CredentialsProvider
446*988fb7b2SAdrian Ambrożewicz     {
447*988fb7b2SAdrian Ambrożewicz       public:
448*988fb7b2SAdrian Ambrożewicz         template <typename T> struct Deleter
449*988fb7b2SAdrian Ambrożewicz         {
450*988fb7b2SAdrian Ambrożewicz             void operator()(T *buff) const
451*988fb7b2SAdrian Ambrożewicz             {
452*988fb7b2SAdrian Ambrożewicz                 if (buff)
453*988fb7b2SAdrian Ambrożewicz                 {
454*988fb7b2SAdrian Ambrożewicz                     secureCleanup(*buff);
455*988fb7b2SAdrian Ambrożewicz                     delete buff;
456*988fb7b2SAdrian Ambrożewicz                 }
457*988fb7b2SAdrian Ambrożewicz             }
458*988fb7b2SAdrian Ambrożewicz         };
459*988fb7b2SAdrian Ambrożewicz 
460*988fb7b2SAdrian Ambrożewicz         using Buffer = std::vector<char>;
461*988fb7b2SAdrian Ambrożewicz         using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
462*988fb7b2SAdrian Ambrożewicz         // Using explicit definition instead of std::function to avoid implicit
463*988fb7b2SAdrian Ambrożewicz         // conversions eg. stack copy instead of reference
464*988fb7b2SAdrian Ambrożewicz         using FormatterFunc = void(const std::string &username,
465*988fb7b2SAdrian Ambrożewicz                                    const std::string &password, Buffer &dest);
466*988fb7b2SAdrian Ambrożewicz 
467*988fb7b2SAdrian Ambrożewicz         CredentialsProvider(std::string &&user, std::string &&password) :
468*988fb7b2SAdrian Ambrożewicz             credentials(std::move(user), std::move(password))
469*988fb7b2SAdrian Ambrożewicz         {
470*988fb7b2SAdrian Ambrożewicz         }
471*988fb7b2SAdrian Ambrożewicz 
472*988fb7b2SAdrian Ambrożewicz         const std::string &user()
473*988fb7b2SAdrian Ambrożewicz         {
474*988fb7b2SAdrian Ambrożewicz             return credentials.user();
475*988fb7b2SAdrian Ambrożewicz         }
476*988fb7b2SAdrian Ambrożewicz 
477*988fb7b2SAdrian Ambrożewicz         const std::string &password()
478*988fb7b2SAdrian Ambrożewicz         {
479*988fb7b2SAdrian Ambrożewicz             return credentials.password();
480*988fb7b2SAdrian Ambrożewicz         }
481*988fb7b2SAdrian Ambrożewicz 
482*988fb7b2SAdrian Ambrożewicz         SecureBuffer pack(const FormatterFunc formatter)
483*988fb7b2SAdrian Ambrożewicz         {
484*988fb7b2SAdrian Ambrożewicz             SecureBuffer packed{new Buffer{}};
485*988fb7b2SAdrian Ambrożewicz             if (formatter)
486*988fb7b2SAdrian Ambrożewicz             {
487*988fb7b2SAdrian Ambrożewicz                 formatter(credentials.user(), credentials.password(), *packed);
488*988fb7b2SAdrian Ambrożewicz             }
489*988fb7b2SAdrian Ambrożewicz 
490*988fb7b2SAdrian Ambrożewicz             return packed;
491*988fb7b2SAdrian Ambrożewicz         }
492*988fb7b2SAdrian Ambrożewicz 
493*988fb7b2SAdrian Ambrożewicz       private:
494*988fb7b2SAdrian Ambrożewicz         Credentials credentials;
495*988fb7b2SAdrian Ambrożewicz     };
496*988fb7b2SAdrian Ambrożewicz 
497*988fb7b2SAdrian Ambrożewicz     // Wrapper for boost::async_pipe ensuring proper pipe cleanup
498*988fb7b2SAdrian Ambrożewicz     template <typename Buffer> class Pipe
499*988fb7b2SAdrian Ambrożewicz     {
500*988fb7b2SAdrian Ambrożewicz       public:
501*988fb7b2SAdrian Ambrożewicz         using unix_fd = sdbusplus::message::unix_fd;
502*988fb7b2SAdrian Ambrożewicz 
503*988fb7b2SAdrian Ambrożewicz         Pipe(boost::asio::io_context &io, Buffer &&buffer) :
504*988fb7b2SAdrian Ambrożewicz             impl(io), buffer{std::move(buffer)}
505*988fb7b2SAdrian Ambrożewicz         {
506*988fb7b2SAdrian Ambrożewicz         }
507*988fb7b2SAdrian Ambrożewicz 
508*988fb7b2SAdrian Ambrożewicz         ~Pipe()
509*988fb7b2SAdrian Ambrożewicz         {
510*988fb7b2SAdrian Ambrożewicz             // Named pipe needs to be explicitly removed
511*988fb7b2SAdrian Ambrożewicz             impl.close();
512*988fb7b2SAdrian Ambrożewicz         }
513*988fb7b2SAdrian Ambrożewicz 
514*988fb7b2SAdrian Ambrożewicz         unix_fd fd()
515*988fb7b2SAdrian Ambrożewicz         {
516*988fb7b2SAdrian Ambrożewicz             return unix_fd{impl.native_source()};
517*988fb7b2SAdrian Ambrożewicz         }
518*988fb7b2SAdrian Ambrożewicz 
519*988fb7b2SAdrian Ambrożewicz         template <typename WriteHandler>
520*988fb7b2SAdrian Ambrożewicz         void async_write(WriteHandler &&handler)
521*988fb7b2SAdrian Ambrożewicz         {
522*988fb7b2SAdrian Ambrożewicz             impl.async_write_some(data(), std::forward<WriteHandler>(handler));
523*988fb7b2SAdrian Ambrożewicz         }
524*988fb7b2SAdrian Ambrożewicz 
525*988fb7b2SAdrian Ambrożewicz       private:
526*988fb7b2SAdrian Ambrożewicz         // Specialization for pointer types
527*988fb7b2SAdrian Ambrożewicz         template <typename B = Buffer>
528*988fb7b2SAdrian Ambrożewicz         typename std::enable_if<boost::has_dereference<B>::value,
529*988fb7b2SAdrian Ambrożewicz                                 boost::asio::const_buffer>::type
530*988fb7b2SAdrian Ambrożewicz             data()
531*988fb7b2SAdrian Ambrożewicz         {
532*988fb7b2SAdrian Ambrożewicz             return boost::asio::buffer(*buffer);
533*988fb7b2SAdrian Ambrożewicz         }
534*988fb7b2SAdrian Ambrożewicz 
535*988fb7b2SAdrian Ambrożewicz         template <typename B = Buffer>
536*988fb7b2SAdrian Ambrożewicz         typename std::enable_if<!boost::has_dereference<B>::value,
537*988fb7b2SAdrian Ambrożewicz                                 boost::asio::const_buffer>::type
538*988fb7b2SAdrian Ambrożewicz             data()
539*988fb7b2SAdrian Ambrożewicz         {
540*988fb7b2SAdrian Ambrożewicz             return boost::asio::buffer(buffer);
541*988fb7b2SAdrian Ambrożewicz         }
542*988fb7b2SAdrian Ambrożewicz 
543*988fb7b2SAdrian Ambrożewicz         const std::string name;
544*988fb7b2SAdrian Ambrożewicz         boost::process::async_pipe impl;
545*988fb7b2SAdrian Ambrożewicz         Buffer buffer;
546*988fb7b2SAdrian Ambrożewicz     };
547*988fb7b2SAdrian Ambrożewicz 
548e13c2760SPrzemyslaw Czarnowski     /**
549e13c2760SPrzemyslaw Czarnowski      * @brief Function transceives data with dbus directly.
550e13c2760SPrzemyslaw Czarnowski      *
551e13c2760SPrzemyslaw Czarnowski      * All BMC state properties will be retrieved before sending reset request.
552e13c2760SPrzemyslaw Czarnowski      */
553d6da5bebSAdrian Ambrożewicz     void doMountVmLegacy(std::shared_ptr<AsyncResp> asyncResp,
554e13c2760SPrzemyslaw Czarnowski                          const std::string &service, const std::string &name,
555*988fb7b2SAdrian Ambrożewicz                          const std::string &imageUrl, const bool rw,
556*988fb7b2SAdrian Ambrożewicz                          std::string &&userName, std::string &&password)
557e13c2760SPrzemyslaw Czarnowski     {
558*988fb7b2SAdrian Ambrożewicz         using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
559*988fb7b2SAdrian Ambrożewicz         constexpr const size_t secretLimit = 1024;
560*988fb7b2SAdrian Ambrożewicz 
561*988fb7b2SAdrian Ambrożewicz         std::shared_ptr<SecurePipe> secretPipe;
562*988fb7b2SAdrian Ambrożewicz         std::variant<int, SecurePipe::unix_fd> unixFd = -1;
563*988fb7b2SAdrian Ambrożewicz 
564*988fb7b2SAdrian Ambrożewicz         if (!userName.empty() || !password.empty())
565*988fb7b2SAdrian Ambrożewicz         {
566*988fb7b2SAdrian Ambrożewicz             // Encapsulate in safe buffer
567*988fb7b2SAdrian Ambrożewicz             CredentialsProvider credentials(std::move(userName),
568*988fb7b2SAdrian Ambrożewicz                                             std::move(password));
569*988fb7b2SAdrian Ambrożewicz 
570*988fb7b2SAdrian Ambrożewicz             // Payload must contain data + NULL delimiters
571*988fb7b2SAdrian Ambrożewicz             if (credentials.user().size() + credentials.password().size() + 2 >
572*988fb7b2SAdrian Ambrożewicz                 secretLimit)
573*988fb7b2SAdrian Ambrożewicz             {
574*988fb7b2SAdrian Ambrożewicz                 BMCWEB_LOG_ERROR << "Credentials too long to handle";
575*988fb7b2SAdrian Ambrożewicz                 messages::unrecognizedRequestBody(asyncResp->res);
576*988fb7b2SAdrian Ambrożewicz                 return;
577*988fb7b2SAdrian Ambrożewicz             }
578*988fb7b2SAdrian Ambrożewicz 
579*988fb7b2SAdrian Ambrożewicz             // Pack secret
580*988fb7b2SAdrian Ambrożewicz             auto secret = credentials.pack([](const auto &user,
581*988fb7b2SAdrian Ambrożewicz                                               const auto &pass, auto &buff) {
582*988fb7b2SAdrian Ambrożewicz                 std::copy(user.begin(), user.end(), std::back_inserter(buff));
583*988fb7b2SAdrian Ambrożewicz                 buff.push_back('\0');
584*988fb7b2SAdrian Ambrożewicz                 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
585*988fb7b2SAdrian Ambrożewicz                 buff.push_back('\0');
586*988fb7b2SAdrian Ambrożewicz             });
587*988fb7b2SAdrian Ambrożewicz 
588*988fb7b2SAdrian Ambrożewicz             // Open pipe
589*988fb7b2SAdrian Ambrożewicz             secretPipe = std::make_shared<SecurePipe>(
590*988fb7b2SAdrian Ambrożewicz                 crow::connections::systemBus->get_io_context(),
591*988fb7b2SAdrian Ambrożewicz                 std::move(secret));
592*988fb7b2SAdrian Ambrożewicz             unixFd = secretPipe->fd();
593*988fb7b2SAdrian Ambrożewicz 
594*988fb7b2SAdrian Ambrożewicz             // Pass secret over pipe
595*988fb7b2SAdrian Ambrożewicz             secretPipe->async_write(
596*988fb7b2SAdrian Ambrożewicz                 [asyncResp](const boost::system::error_code &ec,
597*988fb7b2SAdrian Ambrożewicz                             std::size_t size) {
598*988fb7b2SAdrian Ambrożewicz                     if (ec)
599*988fb7b2SAdrian Ambrożewicz                     {
600*988fb7b2SAdrian Ambrożewicz                         BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
601*988fb7b2SAdrian Ambrożewicz                         messages::internalError(asyncResp->res);
602*988fb7b2SAdrian Ambrożewicz                     }
603*988fb7b2SAdrian Ambrożewicz                 });
604*988fb7b2SAdrian Ambrożewicz         }
605*988fb7b2SAdrian Ambrożewicz 
606e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
607*988fb7b2SAdrian Ambrożewicz             [asyncResp, secretPipe](const boost::system::error_code ec,
608*988fb7b2SAdrian Ambrożewicz                                     bool success) {
609e13c2760SPrzemyslaw Czarnowski                 if (ec)
610e13c2760SPrzemyslaw Czarnowski                 {
611e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
612e13c2760SPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
613d6da5bebSAdrian Ambrożewicz                 }
614d6da5bebSAdrian Ambrożewicz                 else if (!success)
615d6da5bebSAdrian Ambrożewicz                 {
616d6da5bebSAdrian Ambrożewicz                     BMCWEB_LOG_ERROR << "Service responded with error";
617d6da5bebSAdrian Ambrożewicz                     messages::generalError(asyncResp->res);
618e13c2760SPrzemyslaw Czarnowski                 }
619e13c2760SPrzemyslaw Czarnowski             },
620e13c2760SPrzemyslaw Czarnowski             service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
621*988fb7b2SAdrian Ambrożewicz             "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
622*988fb7b2SAdrian Ambrożewicz             unixFd);
623e13c2760SPrzemyslaw Czarnowski     }
624e13c2760SPrzemyslaw Czarnowski };
625e13c2760SPrzemyslaw Czarnowski 
626e13c2760SPrzemyslaw Czarnowski /**
627e13c2760SPrzemyslaw Czarnowski    @brief EjectMedia action class
628e13c2760SPrzemyslaw Czarnowski  */
629e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionEjectMedia : public Node
630e13c2760SPrzemyslaw Czarnowski {
631e13c2760SPrzemyslaw Czarnowski   public:
632e13c2760SPrzemyslaw Czarnowski     VirtualMediaActionEjectMedia(CrowApp &app) :
633e13c2760SPrzemyslaw Czarnowski         Node(app,
634e13c2760SPrzemyslaw Czarnowski              "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
635e13c2760SPrzemyslaw Czarnowski              "VirtualMedia.EjectMedia",
636e13c2760SPrzemyslaw Czarnowski              std::string(), std::string())
637e13c2760SPrzemyslaw Czarnowski     {
638e13c2760SPrzemyslaw Czarnowski         entityPrivileges = {
639e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
640e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
641e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
642e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
643e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
644e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
645e13c2760SPrzemyslaw Czarnowski     }
646e13c2760SPrzemyslaw Czarnowski 
647e13c2760SPrzemyslaw Czarnowski   private:
648e13c2760SPrzemyslaw Czarnowski     /**
649e13c2760SPrzemyslaw Czarnowski      * @brief Function handles POST method request.
650e13c2760SPrzemyslaw Czarnowski      *
651e13c2760SPrzemyslaw Czarnowski      * Analyzes POST body message before sends Reset request data to dbus.
652e13c2760SPrzemyslaw Czarnowski      */
653e13c2760SPrzemyslaw Czarnowski     void doPost(crow::Response &res, const crow::Request &req,
654e13c2760SPrzemyslaw Czarnowski                 const std::vector<std::string> &params) override
655e13c2760SPrzemyslaw Czarnowski     {
656e13c2760SPrzemyslaw Czarnowski         auto aResp = std::make_shared<AsyncResp>(res);
657e13c2760SPrzemyslaw Czarnowski 
658e13c2760SPrzemyslaw Czarnowski         if (params.size() != 2)
659e13c2760SPrzemyslaw Czarnowski         {
660e13c2760SPrzemyslaw Czarnowski             messages::internalError(res);
661e13c2760SPrzemyslaw Czarnowski             return;
662e13c2760SPrzemyslaw Czarnowski         }
663e13c2760SPrzemyslaw Czarnowski 
664e13c2760SPrzemyslaw Czarnowski         // take resource name from URL
665e13c2760SPrzemyslaw Czarnowski         const std::string &resName = params[1];
666e13c2760SPrzemyslaw Czarnowski 
667e13c2760SPrzemyslaw Czarnowski         if (params[0] != "bmc")
668e13c2760SPrzemyslaw Czarnowski         {
669e13c2760SPrzemyslaw Czarnowski             messages::resourceNotFound(res, "VirtualMedia.Eject", resName);
670e13c2760SPrzemyslaw Czarnowski 
671e13c2760SPrzemyslaw Czarnowski             return;
672e13c2760SPrzemyslaw Czarnowski         }
673e13c2760SPrzemyslaw Czarnowski 
674e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
675e13c2760SPrzemyslaw Czarnowski             [this, aResp{std::move(aResp)}, req,
676e13c2760SPrzemyslaw Czarnowski              resName](const boost::system::error_code ec,
677e13c2760SPrzemyslaw Czarnowski                       const GetObjectType &getObjectType) {
678e13c2760SPrzemyslaw Czarnowski                 if (ec)
679e13c2760SPrzemyslaw Czarnowski                 {
680e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
681e13c2760SPrzemyslaw Czarnowski                                      << ec;
682e13c2760SPrzemyslaw Czarnowski                     messages::internalError(aResp->res);
683e13c2760SPrzemyslaw Czarnowski 
684e13c2760SPrzemyslaw Czarnowski                     return;
685e13c2760SPrzemyslaw Czarnowski                 }
686e13c2760SPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
687e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
688e13c2760SPrzemyslaw Czarnowski 
689e13c2760SPrzemyslaw Czarnowski                 crow::connections::systemBus->async_method_call(
690e13c2760SPrzemyslaw Czarnowski                     [this, resName, service, req, aResp{std::move(aResp)}](
691e13c2760SPrzemyslaw Czarnowski                         const boost::system::error_code ec,
692e13c2760SPrzemyslaw Czarnowski                         ManagedObjectType &subtree) {
693e13c2760SPrzemyslaw Czarnowski                         if (ec)
694e13c2760SPrzemyslaw Czarnowski                         {
695e13c2760SPrzemyslaw Czarnowski                             BMCWEB_LOG_DEBUG << "DBUS response error";
696e13c2760SPrzemyslaw Czarnowski 
697e13c2760SPrzemyslaw Czarnowski                             return;
698e13c2760SPrzemyslaw Czarnowski                         }
699e13c2760SPrzemyslaw Czarnowski 
700e13c2760SPrzemyslaw Czarnowski                         for (const auto &object : subtree)
701e13c2760SPrzemyslaw Czarnowski                         {
702e13c2760SPrzemyslaw Czarnowski                             const std::string &path =
703e13c2760SPrzemyslaw Czarnowski                                 static_cast<const std::string &>(object.first);
704e13c2760SPrzemyslaw Czarnowski 
705e13c2760SPrzemyslaw Czarnowski                             std::size_t lastIndex = path.rfind("/");
706e13c2760SPrzemyslaw Czarnowski                             if (lastIndex == std::string::npos)
707e13c2760SPrzemyslaw Czarnowski                             {
708e13c2760SPrzemyslaw Czarnowski                                 continue;
709e13c2760SPrzemyslaw Czarnowski                             }
710e13c2760SPrzemyslaw Czarnowski 
711e13c2760SPrzemyslaw Czarnowski                             lastIndex += 1;
712e13c2760SPrzemyslaw Czarnowski 
713e13c2760SPrzemyslaw Czarnowski                             if (path.substr(lastIndex) == resName)
714e13c2760SPrzemyslaw Czarnowski                             {
715e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Proxy");
716e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
717e13c2760SPrzemyslaw Czarnowski                                 {
718e13c2760SPrzemyslaw Czarnowski                                     // Proxy mode
719e13c2760SPrzemyslaw Czarnowski                                     doVmAction(std::move(aResp), service,
720e13c2760SPrzemyslaw Czarnowski                                                resName, false);
721e13c2760SPrzemyslaw Czarnowski                                 }
722e13c2760SPrzemyslaw Czarnowski 
723e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Legacy");
724e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
725e13c2760SPrzemyslaw Czarnowski                                 {
726e13c2760SPrzemyslaw Czarnowski                                     // Legacy mode
727e13c2760SPrzemyslaw Czarnowski                                     doVmAction(std::move(aResp), service,
728e13c2760SPrzemyslaw Czarnowski                                                resName, true);
729e13c2760SPrzemyslaw Czarnowski                                 }
730e13c2760SPrzemyslaw Czarnowski 
731e13c2760SPrzemyslaw Czarnowski                                 return;
732e13c2760SPrzemyslaw Czarnowski                             }
733e13c2760SPrzemyslaw Czarnowski                         }
734e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_DEBUG << "Parent item not found";
735e13c2760SPrzemyslaw Czarnowski                         messages::resourceNotFound(aResp->res, "VirtualMedia",
736e13c2760SPrzemyslaw Czarnowski                                                    resName);
737e13c2760SPrzemyslaw Czarnowski                     },
738e13c2760SPrzemyslaw Czarnowski                     service, "/xyz/openbmc_project/VirtualMedia",
739e13c2760SPrzemyslaw Czarnowski                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
740e13c2760SPrzemyslaw Czarnowski             },
741e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
742e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
743e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
744e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
745e13c2760SPrzemyslaw Czarnowski     }
746e13c2760SPrzemyslaw Czarnowski 
747e13c2760SPrzemyslaw Czarnowski     /**
748e13c2760SPrzemyslaw Czarnowski      * @brief Function transceives data with dbus directly.
749e13c2760SPrzemyslaw Czarnowski      *
750e13c2760SPrzemyslaw Czarnowski      * All BMC state properties will be retrieved before sending reset request.
751e13c2760SPrzemyslaw Czarnowski      */
752e13c2760SPrzemyslaw Czarnowski     void doVmAction(std::shared_ptr<AsyncResp> asyncResp,
753e13c2760SPrzemyslaw Czarnowski                     const std::string &service, const std::string &name,
754e13c2760SPrzemyslaw Czarnowski                     bool legacy)
755e13c2760SPrzemyslaw Czarnowski     {
756e13c2760SPrzemyslaw Czarnowski 
757e13c2760SPrzemyslaw Czarnowski         // Legacy mount requires parameter with image
758e13c2760SPrzemyslaw Czarnowski         if (legacy)
759e13c2760SPrzemyslaw Czarnowski         {
760e13c2760SPrzemyslaw Czarnowski             crow::connections::systemBus->async_method_call(
761e13c2760SPrzemyslaw Czarnowski                 [asyncResp](const boost::system::error_code ec) {
762e13c2760SPrzemyslaw Czarnowski                     if (ec)
763e13c2760SPrzemyslaw Czarnowski                     {
764e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
765e13c2760SPrzemyslaw Czarnowski 
766e13c2760SPrzemyslaw Czarnowski                         messages::internalError(asyncResp->res);
767e13c2760SPrzemyslaw Czarnowski                         return;
768e13c2760SPrzemyslaw Czarnowski                     }
769e13c2760SPrzemyslaw Czarnowski                 },
770e13c2760SPrzemyslaw Czarnowski                 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
771e13c2760SPrzemyslaw Czarnowski                 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
772e13c2760SPrzemyslaw Czarnowski         }
773e13c2760SPrzemyslaw Czarnowski         else // proxy
774e13c2760SPrzemyslaw Czarnowski         {
775e13c2760SPrzemyslaw Czarnowski             crow::connections::systemBus->async_method_call(
776e13c2760SPrzemyslaw Czarnowski                 [asyncResp](const boost::system::error_code ec) {
777e13c2760SPrzemyslaw Czarnowski                     if (ec)
778e13c2760SPrzemyslaw Czarnowski                     {
779e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
780e13c2760SPrzemyslaw Czarnowski 
781e13c2760SPrzemyslaw Czarnowski                         messages::internalError(asyncResp->res);
782e13c2760SPrzemyslaw Czarnowski                         return;
783e13c2760SPrzemyslaw Czarnowski                     }
784e13c2760SPrzemyslaw Czarnowski                 },
785e13c2760SPrzemyslaw Czarnowski                 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
786e13c2760SPrzemyslaw Czarnowski                 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
787e13c2760SPrzemyslaw Czarnowski         }
788e13c2760SPrzemyslaw Czarnowski     }
789e13c2760SPrzemyslaw Czarnowski };
790e13c2760SPrzemyslaw Czarnowski 
791107077deSPrzemyslaw Czarnowski class VirtualMediaCollection : public Node
792107077deSPrzemyslaw Czarnowski {
793107077deSPrzemyslaw Czarnowski   public:
794107077deSPrzemyslaw Czarnowski     /*
795107077deSPrzemyslaw Czarnowski      * Default Constructor
796107077deSPrzemyslaw Czarnowski      */
797107077deSPrzemyslaw Czarnowski     VirtualMediaCollection(CrowApp &app) :
798107077deSPrzemyslaw Czarnowski         Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
799107077deSPrzemyslaw Czarnowski     {
800107077deSPrzemyslaw Czarnowski         entityPrivileges = {
801107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
802107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
803107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
804107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
805107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
806107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
807107077deSPrzemyslaw Czarnowski     }
808107077deSPrzemyslaw Czarnowski 
809107077deSPrzemyslaw Czarnowski   private:
810107077deSPrzemyslaw Czarnowski     /**
811107077deSPrzemyslaw Czarnowski      * Functions triggers appropriate requests on DBus
812107077deSPrzemyslaw Czarnowski      */
813107077deSPrzemyslaw Czarnowski     void doGet(crow::Response &res, const crow::Request &req,
814107077deSPrzemyslaw Czarnowski                const std::vector<std::string> &params) override
815107077deSPrzemyslaw Czarnowski     {
816107077deSPrzemyslaw Czarnowski         auto asyncResp = std::make_shared<AsyncResp>(res);
817107077deSPrzemyslaw Czarnowski 
818107077deSPrzemyslaw Czarnowski         // Check if there is required param, truly entering this shall be
819107077deSPrzemyslaw Czarnowski         // impossible
820107077deSPrzemyslaw Czarnowski         if (params.size() != 1)
821107077deSPrzemyslaw Czarnowski         {
822107077deSPrzemyslaw Czarnowski             messages::internalError(res);
823107077deSPrzemyslaw Czarnowski 
824107077deSPrzemyslaw Czarnowski             return;
825107077deSPrzemyslaw Czarnowski         }
826107077deSPrzemyslaw Czarnowski 
827107077deSPrzemyslaw Czarnowski         const std::string &name = params[0];
828107077deSPrzemyslaw Czarnowski 
829107077deSPrzemyslaw Czarnowski         if (name != "bmc")
830107077deSPrzemyslaw Czarnowski         {
831107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
832107077deSPrzemyslaw Czarnowski 
833107077deSPrzemyslaw Czarnowski             return;
834107077deSPrzemyslaw Czarnowski         }
835107077deSPrzemyslaw Czarnowski 
836107077deSPrzemyslaw Czarnowski         res.jsonValue["@odata.type"] =
837107077deSPrzemyslaw Czarnowski             "#VirtualMediaCollection.VirtualMediaCollection";
838107077deSPrzemyslaw Czarnowski         res.jsonValue["Name"] = "Virtual Media Services";
839107077deSPrzemyslaw Czarnowski         res.jsonValue["@odata.id"] =
840107077deSPrzemyslaw Czarnowski             "/redfish/v1/Managers/" + name + "/VirtualMedia/";
841107077deSPrzemyslaw Czarnowski 
842107077deSPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
843107077deSPrzemyslaw Czarnowski             [asyncResp, name](const boost::system::error_code ec,
844107077deSPrzemyslaw Czarnowski                               const GetObjectType &getObjectType) {
845107077deSPrzemyslaw Czarnowski                 if (ec)
846107077deSPrzemyslaw Czarnowski                 {
847107077deSPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
848107077deSPrzemyslaw Czarnowski                                      << ec;
849107077deSPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
850107077deSPrzemyslaw Czarnowski 
851107077deSPrzemyslaw Czarnowski                     return;
852107077deSPrzemyslaw Czarnowski                 }
853107077deSPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
854107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
855107077deSPrzemyslaw Czarnowski 
856107077deSPrzemyslaw Czarnowski                 getVmResourceList(asyncResp, service, name);
857107077deSPrzemyslaw Czarnowski             },
858107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
859107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
860107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
861107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
862107077deSPrzemyslaw Czarnowski     }
863107077deSPrzemyslaw Czarnowski };
864107077deSPrzemyslaw Czarnowski 
865107077deSPrzemyslaw Czarnowski class VirtualMedia : public Node
866107077deSPrzemyslaw Czarnowski {
867107077deSPrzemyslaw Czarnowski   public:
868107077deSPrzemyslaw Czarnowski     /*
869107077deSPrzemyslaw Czarnowski      * Default Constructor
870107077deSPrzemyslaw Czarnowski      */
871107077deSPrzemyslaw Czarnowski     VirtualMedia(CrowApp &app) :
872107077deSPrzemyslaw Czarnowski         Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
873107077deSPrzemyslaw Czarnowski              std::string(), std::string())
874107077deSPrzemyslaw Czarnowski     {
875107077deSPrzemyslaw Czarnowski         entityPrivileges = {
876107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
877107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
878107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
879107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
880107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
881107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
882107077deSPrzemyslaw Czarnowski     }
883107077deSPrzemyslaw Czarnowski 
884107077deSPrzemyslaw Czarnowski   private:
885107077deSPrzemyslaw Czarnowski     /**
886107077deSPrzemyslaw Czarnowski      * Functions triggers appropriate requests on DBus
887107077deSPrzemyslaw Czarnowski      */
888107077deSPrzemyslaw Czarnowski     void doGet(crow::Response &res, const crow::Request &req,
889107077deSPrzemyslaw Czarnowski                const std::vector<std::string> &params) override
890107077deSPrzemyslaw Czarnowski     {
891107077deSPrzemyslaw Czarnowski         // Check if there is required param, truly entering this shall be
892107077deSPrzemyslaw Czarnowski         // impossible
893107077deSPrzemyslaw Czarnowski         if (params.size() != 2)
894107077deSPrzemyslaw Czarnowski         {
895107077deSPrzemyslaw Czarnowski             messages::internalError(res);
896107077deSPrzemyslaw Czarnowski 
897107077deSPrzemyslaw Czarnowski             res.end();
898107077deSPrzemyslaw Czarnowski             return;
899107077deSPrzemyslaw Czarnowski         }
900107077deSPrzemyslaw Czarnowski         const std::string &name = params[0];
901107077deSPrzemyslaw Czarnowski         const std::string &resName = params[1];
902107077deSPrzemyslaw Czarnowski 
903107077deSPrzemyslaw Czarnowski         auto asyncResp = std::make_shared<AsyncResp>(res);
904107077deSPrzemyslaw Czarnowski 
905107077deSPrzemyslaw Czarnowski         if (name != "bmc")
906107077deSPrzemyslaw Czarnowski         {
907107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
908107077deSPrzemyslaw Czarnowski 
909107077deSPrzemyslaw Czarnowski             return;
910107077deSPrzemyslaw Czarnowski         }
911107077deSPrzemyslaw Czarnowski 
912107077deSPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
913107077deSPrzemyslaw Czarnowski             [asyncResp, name, resName](const boost::system::error_code ec,
914107077deSPrzemyslaw Czarnowski                                        const GetObjectType &getObjectType) {
915107077deSPrzemyslaw Czarnowski                 if (ec)
916107077deSPrzemyslaw Czarnowski                 {
917107077deSPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
918107077deSPrzemyslaw Czarnowski                                      << ec;
919107077deSPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
920107077deSPrzemyslaw Czarnowski 
921107077deSPrzemyslaw Czarnowski                     return;
922107077deSPrzemyslaw Czarnowski                 }
923107077deSPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
924107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
925107077deSPrzemyslaw Czarnowski 
926107077deSPrzemyslaw Czarnowski                 getVmData(asyncResp, service, name, resName);
927107077deSPrzemyslaw Czarnowski             },
928107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
929107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
930107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
931107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char *, 0>());
932107077deSPrzemyslaw Czarnowski     }
933107077deSPrzemyslaw Czarnowski };
934107077deSPrzemyslaw Czarnowski 
935107077deSPrzemyslaw Czarnowski } // namespace redfish
936