xref: /openbmc/bmcweb/features/redfish/lib/virtual_media.hpp (revision 7e860f1550c8686eec42f7a75bc5f2ef51e756ad)
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 
18*7e860f15SJohn Edward Broadbent #include <app.hpp>
19107077deSPrzemyslaw Czarnowski #include <boost/container/flat_map.hpp>
20988fb7b2SAdrian Ambrożewicz #include <boost/process/async_pipe.hpp>
21988fb7b2SAdrian Ambrożewicz #include <boost/type_traits/has_dereference.hpp>
22107077deSPrzemyslaw Czarnowski #include <node.hpp>
23107077deSPrzemyslaw Czarnowski #include <utils/json_utils.hpp>
24107077deSPrzemyslaw Czarnowski // for GetObjectType and ManagedObjectType
25e13c2760SPrzemyslaw Czarnowski #include <account_service.hpp>
269e319cf0SAnna Platash #include <boost/url/url_view.hpp>
27107077deSPrzemyslaw Czarnowski 
28107077deSPrzemyslaw Czarnowski namespace redfish
29107077deSPrzemyslaw Czarnowski 
30107077deSPrzemyslaw Czarnowski {
319e319cf0SAnna Platash /**
329e319cf0SAnna Platash  * @brief Function extracts transfer protocol name from URI.
339e319cf0SAnna Platash  */
349e319cf0SAnna Platash static std::string getTransferProtocolTypeFromUri(const std::string& imageUri)
359e319cf0SAnna Platash {
369e319cf0SAnna Platash     try
379e319cf0SAnna Platash     {
389e319cf0SAnna Platash         std::string_view scheme = boost::urls::url_view(imageUri).scheme();
399e319cf0SAnna Platash         if (scheme == "smb")
409e319cf0SAnna Platash         {
419e319cf0SAnna Platash             return "CIFS";
429e319cf0SAnna Platash         }
439e319cf0SAnna Platash         else if (scheme == "https")
449e319cf0SAnna Platash         {
459e319cf0SAnna Platash             return "HTTPS";
469e319cf0SAnna Platash         }
479e319cf0SAnna Platash     }
489e319cf0SAnna Platash     catch (std::exception& p)
499e319cf0SAnna Platash     {
509e319cf0SAnna Platash         BMCWEB_LOG_ERROR << p.what();
519e319cf0SAnna Platash     }
529e319cf0SAnna Platash     return "None";
539e319cf0SAnna Platash }
54107077deSPrzemyslaw Czarnowski 
55107077deSPrzemyslaw Czarnowski /**
56107077deSPrzemyslaw Czarnowski  * @brief Read all known properties from VM object interfaces
57107077deSPrzemyslaw Czarnowski  */
588d1b46d7Szhanghch05 static void
598d1b46d7Szhanghch05     vmParseInterfaceObject(const DbusInterfaceType& interface,
608d1b46d7Szhanghch05                            const std::shared_ptr<bmcweb::AsyncResp>& aResp)
61107077deSPrzemyslaw Czarnowski {
62107077deSPrzemyslaw Czarnowski     const auto mountPointIface =
63107077deSPrzemyslaw Czarnowski         interface.find("xyz.openbmc_project.VirtualMedia.MountPoint");
64107077deSPrzemyslaw Czarnowski     if (mountPointIface == interface.cend())
65107077deSPrzemyslaw Czarnowski     {
66107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Interface MountPoint not found";
67107077deSPrzemyslaw Czarnowski         return;
68107077deSPrzemyslaw Czarnowski     }
69107077deSPrzemyslaw Czarnowski 
70107077deSPrzemyslaw Czarnowski     const auto processIface =
71107077deSPrzemyslaw Czarnowski         interface.find("xyz.openbmc_project.VirtualMedia.Process");
72107077deSPrzemyslaw Czarnowski     if (processIface == interface.cend())
73107077deSPrzemyslaw Czarnowski     {
74107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Interface Process not found";
75107077deSPrzemyslaw Czarnowski         return;
76107077deSPrzemyslaw Czarnowski     }
77107077deSPrzemyslaw Czarnowski 
78107077deSPrzemyslaw Czarnowski     const auto endpointIdProperty = mountPointIface->second.find("EndpointId");
79107077deSPrzemyslaw Czarnowski     if (endpointIdProperty == mountPointIface->second.cend())
80107077deSPrzemyslaw Czarnowski     {
81107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Property EndpointId not found";
82107077deSPrzemyslaw Czarnowski         return;
83107077deSPrzemyslaw Czarnowski     }
84107077deSPrzemyslaw Czarnowski 
85107077deSPrzemyslaw Czarnowski     const auto activeProperty = processIface->second.find("Active");
86107077deSPrzemyslaw Czarnowski     if (activeProperty == processIface->second.cend())
87107077deSPrzemyslaw Czarnowski     {
88107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Property Active not found";
89107077deSPrzemyslaw Czarnowski         return;
90107077deSPrzemyslaw Czarnowski     }
91107077deSPrzemyslaw Czarnowski 
92107077deSPrzemyslaw Czarnowski     const bool* activeValue = std::get_if<bool>(&activeProperty->second);
93107077deSPrzemyslaw Czarnowski     if (!activeValue)
94107077deSPrzemyslaw Czarnowski     {
95107077deSPrzemyslaw Czarnowski         BMCWEB_LOG_DEBUG << "Value Active not found";
96107077deSPrzemyslaw Czarnowski         return;
97107077deSPrzemyslaw Czarnowski     }
98107077deSPrzemyslaw Czarnowski 
99107077deSPrzemyslaw Czarnowski     const std::string* endpointIdValue =
100107077deSPrzemyslaw Czarnowski         std::get_if<std::string>(&endpointIdProperty->second);
101107077deSPrzemyslaw Czarnowski     if (endpointIdValue)
102107077deSPrzemyslaw Czarnowski     {
103107077deSPrzemyslaw Czarnowski         if (!endpointIdValue->empty())
104107077deSPrzemyslaw Czarnowski         {
105107077deSPrzemyslaw Czarnowski             // Proxy mode
106d04ba325SPrzemyslaw Czarnowski             aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
107d04ba325SPrzemyslaw Czarnowski                 *endpointIdValue;
108107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["TransferProtocolType"] = "OEM";
109107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["Inserted"] = *activeValue;
110107077deSPrzemyslaw Czarnowski             if (*activeValue == true)
111107077deSPrzemyslaw Czarnowski             {
112107077deSPrzemyslaw Czarnowski                 aResp->res.jsonValue["ConnectedVia"] = "Applet";
113107077deSPrzemyslaw Czarnowski             }
114107077deSPrzemyslaw Czarnowski         }
115107077deSPrzemyslaw Czarnowski         else
116107077deSPrzemyslaw Czarnowski         {
117107077deSPrzemyslaw Czarnowski             // Legacy mode
1189e319cf0SAnna Platash             for (const auto& property : mountPointIface->second)
1199e319cf0SAnna Platash             {
1209e319cf0SAnna Platash                 if (property.first == "ImageURL")
121107077deSPrzemyslaw Czarnowski                 {
122107077deSPrzemyslaw Czarnowski                     const std::string* imageUrlValue =
1239e319cf0SAnna Platash                         std::get_if<std::string>(&property.second);
124107077deSPrzemyslaw Czarnowski                     if (imageUrlValue && !imageUrlValue->empty())
125107077deSPrzemyslaw Czarnowski                     {
126da4784d8SPrzemyslaw Czarnowski                         std::filesystem::path filePath = *imageUrlValue;
127da4784d8SPrzemyslaw Czarnowski                         if (!filePath.has_filename())
128da4784d8SPrzemyslaw Czarnowski                         {
1299e319cf0SAnna Platash                             // this will handle https share, which not
1309e319cf0SAnna Platash                             // necessarily has to have filename given.
131da4784d8SPrzemyslaw Czarnowski                             aResp->res.jsonValue["ImageName"] = "";
132da4784d8SPrzemyslaw Czarnowski                         }
133da4784d8SPrzemyslaw Czarnowski                         else
134da4784d8SPrzemyslaw Czarnowski                         {
1359e319cf0SAnna Platash                             aResp->res.jsonValue["ImageName"] =
1369e319cf0SAnna Platash                                 filePath.filename();
137da4784d8SPrzemyslaw Czarnowski                         }
138da4784d8SPrzemyslaw Czarnowski 
139da4784d8SPrzemyslaw Czarnowski                         aResp->res.jsonValue["Image"] = *imageUrlValue;
140107077deSPrzemyslaw Czarnowski                         aResp->res.jsonValue["Inserted"] = *activeValue;
1419e319cf0SAnna Platash                         aResp->res.jsonValue["TransferProtocolType"] =
1429e319cf0SAnna Platash                             getTransferProtocolTypeFromUri(*imageUrlValue);
1439e319cf0SAnna Platash 
144107077deSPrzemyslaw Czarnowski                         if (*activeValue == true)
145107077deSPrzemyslaw Czarnowski                         {
146107077deSPrzemyslaw Czarnowski                             aResp->res.jsonValue["ConnectedVia"] = "URI";
147107077deSPrzemyslaw Czarnowski                         }
148107077deSPrzemyslaw Czarnowski                     }
149107077deSPrzemyslaw Czarnowski                 }
1509e319cf0SAnna Platash                 else if (property.first == "WriteProtected")
1519e319cf0SAnna Platash                 {
1529e319cf0SAnna Platash                     const bool* writeProtectedValue =
1539e319cf0SAnna Platash                         std::get_if<bool>(&property.second);
1549e319cf0SAnna Platash                     if (writeProtectedValue)
1559e319cf0SAnna Platash                     {
1569e319cf0SAnna Platash                         aResp->res.jsonValue["WriteProtected"] =
1579e319cf0SAnna Platash                             *writeProtectedValue;
1589e319cf0SAnna Platash                     }
1599e319cf0SAnna Platash                 }
1609e319cf0SAnna Platash             }
161107077deSPrzemyslaw Czarnowski         }
162107077deSPrzemyslaw Czarnowski     }
163107077deSPrzemyslaw Czarnowski }
164107077deSPrzemyslaw Czarnowski 
165107077deSPrzemyslaw Czarnowski /**
166107077deSPrzemyslaw Czarnowski  * @brief Fill template for Virtual Media Item.
167107077deSPrzemyslaw Czarnowski  */
168107077deSPrzemyslaw Czarnowski static nlohmann::json vmItemTemplate(const std::string& name,
169107077deSPrzemyslaw Czarnowski                                      const std::string& resName)
170107077deSPrzemyslaw Czarnowski {
171107077deSPrzemyslaw Czarnowski     nlohmann::json item;
172107077deSPrzemyslaw Czarnowski     item["@odata.id"] =
173107077deSPrzemyslaw Czarnowski         "/redfish/v1/Managers/" + name + "/VirtualMedia/" + resName;
174d04ba325SPrzemyslaw Czarnowski     item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
175107077deSPrzemyslaw Czarnowski     item["Name"] = "Virtual Removable Media";
176107077deSPrzemyslaw Czarnowski     item["Id"] = resName;
177107077deSPrzemyslaw Czarnowski     item["WriteProtected"] = true;
178107077deSPrzemyslaw Czarnowski     item["MediaTypes"] = {"CD", "USBStick"};
179107077deSPrzemyslaw Czarnowski     item["TransferMethod"] = "Stream";
180d04ba325SPrzemyslaw Czarnowski     item["Oem"]["OpenBMC"]["@odata.type"] =
181d04ba325SPrzemyslaw Czarnowski         "#OemVirtualMedia.v1_0_0.VirtualMedia";
182107077deSPrzemyslaw Czarnowski 
183107077deSPrzemyslaw Czarnowski     return item;
184107077deSPrzemyslaw Czarnowski }
185107077deSPrzemyslaw Czarnowski 
186107077deSPrzemyslaw Czarnowski /**
187107077deSPrzemyslaw Czarnowski  *  @brief Fills collection data
188107077deSPrzemyslaw Czarnowski  */
1898d1b46d7Szhanghch05 static void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> aResp,
190107077deSPrzemyslaw Czarnowski                               const std::string& service,
191107077deSPrzemyslaw Czarnowski                               const std::string& name)
192107077deSPrzemyslaw Czarnowski {
193107077deSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
194107077deSPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
195107077deSPrzemyslaw Czarnowski         [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
196107077deSPrzemyslaw Czarnowski                                         ManagedObjectType& subtree) {
197107077deSPrzemyslaw Czarnowski             if (ec)
198107077deSPrzemyslaw Czarnowski             {
199107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "DBUS response error";
200107077deSPrzemyslaw Czarnowski                 return;
201107077deSPrzemyslaw Czarnowski             }
202107077deSPrzemyslaw Czarnowski             nlohmann::json& members = aResp->res.jsonValue["Members"];
203107077deSPrzemyslaw Czarnowski             members = nlohmann::json::array();
204107077deSPrzemyslaw Czarnowski 
205107077deSPrzemyslaw Czarnowski             for (const auto& object : subtree)
206107077deSPrzemyslaw Czarnowski             {
207107077deSPrzemyslaw Czarnowski                 nlohmann::json item;
2082dfd18efSEd Tanous                 std::string path = object.first.filename();
2092dfd18efSEd Tanous                 if (path.empty())
210107077deSPrzemyslaw Czarnowski                 {
211107077deSPrzemyslaw Czarnowski                     continue;
212107077deSPrzemyslaw Czarnowski                 }
213107077deSPrzemyslaw Czarnowski 
2142dfd18efSEd Tanous                 item["@odata.id"] =
215788ca507SAppaRao Puli                     "/redfish/v1/Managers/" + name + "/VirtualMedia/" + path;
216107077deSPrzemyslaw Czarnowski 
217107077deSPrzemyslaw Czarnowski                 members.emplace_back(std::move(item));
218107077deSPrzemyslaw Czarnowski             }
219107077deSPrzemyslaw Czarnowski             aResp->res.jsonValue["Members@odata.count"] = members.size();
220107077deSPrzemyslaw Czarnowski         },
221107077deSPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia",
222107077deSPrzemyslaw Czarnowski         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
223107077deSPrzemyslaw Czarnowski }
224107077deSPrzemyslaw Czarnowski 
225107077deSPrzemyslaw Czarnowski /**
226107077deSPrzemyslaw Czarnowski  *  @brief Fills data for specific resource
227107077deSPrzemyslaw Czarnowski  */
2288d1b46d7Szhanghch05 static void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
229107077deSPrzemyslaw Czarnowski                       const std::string& service, const std::string& name,
230107077deSPrzemyslaw Czarnowski                       const std::string& resName)
231107077deSPrzemyslaw Czarnowski {
232107077deSPrzemyslaw Czarnowski     BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
233107077deSPrzemyslaw Czarnowski 
234107077deSPrzemyslaw Czarnowski     crow::connections::systemBus->async_method_call(
235107077deSPrzemyslaw Czarnowski         [resName, name, aResp](const boost::system::error_code ec,
236107077deSPrzemyslaw Czarnowski                                ManagedObjectType& subtree) {
237107077deSPrzemyslaw Czarnowski             if (ec)
238107077deSPrzemyslaw Czarnowski             {
239107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "DBUS response error";
240e13c2760SPrzemyslaw Czarnowski 
241107077deSPrzemyslaw Czarnowski                 return;
242107077deSPrzemyslaw Czarnowski             }
243107077deSPrzemyslaw Czarnowski 
244107077deSPrzemyslaw Czarnowski             for (auto& item : subtree)
245107077deSPrzemyslaw Czarnowski             {
2462dfd18efSEd Tanous                 std::string thispath = item.first.filename();
2472dfd18efSEd Tanous                 if (thispath.empty())
248107077deSPrzemyslaw Czarnowski                 {
249107077deSPrzemyslaw Czarnowski                     continue;
250107077deSPrzemyslaw Czarnowski                 }
251107077deSPrzemyslaw Czarnowski 
2522dfd18efSEd Tanous                 if (thispath != resName)
253107077deSPrzemyslaw Czarnowski                 {
254107077deSPrzemyslaw Czarnowski                     continue;
255107077deSPrzemyslaw Czarnowski                 }
256107077deSPrzemyslaw Czarnowski 
2571a6258dcSPrzemyslaw Czarnowski                 // "Legacy"/"Proxy"
2581a6258dcSPrzemyslaw Czarnowski                 auto mode = item.first.parent_path();
2591a6258dcSPrzemyslaw Czarnowski                 // "VirtualMedia"
2601a6258dcSPrzemyslaw Czarnowski                 auto type = mode.parent_path();
2611a6258dcSPrzemyslaw Czarnowski                 if (mode.filename().empty() || type.filename().empty())
2621a6258dcSPrzemyslaw Czarnowski                 {
2631a6258dcSPrzemyslaw Czarnowski                     continue;
2641a6258dcSPrzemyslaw Czarnowski                 }
2651a6258dcSPrzemyslaw Czarnowski 
2661a6258dcSPrzemyslaw Czarnowski                 if (type.filename() != "VirtualMedia")
2671a6258dcSPrzemyslaw Czarnowski                 {
2681a6258dcSPrzemyslaw Czarnowski                     continue;
2691a6258dcSPrzemyslaw Czarnowski                 }
2701a6258dcSPrzemyslaw Czarnowski 
271107077deSPrzemyslaw Czarnowski                 aResp->res.jsonValue = vmItemTemplate(name, resName);
272107077deSPrzemyslaw Czarnowski 
273e13c2760SPrzemyslaw Czarnowski                 // Check if dbus path is Legacy type
2741a6258dcSPrzemyslaw Czarnowski                 if (mode.filename() == "Legacy")
275e13c2760SPrzemyslaw Czarnowski                 {
276e13c2760SPrzemyslaw Czarnowski                     aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
277e13c2760SPrzemyslaw Czarnowski                                         ["target"] =
278e13c2760SPrzemyslaw Czarnowski                         "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
279e13c2760SPrzemyslaw Czarnowski                         resName + "/Actions/VirtualMedia.InsertMedia";
280e13c2760SPrzemyslaw Czarnowski                 }
281e13c2760SPrzemyslaw Czarnowski 
282107077deSPrzemyslaw Czarnowski                 vmParseInterfaceObject(item.second, aResp);
283107077deSPrzemyslaw Czarnowski 
284e13c2760SPrzemyslaw Czarnowski                 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
285e13c2760SPrzemyslaw Czarnowski                                     ["target"] =
286e13c2760SPrzemyslaw Czarnowski                     "/redfish/v1/Managers/" + name + "/VirtualMedia/" +
287e13c2760SPrzemyslaw Czarnowski                     resName + "/Actions/VirtualMedia.EjectMedia";
288e13c2760SPrzemyslaw Czarnowski 
289107077deSPrzemyslaw Czarnowski                 return;
290107077deSPrzemyslaw Czarnowski             }
291107077deSPrzemyslaw Czarnowski 
292107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(
293d04ba325SPrzemyslaw Czarnowski                 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
294107077deSPrzemyslaw Czarnowski         },
295107077deSPrzemyslaw Czarnowski         service, "/xyz/openbmc_project/VirtualMedia",
296107077deSPrzemyslaw Czarnowski         "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
297107077deSPrzemyslaw Czarnowski }
298107077deSPrzemyslaw Czarnowski 
299e13c2760SPrzemyslaw Czarnowski /**
300e13c2760SPrzemyslaw Czarnowski    @brief InsertMedia action class
301e13c2760SPrzemyslaw Czarnowski  */
302e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionInsertMedia : public Node
303e13c2760SPrzemyslaw Czarnowski {
304e13c2760SPrzemyslaw Czarnowski   public:
30552cc112dSEd Tanous     VirtualMediaActionInsertMedia(App& app) :
306e13c2760SPrzemyslaw Czarnowski         Node(app,
307e13c2760SPrzemyslaw Czarnowski              "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
308e13c2760SPrzemyslaw Czarnowski              "VirtualMedia.InsertMedia",
309e13c2760SPrzemyslaw Czarnowski              std::string(), std::string())
310e13c2760SPrzemyslaw Czarnowski     {
311e13c2760SPrzemyslaw Czarnowski         entityPrivileges = {
312e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
313e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
314e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
315e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
316e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
317e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
318e13c2760SPrzemyslaw Czarnowski     }
319e13c2760SPrzemyslaw Czarnowski 
320e13c2760SPrzemyslaw Czarnowski   private:
321e13c2760SPrzemyslaw Czarnowski     /**
322c6f4e017SAgata Olender      * @brief Transfer protocols supported for InsertMedia action.
323c6f4e017SAgata Olender      *
324c6f4e017SAgata Olender      */
325c6f4e017SAgata Olender     enum class TransferProtocol
326c6f4e017SAgata Olender     {
327c6f4e017SAgata Olender         https,
328c6f4e017SAgata Olender         smb,
329c6f4e017SAgata Olender         invalid
330c6f4e017SAgata Olender     };
331c6f4e017SAgata Olender 
332c6f4e017SAgata Olender     /**
333c6f4e017SAgata Olender      * @brief Function extracts transfer protocol type from URI.
334c6f4e017SAgata Olender      *
335c6f4e017SAgata Olender      */
336c6f4e017SAgata Olender     std::optional<TransferProtocol>
337c6f4e017SAgata Olender         getTransferProtocolFromUri(const std::string& imageUri)
338c6f4e017SAgata Olender     {
3399e319cf0SAnna Platash         try
3409e319cf0SAnna Platash         {
3419e319cf0SAnna Platash             std::string_view scheme = boost::urls::url_view(imageUri).scheme();
3429e319cf0SAnna Platash             if (scheme == "smb")
343c6f4e017SAgata Olender             {
344c6f4e017SAgata Olender                 return TransferProtocol::smb;
345c6f4e017SAgata Olender             }
34681ce609eSEd Tanous             if (scheme == "https")
347c6f4e017SAgata Olender             {
348c6f4e017SAgata Olender                 return TransferProtocol::https;
349c6f4e017SAgata Olender             }
3509e319cf0SAnna Platash             else if (!scheme.empty())
351c6f4e017SAgata Olender             {
352c6f4e017SAgata Olender                 return TransferProtocol::invalid;
353c6f4e017SAgata Olender             }
354c6f4e017SAgata Olender         }
3559e319cf0SAnna Platash         catch (std::exception& p)
3569e319cf0SAnna Platash         {
3579e319cf0SAnna Platash             BMCWEB_LOG_ERROR << p.what();
3589e319cf0SAnna Platash         }
3599e319cf0SAnna Platash 
3609e319cf0SAnna Platash         return {};
361c6f4e017SAgata Olender     }
362c6f4e017SAgata Olender 
363c6f4e017SAgata Olender     /**
364c6f4e017SAgata Olender      * @brief Function convert transfer protocol from string param.
365c6f4e017SAgata Olender      *
366c6f4e017SAgata Olender      */
367c6f4e017SAgata Olender     std::optional<TransferProtocol> getTransferProtocolFromParam(
368c6f4e017SAgata Olender         const std::optional<std::string>& transferProtocolType)
369c6f4e017SAgata Olender     {
370c6f4e017SAgata Olender         if (transferProtocolType == std::nullopt)
371c6f4e017SAgata Olender         {
372c6f4e017SAgata Olender             return {};
373c6f4e017SAgata Olender         }
374c6f4e017SAgata Olender 
375c6f4e017SAgata Olender         if (*transferProtocolType == "CIFS")
376c6f4e017SAgata Olender         {
377c6f4e017SAgata Olender             return TransferProtocol::smb;
378c6f4e017SAgata Olender         }
379c6f4e017SAgata Olender 
380c6f4e017SAgata Olender         if (*transferProtocolType == "HTTPS")
381c6f4e017SAgata Olender         {
382c6f4e017SAgata Olender             return TransferProtocol::https;
383c6f4e017SAgata Olender         }
384c6f4e017SAgata Olender 
385c6f4e017SAgata Olender         return TransferProtocol::invalid;
386c6f4e017SAgata Olender     }
387c6f4e017SAgata Olender 
388c6f4e017SAgata Olender     /**
389c6f4e017SAgata Olender      * @brief Function extends URI with transfer protocol type.
390c6f4e017SAgata Olender      *
391c6f4e017SAgata Olender      */
39281ce609eSEd Tanous     std::string
393c6f4e017SAgata Olender         getUriWithTransferProtocol(const std::string& imageUri,
394c6f4e017SAgata Olender                                    const TransferProtocol& transferProtocol)
395c6f4e017SAgata Olender     {
396c6f4e017SAgata Olender         if (transferProtocol == TransferProtocol::smb)
397c6f4e017SAgata Olender         {
398c6f4e017SAgata Olender             return "smb://" + imageUri;
399c6f4e017SAgata Olender         }
400c6f4e017SAgata Olender 
401c6f4e017SAgata Olender         if (transferProtocol == TransferProtocol::https)
402c6f4e017SAgata Olender         {
403c6f4e017SAgata Olender             return "https://" + imageUri;
404c6f4e017SAgata Olender         }
405c6f4e017SAgata Olender 
406c6f4e017SAgata Olender         return imageUri;
407c6f4e017SAgata Olender     }
408c6f4e017SAgata Olender 
409c6f4e017SAgata Olender     /**
410c6f4e017SAgata Olender      * @brief Function validate parameters of insert media request.
411c6f4e017SAgata Olender      *
412c6f4e017SAgata Olender      */
4138d1b46d7Szhanghch05     bool validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4148d1b46d7Szhanghch05                         std::string& imageUrl,
415c6f4e017SAgata Olender                         const std::optional<bool>& inserted,
416c6f4e017SAgata Olender                         const std::optional<std::string>& transferMethod,
417c6f4e017SAgata Olender                         const std::optional<std::string>& transferProtocolType)
418c6f4e017SAgata Olender     {
419c6f4e017SAgata Olender         BMCWEB_LOG_DEBUG << "Validation started";
420c6f4e017SAgata Olender         // required param imageUrl must not be empty
421c6f4e017SAgata Olender         if (imageUrl.empty())
422c6f4e017SAgata Olender         {
423c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
424c6f4e017SAgata Olender 
4258d1b46d7Szhanghch05             messages::propertyValueFormatError(asyncResp->res, "<empty>",
4268d1b46d7Szhanghch05                                                "Image");
427c6f4e017SAgata Olender 
428c6f4e017SAgata Olender             return false;
429c6f4e017SAgata Olender         }
430c6f4e017SAgata Olender 
431c6f4e017SAgata Olender         // optional param inserted must be true
432c6f4e017SAgata Olender         if ((inserted != std::nullopt) && (*inserted != true))
433c6f4e017SAgata Olender         {
434c6f4e017SAgata Olender             BMCWEB_LOG_ERROR
435c6f4e017SAgata Olender                 << "Request action optional parameter Inserted must be true.";
436c6f4e017SAgata Olender 
4378d1b46d7Szhanghch05             messages::actionParameterNotSupported(asyncResp->res, "Inserted",
438c6f4e017SAgata Olender                                                   "InsertMedia");
439c6f4e017SAgata Olender 
440c6f4e017SAgata Olender             return false;
441c6f4e017SAgata Olender         }
442c6f4e017SAgata Olender 
443c6f4e017SAgata Olender         // optional param transferMethod must be stream
444c6f4e017SAgata Olender         if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
445c6f4e017SAgata Olender         {
446c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action optional parameter "
447c6f4e017SAgata Olender                                 "TransferMethod must be Stream.";
448c6f4e017SAgata Olender 
4498d1b46d7Szhanghch05             messages::actionParameterNotSupported(
4508d1b46d7Szhanghch05                 asyncResp->res, "TransferMethod", "InsertMedia");
451c6f4e017SAgata Olender 
452c6f4e017SAgata Olender             return false;
453c6f4e017SAgata Olender         }
454c6f4e017SAgata Olender 
455c6f4e017SAgata Olender         std::optional<TransferProtocol> uriTransferProtocolType =
456c6f4e017SAgata Olender             getTransferProtocolFromUri(imageUrl);
457c6f4e017SAgata Olender 
458c6f4e017SAgata Olender         std::optional<TransferProtocol> paramTransferProtocolType =
459c6f4e017SAgata Olender             getTransferProtocolFromParam(transferProtocolType);
460c6f4e017SAgata Olender 
461c6f4e017SAgata Olender         // ImageUrl does not contain valid protocol type
462c6f4e017SAgata Olender         if (*uriTransferProtocolType == TransferProtocol::invalid)
463c6f4e017SAgata Olender         {
464c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
465c6f4e017SAgata Olender                                 "contain specified protocol type from list: "
466c6f4e017SAgata Olender                                 "(smb, https).";
467c6f4e017SAgata Olender 
4688d1b46d7Szhanghch05             messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
469c6f4e017SAgata Olender 
470c6f4e017SAgata Olender             return false;
471c6f4e017SAgata Olender         }
472c6f4e017SAgata Olender 
473c6f4e017SAgata Olender         // transferProtocolType should contain value from list
474c6f4e017SAgata Olender         if (*paramTransferProtocolType == TransferProtocol::invalid)
475c6f4e017SAgata Olender         {
476c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
477c6f4e017SAgata Olender                                 "must be provided with value from list: "
478c6f4e017SAgata Olender                                 "(CIFS, HTTPS).";
479c6f4e017SAgata Olender 
4808d1b46d7Szhanghch05             messages::propertyValueNotInList(
4818d1b46d7Szhanghch05                 asyncResp->res, *transferProtocolType, "TransferProtocolType");
482c6f4e017SAgata Olender             return false;
483c6f4e017SAgata Olender         }
484c6f4e017SAgata Olender 
485c6f4e017SAgata Olender         // valid transfer protocol not provided either with URI nor param
486c6f4e017SAgata Olender         if ((uriTransferProtocolType == std::nullopt) &&
487c6f4e017SAgata Olender             (paramTransferProtocolType == std::nullopt))
488c6f4e017SAgata Olender         {
489c6f4e017SAgata Olender             BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
490c6f4e017SAgata Olender                                 "contain specified protocol type or param "
491c6f4e017SAgata Olender                                 "TransferProtocolType must be provided.";
492c6f4e017SAgata Olender 
4938d1b46d7Szhanghch05             messages::resourceAtUriInUnknownFormat(asyncResp->res, imageUrl);
494c6f4e017SAgata Olender 
495c6f4e017SAgata Olender             return false;
496c6f4e017SAgata Olender         }
497c6f4e017SAgata Olender 
498c6f4e017SAgata Olender         // valid transfer protocol provided both with URI and param
499c6f4e017SAgata Olender         if ((paramTransferProtocolType != std::nullopt) &&
500c6f4e017SAgata Olender             (uriTransferProtocolType != std::nullopt))
501c6f4e017SAgata Olender         {
502c6f4e017SAgata Olender             // check if protocol is the same for URI and param
503c6f4e017SAgata Olender             if (*paramTransferProtocolType != *uriTransferProtocolType)
504c6f4e017SAgata Olender             {
505c6f4e017SAgata Olender                 BMCWEB_LOG_ERROR << "Request action parameter "
506c6f4e017SAgata Olender                                     "TransferProtocolType must  contain the "
507c6f4e017SAgata Olender                                     "same protocol type as protocol type "
508c6f4e017SAgata Olender                                     "provided with param imageUrl.";
509c6f4e017SAgata Olender 
510c6f4e017SAgata Olender                 messages::actionParameterValueTypeError(
5118d1b46d7Szhanghch05                     asyncResp->res, *transferProtocolType,
5128d1b46d7Szhanghch05                     "TransferProtocolType", "InsertMedia");
513c6f4e017SAgata Olender 
514c6f4e017SAgata Olender                 return false;
515c6f4e017SAgata Olender             }
516c6f4e017SAgata Olender         }
517c6f4e017SAgata Olender 
518c6f4e017SAgata Olender         // validation passed
519c6f4e017SAgata Olender         // add protocol to URI if needed
520c6f4e017SAgata Olender         if (uriTransferProtocolType == std::nullopt)
521c6f4e017SAgata Olender         {
522c6f4e017SAgata Olender             imageUrl = getUriWithTransferProtocol(imageUrl,
523c6f4e017SAgata Olender                                                   *paramTransferProtocolType);
524c6f4e017SAgata Olender         }
525c6f4e017SAgata Olender 
526c6f4e017SAgata Olender         return true;
527c6f4e017SAgata Olender     }
528c6f4e017SAgata Olender 
529c6f4e017SAgata Olender     /**
530e13c2760SPrzemyslaw Czarnowski      * @brief Function handles POST method request.
531e13c2760SPrzemyslaw Czarnowski      *
532e13c2760SPrzemyslaw Czarnowski      * Analyzes POST body message before sends Reset request data to dbus.
533e13c2760SPrzemyslaw Czarnowski      */
5348d1b46d7Szhanghch05     void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5358d1b46d7Szhanghch05                 const crow::Request& req,
536e13c2760SPrzemyslaw Czarnowski                 const std::vector<std::string>& params) override
537e13c2760SPrzemyslaw Czarnowski     {
538e13c2760SPrzemyslaw Czarnowski         if (params.size() != 2)
539e13c2760SPrzemyslaw Czarnowski         {
5408d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
541e13c2760SPrzemyslaw Czarnowski             return;
542e13c2760SPrzemyslaw Czarnowski         }
543e13c2760SPrzemyslaw Czarnowski 
544e13c2760SPrzemyslaw Czarnowski         // take resource name from URL
545e13c2760SPrzemyslaw Czarnowski         const std::string& resName = params[1];
546e13c2760SPrzemyslaw Czarnowski 
547e13c2760SPrzemyslaw Czarnowski         if (params[0] != "bmc")
548e13c2760SPrzemyslaw Czarnowski         {
5498d1b46d7Szhanghch05             messages::resourceNotFound(asyncResp->res, "VirtualMedia.Insert",
5508d1b46d7Szhanghch05                                        resName);
551e13c2760SPrzemyslaw Czarnowski 
552e13c2760SPrzemyslaw Czarnowski             return;
553e13c2760SPrzemyslaw Czarnowski         }
554e13c2760SPrzemyslaw Czarnowski 
555e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
5568d1b46d7Szhanghch05             [this, asyncResp, req,
557e13c2760SPrzemyslaw Czarnowski              resName](const boost::system::error_code ec,
558e13c2760SPrzemyslaw Czarnowski                       const GetObjectType& getObjectType) {
559e13c2760SPrzemyslaw Czarnowski                 if (ec)
560e13c2760SPrzemyslaw Czarnowski                 {
561e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
562e13c2760SPrzemyslaw Czarnowski                                      << ec;
5638d1b46d7Szhanghch05                     messages::internalError(asyncResp->res);
564e13c2760SPrzemyslaw Czarnowski 
565e13c2760SPrzemyslaw Czarnowski                     return;
566e13c2760SPrzemyslaw Czarnowski                 }
567e13c2760SPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
568e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
569e13c2760SPrzemyslaw Czarnowski 
570e13c2760SPrzemyslaw Czarnowski                 crow::connections::systemBus->async_method_call(
57181ce609eSEd Tanous                     [this, service, resName, req,
5728d1b46d7Szhanghch05                      asyncResp](const boost::system::error_code ec,
573e13c2760SPrzemyslaw Czarnowski                                 ManagedObjectType& subtree) {
574e13c2760SPrzemyslaw Czarnowski                         if (ec)
575e13c2760SPrzemyslaw Czarnowski                         {
576e13c2760SPrzemyslaw Czarnowski                             BMCWEB_LOG_DEBUG << "DBUS response error";
577e13c2760SPrzemyslaw Czarnowski 
578e13c2760SPrzemyslaw Czarnowski                             return;
579e13c2760SPrzemyslaw Czarnowski                         }
580e13c2760SPrzemyslaw Czarnowski 
581e13c2760SPrzemyslaw Czarnowski                         for (const auto& object : subtree)
582e13c2760SPrzemyslaw Czarnowski                         {
583e13c2760SPrzemyslaw Czarnowski                             const std::string& path =
584e13c2760SPrzemyslaw Czarnowski                                 static_cast<const std::string&>(object.first);
585e13c2760SPrzemyslaw Czarnowski 
586f23b7296SEd Tanous                             std::size_t lastIndex = path.rfind('/');
587e13c2760SPrzemyslaw Czarnowski                             if (lastIndex == std::string::npos)
588e13c2760SPrzemyslaw Czarnowski                             {
589e13c2760SPrzemyslaw Czarnowski                                 continue;
590e13c2760SPrzemyslaw Czarnowski                             }
591e13c2760SPrzemyslaw Czarnowski 
592e13c2760SPrzemyslaw Czarnowski                             lastIndex += 1;
593e13c2760SPrzemyslaw Czarnowski 
594e13c2760SPrzemyslaw Czarnowski                             if (path.substr(lastIndex) == resName)
595e13c2760SPrzemyslaw Czarnowski                             {
596e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Proxy");
597e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
598e13c2760SPrzemyslaw Czarnowski                                 {
599e13c2760SPrzemyslaw Czarnowski                                     // Not possible in proxy mode
600e13c2760SPrzemyslaw Czarnowski                                     BMCWEB_LOG_DEBUG << "InsertMedia not "
601e13c2760SPrzemyslaw Czarnowski                                                         "allowed in proxy mode";
602e13c2760SPrzemyslaw Czarnowski                                     messages::resourceNotFound(
6038d1b46d7Szhanghch05                                         asyncResp->res,
6048d1b46d7Szhanghch05                                         "VirtualMedia.InsertMedia", resName);
605e13c2760SPrzemyslaw Czarnowski 
606e13c2760SPrzemyslaw Czarnowski                                     return;
607e13c2760SPrzemyslaw Czarnowski                                 }
608e13c2760SPrzemyslaw Czarnowski 
609e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Legacy");
610c6f4e017SAgata Olender                                 if (lastIndex == std::string::npos)
611e13c2760SPrzemyslaw Czarnowski                                 {
612c6f4e017SAgata Olender                                     continue;
613c6f4e017SAgata Olender                                 }
614c6f4e017SAgata Olender 
615e13c2760SPrzemyslaw Czarnowski                                 // Legacy mode
616e13c2760SPrzemyslaw Czarnowski                                 std::string imageUrl;
617c6f4e017SAgata Olender                                 std::optional<std::string> userName;
618c6f4e017SAgata Olender                                 std::optional<std::string> password;
619c6f4e017SAgata Olender                                 std::optional<std::string> transferMethod;
620c6f4e017SAgata Olender                                 std::optional<std::string> transferProtocolType;
621c6f4e017SAgata Olender                                 std::optional<bool> writeProtected = true;
622c6f4e017SAgata Olender                                 std::optional<bool> inserted;
623e13c2760SPrzemyslaw Czarnowski 
6244e0453b1SGunnar Mills                                 // Read obligatory parameters (url of image)
625d6da5bebSAdrian Ambrożewicz                                 if (!json_util::readJson(
6268d1b46d7Szhanghch05                                         req, asyncResp->res, "Image", imageUrl,
627988fb7b2SAdrian Ambrożewicz                                         "WriteProtected", writeProtected,
628988fb7b2SAdrian Ambrożewicz                                         "UserName", userName, "Password",
629c6f4e017SAgata Olender                                         password, "Inserted", inserted,
630c6f4e017SAgata Olender                                         "TransferMethod", transferMethod,
631c6f4e017SAgata Olender                                         "TransferProtocolType",
632c6f4e017SAgata Olender                                         transferProtocolType))
633e13c2760SPrzemyslaw Czarnowski                                 {
634c6f4e017SAgata Olender                                     BMCWEB_LOG_DEBUG << "Image is not provided";
635e13c2760SPrzemyslaw Czarnowski                                     return;
636e13c2760SPrzemyslaw Czarnowski                                 }
637e13c2760SPrzemyslaw Czarnowski 
638c6f4e017SAgata Olender                                 bool paramsValid = validateParams(
6398d1b46d7Szhanghch05                                     asyncResp->res, imageUrl, inserted,
640c6f4e017SAgata Olender                                     transferMethod, transferProtocolType);
641c6f4e017SAgata Olender 
642c6f4e017SAgata Olender                                 if (paramsValid == false)
643e13c2760SPrzemyslaw Czarnowski                                 {
644e13c2760SPrzemyslaw Czarnowski                                     return;
645e13c2760SPrzemyslaw Czarnowski                                 }
646e13c2760SPrzemyslaw Czarnowski 
647c6f4e017SAgata Olender                                 // manager is irrelevant for VirtualMedia dbus
648c6f4e017SAgata Olender                                 // calls
6498d1b46d7Szhanghch05                                 doMountVmLegacy(asyncResp, service, resName,
650c6f4e017SAgata Olender                                                 imageUrl, !(*writeProtected),
65181ce609eSEd Tanous                                                 std::move(*userName),
65281ce609eSEd Tanous                                                 std::move(*password));
653e13c2760SPrzemyslaw Czarnowski 
654e13c2760SPrzemyslaw Czarnowski                                 return;
655e13c2760SPrzemyslaw Czarnowski                             }
656e13c2760SPrzemyslaw Czarnowski                         }
657e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_DEBUG << "Parent item not found";
6588d1b46d7Szhanghch05                         messages::resourceNotFound(asyncResp->res,
6598d1b46d7Szhanghch05                                                    "VirtualMedia", resName);
660e13c2760SPrzemyslaw Czarnowski                     },
661e13c2760SPrzemyslaw Czarnowski                     service, "/xyz/openbmc_project/VirtualMedia",
662e13c2760SPrzemyslaw Czarnowski                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
663e13c2760SPrzemyslaw Czarnowski             },
664e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
665e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
666e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
667e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
668e13c2760SPrzemyslaw Czarnowski     }
669e13c2760SPrzemyslaw Czarnowski 
6701214b7e7SGunnar Mills     template <typename T>
6711214b7e7SGunnar Mills     static void secureCleanup(T& value)
672988fb7b2SAdrian Ambrożewicz     {
673988fb7b2SAdrian Ambrożewicz         auto raw = const_cast<typename T::value_type*>(value.data());
674988fb7b2SAdrian Ambrożewicz         explicit_bzero(raw, value.size() * sizeof(*raw));
675988fb7b2SAdrian Ambrożewicz     }
676988fb7b2SAdrian Ambrożewicz 
677988fb7b2SAdrian Ambrożewicz     class Credentials
678988fb7b2SAdrian Ambrożewicz     {
679988fb7b2SAdrian Ambrożewicz       public:
680988fb7b2SAdrian Ambrożewicz         Credentials(std::string&& user, std::string&& password) :
681988fb7b2SAdrian Ambrożewicz             userBuf(std::move(user)), passBuf(std::move(password))
6821214b7e7SGunnar Mills         {}
683988fb7b2SAdrian Ambrożewicz 
684988fb7b2SAdrian Ambrożewicz         ~Credentials()
685988fb7b2SAdrian Ambrożewicz         {
686988fb7b2SAdrian Ambrożewicz             secureCleanup(userBuf);
687988fb7b2SAdrian Ambrożewicz             secureCleanup(passBuf);
688988fb7b2SAdrian Ambrożewicz         }
689988fb7b2SAdrian Ambrożewicz 
690988fb7b2SAdrian Ambrożewicz         const std::string& user()
691988fb7b2SAdrian Ambrożewicz         {
692988fb7b2SAdrian Ambrożewicz             return userBuf;
693988fb7b2SAdrian Ambrożewicz         }
694988fb7b2SAdrian Ambrożewicz 
695988fb7b2SAdrian Ambrożewicz         const std::string& password()
696988fb7b2SAdrian Ambrożewicz         {
697988fb7b2SAdrian Ambrożewicz             return passBuf;
698988fb7b2SAdrian Ambrożewicz         }
699988fb7b2SAdrian Ambrożewicz 
700988fb7b2SAdrian Ambrożewicz       private:
701988fb7b2SAdrian Ambrożewicz         Credentials() = delete;
702988fb7b2SAdrian Ambrożewicz         Credentials(const Credentials&) = delete;
703988fb7b2SAdrian Ambrożewicz         Credentials& operator=(const Credentials&) = delete;
704988fb7b2SAdrian Ambrożewicz 
705988fb7b2SAdrian Ambrożewicz         std::string userBuf;
706988fb7b2SAdrian Ambrożewicz         std::string passBuf;
707988fb7b2SAdrian Ambrożewicz     };
708988fb7b2SAdrian Ambrożewicz 
709988fb7b2SAdrian Ambrożewicz     class CredentialsProvider
710988fb7b2SAdrian Ambrożewicz     {
711988fb7b2SAdrian Ambrożewicz       public:
7121214b7e7SGunnar Mills         template <typename T>
7131214b7e7SGunnar Mills         struct Deleter
714988fb7b2SAdrian Ambrożewicz         {
715988fb7b2SAdrian Ambrożewicz             void operator()(T* buff) const
716988fb7b2SAdrian Ambrożewicz             {
717988fb7b2SAdrian Ambrożewicz                 if (buff)
718988fb7b2SAdrian Ambrożewicz                 {
719988fb7b2SAdrian Ambrożewicz                     secureCleanup(*buff);
720988fb7b2SAdrian Ambrożewicz                     delete buff;
721988fb7b2SAdrian Ambrożewicz                 }
722988fb7b2SAdrian Ambrożewicz             }
723988fb7b2SAdrian Ambrożewicz         };
724988fb7b2SAdrian Ambrożewicz 
725988fb7b2SAdrian Ambrożewicz         using Buffer = std::vector<char>;
726988fb7b2SAdrian Ambrożewicz         using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
727988fb7b2SAdrian Ambrożewicz         // Using explicit definition instead of std::function to avoid implicit
728988fb7b2SAdrian Ambrożewicz         // conversions eg. stack copy instead of reference
729988fb7b2SAdrian Ambrożewicz         using FormatterFunc = void(const std::string& username,
730988fb7b2SAdrian Ambrożewicz                                    const std::string& password, Buffer& dest);
731988fb7b2SAdrian Ambrożewicz 
732988fb7b2SAdrian Ambrożewicz         CredentialsProvider(std::string&& user, std::string&& password) :
733988fb7b2SAdrian Ambrożewicz             credentials(std::move(user), std::move(password))
7341214b7e7SGunnar Mills         {}
735988fb7b2SAdrian Ambrożewicz 
736988fb7b2SAdrian Ambrożewicz         const std::string& user()
737988fb7b2SAdrian Ambrożewicz         {
738988fb7b2SAdrian Ambrożewicz             return credentials.user();
739988fb7b2SAdrian Ambrożewicz         }
740988fb7b2SAdrian Ambrożewicz 
741988fb7b2SAdrian Ambrożewicz         const std::string& password()
742988fb7b2SAdrian Ambrożewicz         {
743988fb7b2SAdrian Ambrożewicz             return credentials.password();
744988fb7b2SAdrian Ambrożewicz         }
745988fb7b2SAdrian Ambrożewicz 
74681ce609eSEd Tanous         SecureBuffer pack(FormatterFunc formatter)
747988fb7b2SAdrian Ambrożewicz         {
748988fb7b2SAdrian Ambrożewicz             SecureBuffer packed{new Buffer{}};
749988fb7b2SAdrian Ambrożewicz             if (formatter)
750988fb7b2SAdrian Ambrożewicz             {
751988fb7b2SAdrian Ambrożewicz                 formatter(credentials.user(), credentials.password(), *packed);
752988fb7b2SAdrian Ambrożewicz             }
753988fb7b2SAdrian Ambrożewicz 
754988fb7b2SAdrian Ambrożewicz             return packed;
755988fb7b2SAdrian Ambrożewicz         }
756988fb7b2SAdrian Ambrożewicz 
757988fb7b2SAdrian Ambrożewicz       private:
758988fb7b2SAdrian Ambrożewicz         Credentials credentials;
759988fb7b2SAdrian Ambrożewicz     };
760988fb7b2SAdrian Ambrożewicz 
761988fb7b2SAdrian Ambrożewicz     // Wrapper for boost::async_pipe ensuring proper pipe cleanup
7621214b7e7SGunnar Mills     template <typename Buffer>
7631214b7e7SGunnar Mills     class Pipe
764988fb7b2SAdrian Ambrożewicz     {
765988fb7b2SAdrian Ambrożewicz       public:
766988fb7b2SAdrian Ambrożewicz         using unix_fd = sdbusplus::message::unix_fd;
767988fb7b2SAdrian Ambrożewicz 
768988fb7b2SAdrian Ambrożewicz         Pipe(boost::asio::io_context& io, Buffer&& buffer) :
769988fb7b2SAdrian Ambrożewicz             impl(io), buffer{std::move(buffer)}
7701214b7e7SGunnar Mills         {}
771988fb7b2SAdrian Ambrożewicz 
772988fb7b2SAdrian Ambrożewicz         ~Pipe()
773988fb7b2SAdrian Ambrożewicz         {
774988fb7b2SAdrian Ambrożewicz             // Named pipe needs to be explicitly removed
775988fb7b2SAdrian Ambrożewicz             impl.close();
776988fb7b2SAdrian Ambrożewicz         }
777988fb7b2SAdrian Ambrożewicz 
778988fb7b2SAdrian Ambrożewicz         unix_fd fd()
779988fb7b2SAdrian Ambrożewicz         {
780988fb7b2SAdrian Ambrożewicz             return unix_fd{impl.native_source()};
781988fb7b2SAdrian Ambrożewicz         }
782988fb7b2SAdrian Ambrożewicz 
783988fb7b2SAdrian Ambrożewicz         template <typename WriteHandler>
78481ce609eSEd Tanous         void asyncWrite(WriteHandler&& handler)
785988fb7b2SAdrian Ambrożewicz         {
786988fb7b2SAdrian Ambrożewicz             impl.async_write_some(data(), std::forward<WriteHandler>(handler));
787988fb7b2SAdrian Ambrożewicz         }
788988fb7b2SAdrian Ambrożewicz 
789988fb7b2SAdrian Ambrożewicz       private:
790988fb7b2SAdrian Ambrożewicz         // Specialization for pointer types
791988fb7b2SAdrian Ambrożewicz         template <typename B = Buffer>
792988fb7b2SAdrian Ambrożewicz         typename std::enable_if<boost::has_dereference<B>::value,
793988fb7b2SAdrian Ambrożewicz                                 boost::asio::const_buffer>::type
794988fb7b2SAdrian Ambrożewicz             data()
795988fb7b2SAdrian Ambrożewicz         {
796988fb7b2SAdrian Ambrożewicz             return boost::asio::buffer(*buffer);
797988fb7b2SAdrian Ambrożewicz         }
798988fb7b2SAdrian Ambrożewicz 
799988fb7b2SAdrian Ambrożewicz         template <typename B = Buffer>
800988fb7b2SAdrian Ambrożewicz         typename std::enable_if<!boost::has_dereference<B>::value,
801988fb7b2SAdrian Ambrożewicz                                 boost::asio::const_buffer>::type
802988fb7b2SAdrian Ambrożewicz             data()
803988fb7b2SAdrian Ambrożewicz         {
804988fb7b2SAdrian Ambrożewicz             return boost::asio::buffer(buffer);
805988fb7b2SAdrian Ambrożewicz         }
806988fb7b2SAdrian Ambrożewicz 
807988fb7b2SAdrian Ambrożewicz         const std::string name;
808988fb7b2SAdrian Ambrożewicz         boost::process::async_pipe impl;
809988fb7b2SAdrian Ambrożewicz         Buffer buffer;
810988fb7b2SAdrian Ambrożewicz     };
811988fb7b2SAdrian Ambrożewicz 
812e13c2760SPrzemyslaw Czarnowski     /**
813e13c2760SPrzemyslaw Czarnowski      * @brief Function transceives data with dbus directly.
814e13c2760SPrzemyslaw Czarnowski      *
815e13c2760SPrzemyslaw Czarnowski      * All BMC state properties will be retrieved before sending reset request.
816e13c2760SPrzemyslaw Czarnowski      */
8178d1b46d7Szhanghch05     void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
818e13c2760SPrzemyslaw Czarnowski                          const std::string& service, const std::string& name,
819988fb7b2SAdrian Ambrożewicz                          const std::string& imageUrl, const bool rw,
820988fb7b2SAdrian Ambrożewicz                          std::string&& userName, std::string&& password)
821e13c2760SPrzemyslaw Czarnowski     {
822988fb7b2SAdrian Ambrożewicz         using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
823988fb7b2SAdrian Ambrożewicz         constexpr const size_t secretLimit = 1024;
824988fb7b2SAdrian Ambrożewicz 
825988fb7b2SAdrian Ambrożewicz         std::shared_ptr<SecurePipe> secretPipe;
826988fb7b2SAdrian Ambrożewicz         std::variant<int, SecurePipe::unix_fd> unixFd = -1;
827988fb7b2SAdrian Ambrożewicz 
828988fb7b2SAdrian Ambrożewicz         if (!userName.empty() || !password.empty())
829988fb7b2SAdrian Ambrożewicz         {
830988fb7b2SAdrian Ambrożewicz             // Encapsulate in safe buffer
831988fb7b2SAdrian Ambrożewicz             CredentialsProvider credentials(std::move(userName),
832988fb7b2SAdrian Ambrożewicz                                             std::move(password));
833988fb7b2SAdrian Ambrożewicz 
834988fb7b2SAdrian Ambrożewicz             // Payload must contain data + NULL delimiters
835988fb7b2SAdrian Ambrożewicz             if (credentials.user().size() + credentials.password().size() + 2 >
836988fb7b2SAdrian Ambrożewicz                 secretLimit)
837988fb7b2SAdrian Ambrożewicz             {
838988fb7b2SAdrian Ambrożewicz                 BMCWEB_LOG_ERROR << "Credentials too long to handle";
839988fb7b2SAdrian Ambrożewicz                 messages::unrecognizedRequestBody(asyncResp->res);
840988fb7b2SAdrian Ambrożewicz                 return;
841988fb7b2SAdrian Ambrożewicz             }
842988fb7b2SAdrian Ambrożewicz 
843988fb7b2SAdrian Ambrożewicz             // Pack secret
844988fb7b2SAdrian Ambrożewicz             auto secret = credentials.pack([](const auto& user,
845988fb7b2SAdrian Ambrożewicz                                               const auto& pass, auto& buff) {
846988fb7b2SAdrian Ambrożewicz                 std::copy(user.begin(), user.end(), std::back_inserter(buff));
847988fb7b2SAdrian Ambrożewicz                 buff.push_back('\0');
848988fb7b2SAdrian Ambrożewicz                 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
849988fb7b2SAdrian Ambrożewicz                 buff.push_back('\0');
850988fb7b2SAdrian Ambrożewicz             });
851988fb7b2SAdrian Ambrożewicz 
852988fb7b2SAdrian Ambrożewicz             // Open pipe
853988fb7b2SAdrian Ambrożewicz             secretPipe = std::make_shared<SecurePipe>(
854988fb7b2SAdrian Ambrożewicz                 crow::connections::systemBus->get_io_context(),
855988fb7b2SAdrian Ambrożewicz                 std::move(secret));
856988fb7b2SAdrian Ambrożewicz             unixFd = secretPipe->fd();
857988fb7b2SAdrian Ambrożewicz 
858988fb7b2SAdrian Ambrożewicz             // Pass secret over pipe
85981ce609eSEd Tanous             secretPipe->asyncWrite(
860f5b16f03SVikram Bodireddy                 [asyncResp](const boost::system::error_code& ec, std::size_t) {
861988fb7b2SAdrian Ambrożewicz                     if (ec)
862988fb7b2SAdrian Ambrożewicz                     {
863988fb7b2SAdrian Ambrożewicz                         BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
864988fb7b2SAdrian Ambrożewicz                         messages::internalError(asyncResp->res);
865988fb7b2SAdrian Ambrożewicz                     }
866988fb7b2SAdrian Ambrożewicz                 });
867988fb7b2SAdrian Ambrożewicz         }
868988fb7b2SAdrian Ambrożewicz 
869e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
870988fb7b2SAdrian Ambrożewicz             [asyncResp, secretPipe](const boost::system::error_code ec,
871988fb7b2SAdrian Ambrożewicz                                     bool success) {
872e13c2760SPrzemyslaw Czarnowski                 if (ec)
873e13c2760SPrzemyslaw Czarnowski                 {
874e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
875e13c2760SPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
876d6da5bebSAdrian Ambrożewicz                 }
877d6da5bebSAdrian Ambrożewicz                 else if (!success)
878d6da5bebSAdrian Ambrożewicz                 {
879d6da5bebSAdrian Ambrożewicz                     BMCWEB_LOG_ERROR << "Service responded with error";
880d6da5bebSAdrian Ambrożewicz                     messages::generalError(asyncResp->res);
881e13c2760SPrzemyslaw Czarnowski                 }
882e13c2760SPrzemyslaw Czarnowski             },
883e13c2760SPrzemyslaw Czarnowski             service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
884988fb7b2SAdrian Ambrożewicz             "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
885988fb7b2SAdrian Ambrożewicz             unixFd);
886e13c2760SPrzemyslaw Czarnowski     }
887e13c2760SPrzemyslaw Czarnowski };
888e13c2760SPrzemyslaw Czarnowski 
889e13c2760SPrzemyslaw Czarnowski /**
890e13c2760SPrzemyslaw Czarnowski    @brief EjectMedia action class
891e13c2760SPrzemyslaw Czarnowski  */
892e13c2760SPrzemyslaw Czarnowski class VirtualMediaActionEjectMedia : public Node
893e13c2760SPrzemyslaw Czarnowski {
894e13c2760SPrzemyslaw Czarnowski   public:
89552cc112dSEd Tanous     VirtualMediaActionEjectMedia(App& app) :
896e13c2760SPrzemyslaw Czarnowski         Node(app,
897e13c2760SPrzemyslaw Czarnowski              "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
898e13c2760SPrzemyslaw Czarnowski              "VirtualMedia.EjectMedia",
899e13c2760SPrzemyslaw Czarnowski              std::string(), std::string())
900e13c2760SPrzemyslaw Czarnowski     {
901e13c2760SPrzemyslaw Czarnowski         entityPrivileges = {
902e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
903e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
904e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
905e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
906e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
907e13c2760SPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
908e13c2760SPrzemyslaw Czarnowski     }
909e13c2760SPrzemyslaw Czarnowski 
910e13c2760SPrzemyslaw Czarnowski   private:
911e13c2760SPrzemyslaw Czarnowski     /**
912e13c2760SPrzemyslaw Czarnowski      * @brief Function handles POST method request.
913e13c2760SPrzemyslaw Czarnowski      *
914e13c2760SPrzemyslaw Czarnowski      * Analyzes POST body message before sends Reset request data to dbus.
915e13c2760SPrzemyslaw Czarnowski      */
9168d1b46d7Szhanghch05     void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9178d1b46d7Szhanghch05                 const crow::Request& req,
918e13c2760SPrzemyslaw Czarnowski                 const std::vector<std::string>& params) override
919e13c2760SPrzemyslaw Czarnowski     {
920e13c2760SPrzemyslaw Czarnowski         if (params.size() != 2)
921e13c2760SPrzemyslaw Czarnowski         {
9228d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
923e13c2760SPrzemyslaw Czarnowski             return;
924e13c2760SPrzemyslaw Czarnowski         }
925e13c2760SPrzemyslaw Czarnowski 
926e13c2760SPrzemyslaw Czarnowski         // take resource name from URL
927e13c2760SPrzemyslaw Czarnowski         const std::string& resName = params[1];
928e13c2760SPrzemyslaw Czarnowski 
929e13c2760SPrzemyslaw Czarnowski         if (params[0] != "bmc")
930e13c2760SPrzemyslaw Czarnowski         {
9318d1b46d7Szhanghch05             messages::resourceNotFound(asyncResp->res, "VirtualMedia.Eject",
9328d1b46d7Szhanghch05                                        resName);
933e13c2760SPrzemyslaw Czarnowski 
934e13c2760SPrzemyslaw Czarnowski             return;
935e13c2760SPrzemyslaw Czarnowski         }
936e13c2760SPrzemyslaw Czarnowski 
937e13c2760SPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
9388d1b46d7Szhanghch05             [this, asyncResp{std::move(asyncResp)}, req,
939e13c2760SPrzemyslaw Czarnowski              resName](const boost::system::error_code ec,
940e13c2760SPrzemyslaw Czarnowski                       const GetObjectType& getObjectType) {
941e13c2760SPrzemyslaw Czarnowski                 if (ec)
942e13c2760SPrzemyslaw Czarnowski                 {
943e13c2760SPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
944e13c2760SPrzemyslaw Czarnowski                                      << ec;
9458d1b46d7Szhanghch05                     messages::internalError(asyncResp->res);
946e13c2760SPrzemyslaw Czarnowski 
947e13c2760SPrzemyslaw Czarnowski                     return;
948e13c2760SPrzemyslaw Czarnowski                 }
949e13c2760SPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
950e13c2760SPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
951e13c2760SPrzemyslaw Czarnowski 
952e13c2760SPrzemyslaw Czarnowski                 crow::connections::systemBus->async_method_call(
95381ce609eSEd Tanous                     [this, resName, service, req,
9548d1b46d7Szhanghch05                      asyncResp{asyncResp}](const boost::system::error_code ec,
955e13c2760SPrzemyslaw Czarnowski                                            ManagedObjectType& subtree) {
956e13c2760SPrzemyslaw Czarnowski                         if (ec)
957e13c2760SPrzemyslaw Czarnowski                         {
958e13c2760SPrzemyslaw Czarnowski                             BMCWEB_LOG_DEBUG << "DBUS response error";
959e13c2760SPrzemyslaw Czarnowski 
960e13c2760SPrzemyslaw Czarnowski                             return;
961e13c2760SPrzemyslaw Czarnowski                         }
962e13c2760SPrzemyslaw Czarnowski 
963e13c2760SPrzemyslaw Czarnowski                         for (const auto& object : subtree)
964e13c2760SPrzemyslaw Czarnowski                         {
965e13c2760SPrzemyslaw Czarnowski                             const std::string& path =
966e13c2760SPrzemyslaw Czarnowski                                 static_cast<const std::string&>(object.first);
967e13c2760SPrzemyslaw Czarnowski 
968f23b7296SEd Tanous                             std::size_t lastIndex = path.rfind('/');
969e13c2760SPrzemyslaw Czarnowski                             if (lastIndex == std::string::npos)
970e13c2760SPrzemyslaw Czarnowski                             {
971e13c2760SPrzemyslaw Czarnowski                                 continue;
972e13c2760SPrzemyslaw Czarnowski                             }
973e13c2760SPrzemyslaw Czarnowski 
974e13c2760SPrzemyslaw Czarnowski                             lastIndex += 1;
975e13c2760SPrzemyslaw Czarnowski 
976e13c2760SPrzemyslaw Czarnowski                             if (path.substr(lastIndex) == resName)
977e13c2760SPrzemyslaw Czarnowski                             {
978e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Proxy");
979e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
980e13c2760SPrzemyslaw Czarnowski                                 {
981e13c2760SPrzemyslaw Czarnowski                                     // Proxy mode
9828d1b46d7Szhanghch05                                     doVmAction(asyncResp, service, resName,
9838d1b46d7Szhanghch05                                                false);
984e13c2760SPrzemyslaw Czarnowski                                 }
985e13c2760SPrzemyslaw Czarnowski 
986e13c2760SPrzemyslaw Czarnowski                                 lastIndex = path.rfind("Legacy");
987e13c2760SPrzemyslaw Czarnowski                                 if (lastIndex != std::string::npos)
988e13c2760SPrzemyslaw Czarnowski                                 {
989e13c2760SPrzemyslaw Czarnowski                                     // Legacy mode
9908d1b46d7Szhanghch05                                     doVmAction(asyncResp, service, resName,
9918d1b46d7Szhanghch05                                                true);
992e13c2760SPrzemyslaw Czarnowski                                 }
993e13c2760SPrzemyslaw Czarnowski 
994e13c2760SPrzemyslaw Czarnowski                                 return;
995e13c2760SPrzemyslaw Czarnowski                             }
996e13c2760SPrzemyslaw Czarnowski                         }
997e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_DEBUG << "Parent item not found";
9988d1b46d7Szhanghch05                         messages::resourceNotFound(asyncResp->res,
9998d1b46d7Szhanghch05                                                    "VirtualMedia", resName);
1000e13c2760SPrzemyslaw Czarnowski                     },
1001e13c2760SPrzemyslaw Czarnowski                     service, "/xyz/openbmc_project/VirtualMedia",
1002e13c2760SPrzemyslaw Czarnowski                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1003e13c2760SPrzemyslaw Czarnowski             },
1004e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
1005e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
1006e13c2760SPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
1007e13c2760SPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
1008e13c2760SPrzemyslaw Czarnowski     }
1009e13c2760SPrzemyslaw Czarnowski 
1010e13c2760SPrzemyslaw Czarnowski     /**
1011e13c2760SPrzemyslaw Czarnowski      * @brief Function transceives data with dbus directly.
1012e13c2760SPrzemyslaw Czarnowski      *
1013e13c2760SPrzemyslaw Czarnowski      * All BMC state properties will be retrieved before sending reset request.
1014e13c2760SPrzemyslaw Czarnowski      */
10158d1b46d7Szhanghch05     void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1016e13c2760SPrzemyslaw Czarnowski                     const std::string& service, const std::string& name,
1017e13c2760SPrzemyslaw Czarnowski                     bool legacy)
1018e13c2760SPrzemyslaw Czarnowski     {
1019e13c2760SPrzemyslaw Czarnowski 
1020e13c2760SPrzemyslaw Czarnowski         // Legacy mount requires parameter with image
1021e13c2760SPrzemyslaw Czarnowski         if (legacy)
1022e13c2760SPrzemyslaw Czarnowski         {
1023e13c2760SPrzemyslaw Czarnowski             crow::connections::systemBus->async_method_call(
1024e13c2760SPrzemyslaw Czarnowski                 [asyncResp](const boost::system::error_code ec) {
1025e13c2760SPrzemyslaw Czarnowski                     if (ec)
1026e13c2760SPrzemyslaw Czarnowski                     {
1027e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1028e13c2760SPrzemyslaw Czarnowski 
1029e13c2760SPrzemyslaw Czarnowski                         messages::internalError(asyncResp->res);
1030e13c2760SPrzemyslaw Czarnowski                         return;
1031e13c2760SPrzemyslaw Czarnowski                     }
1032e13c2760SPrzemyslaw Czarnowski                 },
1033e13c2760SPrzemyslaw Czarnowski                 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
1034e13c2760SPrzemyslaw Czarnowski                 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
1035e13c2760SPrzemyslaw Czarnowski         }
1036e13c2760SPrzemyslaw Czarnowski         else // proxy
1037e13c2760SPrzemyslaw Czarnowski         {
1038e13c2760SPrzemyslaw Czarnowski             crow::connections::systemBus->async_method_call(
1039e13c2760SPrzemyslaw Czarnowski                 [asyncResp](const boost::system::error_code ec) {
1040e13c2760SPrzemyslaw Czarnowski                     if (ec)
1041e13c2760SPrzemyslaw Czarnowski                     {
1042e13c2760SPrzemyslaw Czarnowski                         BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
1043e13c2760SPrzemyslaw Czarnowski 
1044e13c2760SPrzemyslaw Czarnowski                         messages::internalError(asyncResp->res);
1045e13c2760SPrzemyslaw Czarnowski                         return;
1046e13c2760SPrzemyslaw Czarnowski                     }
1047e13c2760SPrzemyslaw Czarnowski                 },
1048e13c2760SPrzemyslaw Czarnowski                 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
1049e13c2760SPrzemyslaw Czarnowski                 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
1050e13c2760SPrzemyslaw Czarnowski         }
1051e13c2760SPrzemyslaw Czarnowski     }
1052e13c2760SPrzemyslaw Czarnowski };
1053e13c2760SPrzemyslaw Czarnowski 
1054107077deSPrzemyslaw Czarnowski class VirtualMediaCollection : public Node
1055107077deSPrzemyslaw Czarnowski {
1056107077deSPrzemyslaw Czarnowski   public:
1057107077deSPrzemyslaw Czarnowski     /*
1058107077deSPrzemyslaw Czarnowski      * Default Constructor
1059107077deSPrzemyslaw Czarnowski      */
106052cc112dSEd Tanous     VirtualMediaCollection(App& app) :
1061107077deSPrzemyslaw Czarnowski         Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/", std::string())
1062107077deSPrzemyslaw Czarnowski     {
1063107077deSPrzemyslaw Czarnowski         entityPrivileges = {
1064107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
1065107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
1066107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1067107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1068107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1069107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1070107077deSPrzemyslaw Czarnowski     }
1071107077deSPrzemyslaw Czarnowski 
1072107077deSPrzemyslaw Czarnowski   private:
1073107077deSPrzemyslaw Czarnowski     /**
1074107077deSPrzemyslaw Czarnowski      * Functions triggers appropriate requests on DBus
1075107077deSPrzemyslaw Czarnowski      */
10768d1b46d7Szhanghch05     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
10778d1b46d7Szhanghch05                const crow::Request&,
1078107077deSPrzemyslaw Czarnowski                const std::vector<std::string>& params) override
1079107077deSPrzemyslaw Czarnowski     {
1080107077deSPrzemyslaw Czarnowski 
1081107077deSPrzemyslaw Czarnowski         // Check if there is required param, truly entering this shall be
1082107077deSPrzemyslaw Czarnowski         // impossible
1083107077deSPrzemyslaw Czarnowski         if (params.size() != 1)
1084107077deSPrzemyslaw Czarnowski         {
10858d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
1086107077deSPrzemyslaw Czarnowski 
1087107077deSPrzemyslaw Czarnowski             return;
1088107077deSPrzemyslaw Czarnowski         }
1089107077deSPrzemyslaw Czarnowski 
1090107077deSPrzemyslaw Czarnowski         const std::string& name = params[0];
1091107077deSPrzemyslaw Czarnowski 
1092107077deSPrzemyslaw Czarnowski         if (name != "bmc")
1093107077deSPrzemyslaw Czarnowski         {
1094107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
1095107077deSPrzemyslaw Czarnowski 
1096107077deSPrzemyslaw Czarnowski             return;
1097107077deSPrzemyslaw Czarnowski         }
1098107077deSPrzemyslaw Czarnowski 
10998d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.type"] =
1100107077deSPrzemyslaw Czarnowski             "#VirtualMediaCollection.VirtualMediaCollection";
11018d1b46d7Szhanghch05         asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
11028d1b46d7Szhanghch05         asyncResp->res.jsonValue["@odata.id"] =
1103d6c414f3SPrzemyslaw Czarnowski             "/redfish/v1/Managers/" + name + "/VirtualMedia";
1104107077deSPrzemyslaw Czarnowski 
1105107077deSPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
1106107077deSPrzemyslaw Czarnowski             [asyncResp, name](const boost::system::error_code ec,
1107107077deSPrzemyslaw Czarnowski                               const GetObjectType& getObjectType) {
1108107077deSPrzemyslaw Czarnowski                 if (ec)
1109107077deSPrzemyslaw Czarnowski                 {
1110107077deSPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1111107077deSPrzemyslaw Czarnowski                                      << ec;
1112107077deSPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
1113107077deSPrzemyslaw Czarnowski 
1114107077deSPrzemyslaw Czarnowski                     return;
1115107077deSPrzemyslaw Czarnowski                 }
1116107077deSPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
1117107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1118107077deSPrzemyslaw Czarnowski 
1119107077deSPrzemyslaw Czarnowski                 getVmResourceList(asyncResp, service, name);
1120107077deSPrzemyslaw Czarnowski             },
1121107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
1122107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
1123107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
1124107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
1125107077deSPrzemyslaw Czarnowski     }
1126107077deSPrzemyslaw Czarnowski };
1127107077deSPrzemyslaw Czarnowski 
1128107077deSPrzemyslaw Czarnowski class VirtualMedia : public Node
1129107077deSPrzemyslaw Czarnowski {
1130107077deSPrzemyslaw Czarnowski   public:
1131107077deSPrzemyslaw Czarnowski     /*
1132107077deSPrzemyslaw Czarnowski      * Default Constructor
1133107077deSPrzemyslaw Czarnowski      */
113452cc112dSEd Tanous     VirtualMedia(App& app) :
1135107077deSPrzemyslaw Czarnowski         Node(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/",
1136107077deSPrzemyslaw Czarnowski              std::string(), std::string())
1137107077deSPrzemyslaw Czarnowski     {
1138107077deSPrzemyslaw Czarnowski         entityPrivileges = {
1139107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::get, {{"Login"}}},
1140107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::head, {{"Login"}}},
1141107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1142107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1143107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1144107077deSPrzemyslaw Czarnowski             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1145107077deSPrzemyslaw Czarnowski     }
1146107077deSPrzemyslaw Czarnowski 
1147107077deSPrzemyslaw Czarnowski   private:
1148107077deSPrzemyslaw Czarnowski     /**
1149107077deSPrzemyslaw Czarnowski      * Functions triggers appropriate requests on DBus
1150107077deSPrzemyslaw Czarnowski      */
11518d1b46d7Szhanghch05     void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
11528d1b46d7Szhanghch05                const crow::Request&,
1153107077deSPrzemyslaw Czarnowski                const std::vector<std::string>& params) override
1154107077deSPrzemyslaw Czarnowski     {
1155107077deSPrzemyslaw Czarnowski         // Check if there is required param, truly entering this shall be
1156107077deSPrzemyslaw Czarnowski         // impossible
1157107077deSPrzemyslaw Czarnowski         if (params.size() != 2)
1158107077deSPrzemyslaw Czarnowski         {
11598d1b46d7Szhanghch05             messages::internalError(asyncResp->res);
1160107077deSPrzemyslaw Czarnowski             return;
1161107077deSPrzemyslaw Czarnowski         }
1162107077deSPrzemyslaw Czarnowski         const std::string& name = params[0];
1163107077deSPrzemyslaw Czarnowski         const std::string& resName = params[1];
1164107077deSPrzemyslaw Czarnowski 
1165107077deSPrzemyslaw Czarnowski         if (name != "bmc")
1166107077deSPrzemyslaw Czarnowski         {
1167107077deSPrzemyslaw Czarnowski             messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1168107077deSPrzemyslaw Czarnowski 
1169107077deSPrzemyslaw Czarnowski             return;
1170107077deSPrzemyslaw Czarnowski         }
1171107077deSPrzemyslaw Czarnowski 
1172107077deSPrzemyslaw Czarnowski         crow::connections::systemBus->async_method_call(
1173107077deSPrzemyslaw Czarnowski             [asyncResp, name, resName](const boost::system::error_code ec,
1174107077deSPrzemyslaw Czarnowski                                        const GetObjectType& getObjectType) {
1175107077deSPrzemyslaw Czarnowski                 if (ec)
1176107077deSPrzemyslaw Czarnowski                 {
1177107077deSPrzemyslaw Czarnowski                     BMCWEB_LOG_ERROR << "ObjectMapper::GetObject call failed: "
1178107077deSPrzemyslaw Czarnowski                                      << ec;
1179107077deSPrzemyslaw Czarnowski                     messages::internalError(asyncResp->res);
1180107077deSPrzemyslaw Czarnowski 
1181107077deSPrzemyslaw Czarnowski                     return;
1182107077deSPrzemyslaw Czarnowski                 }
1183107077deSPrzemyslaw Czarnowski                 std::string service = getObjectType.begin()->first;
1184107077deSPrzemyslaw Czarnowski                 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1185107077deSPrzemyslaw Czarnowski 
1186107077deSPrzemyslaw Czarnowski                 getVmData(asyncResp, service, name, resName);
1187107077deSPrzemyslaw Czarnowski             },
1188107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper",
1189107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/object_mapper",
1190107077deSPrzemyslaw Czarnowski             "xyz.openbmc_project.ObjectMapper", "GetObject",
1191107077deSPrzemyslaw Czarnowski             "/xyz/openbmc_project/VirtualMedia", std::array<const char*, 0>());
1192107077deSPrzemyslaw Czarnowski     }
1193107077deSPrzemyslaw Czarnowski };
1194107077deSPrzemyslaw Czarnowski 
1195107077deSPrzemyslaw Czarnowski } // namespace redfish
1196