blob: 304fffa63587c0259840485a98e6179a2bd28667 [file] [log] [blame]
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "account_service.hpp"
19#include "app.hpp"
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +020020#include "async_resp.hpp"
George Liu2b731192023-01-11 16:27:13 +080021#include "dbus_utility.hpp"
Ed Tanous739b87e2023-02-24 13:13:33 -080022#include "generated/enums/virtual_media.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080023#include "query.hpp"
24#include "registries/privilege_registry.hpp"
25#include "utils/json_utils.hpp"
26
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +010027#include <boost/process/async_pipe.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070028#include <boost/url/format.hpp>
Anna Platash9e319cf2020-11-17 10:18:31 +010029#include <boost/url/url_view.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020030
George Liu2b731192023-01-11 16:27:13 +080031#include <array>
Ed Tanous3544d2a2023-08-06 18:12:20 -070032#include <ranges>
George Liu2b731192023-01-11 16:27:13 +080033#include <string_view>
34
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020035namespace redfish
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020036{
Ed Tanous365a73f2023-02-24 12:16:49 -080037
38enum class VmMode
39{
40 Invalid,
41 Legacy,
42 Proxy
43};
44
45inline VmMode
46 parseObjectPathAndGetMode(const sdbusplus::message::object_path& itemPath,
47 const std::string& resName)
48{
49 std::string thisPath = itemPath.filename();
Ed Tanous62598e32023-07-17 17:06:25 -070050 BMCWEB_LOG_DEBUG("Filename: {}, ThisPath: {}", itemPath.str, thisPath);
Ed Tanous365a73f2023-02-24 12:16:49 -080051
52 if (thisPath.empty())
53 {
54 return VmMode::Invalid;
55 }
56
57 if (thisPath != resName)
58 {
59 return VmMode::Invalid;
60 }
61
62 auto mode = itemPath.parent_path();
63 auto type = mode.parent_path();
64
65 if (mode.filename().empty() || type.filename().empty())
66 {
67 return VmMode::Invalid;
68 }
69
70 if (type.filename() != "VirtualMedia")
71 {
72 return VmMode::Invalid;
73 }
74 std::string modeStr = mode.filename();
75 if (modeStr == "Legacy")
76 {
77 return VmMode::Legacy;
78 }
79 if (modeStr == "Proxy")
80 {
81 return VmMode::Proxy;
82 }
83 return VmMode::Invalid;
84}
85
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +020086using CheckItemHandler =
87 std::function<void(const std::string& service, const std::string& resName,
88 const std::shared_ptr<bmcweb::AsyncResp>&,
George Liu70cbdf52023-03-04 12:07:25 +080089 const std::pair<sdbusplus::message::object_path,
Michael Shen80f79a42023-08-24 13:41:53 +000090 dbus::utility::DBusInterfacesMap>&)>;
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +020091
Ed Tanousac106bf2023-06-07 09:24:59 -070092inline void
93 findAndParseObject(const std::string& service, const std::string& resName,
94 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
95 CheckItemHandler&& handler)
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +020096{
George Liu5eb468d2023-06-20 17:03:24 +080097 sdbusplus::message::object_path path("/xyz/openbmc_project/VirtualMedia");
98 dbus::utility::getManagedObjects(
99 service, path,
Ed Tanousac106bf2023-06-07 09:24:59 -0700100 [service, resName, asyncResp,
Lakshmi Yadlapati746c5b82023-03-06 16:07:28 -0600101 handler](const boost::system::error_code& ec,
George Liu70cbdf52023-03-04 12:07:25 +0800102 const dbus::utility::ManagedObjectType& subtree) {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200103 if (ec)
104 {
Ed Tanous62598e32023-07-17 17:06:25 -0700105 BMCWEB_LOG_DEBUG("DBUS response error");
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200106
107 return;
108 }
109
George Liu70cbdf52023-03-04 12:07:25 +0800110 for (const auto& item : subtree)
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200111 {
112 VmMode mode = parseObjectPathAndGetMode(item.first, resName);
113 if (mode != VmMode::Invalid)
114 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700115 handler(service, resName, asyncResp, item);
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200116 return;
117 }
118 }
119
Ed Tanous62598e32023-07-17 17:06:25 -0700120 BMCWEB_LOG_DEBUG("Parent item not found");
Ed Tanousac106bf2023-06-07 09:24:59 -0700121 asyncResp->res.result(boost::beast::http::status::not_found);
George Liu5eb468d2023-06-20 17:03:24 +0800122 });
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200123}
124
Anna Platash9e319cf2020-11-17 10:18:31 +0100125/**
126 * @brief Function extracts transfer protocol name from URI.
127 */
Ed Tanous67df0732021-10-26 11:23:56 -0700128inline std::string getTransferProtocolTypeFromUri(const std::string& imageUri)
129{
130 boost::urls::result<boost::urls::url_view> url =
Ed Tanous079360a2022-06-29 10:05:19 -0700131 boost::urls::parse_uri(imageUri);
Ed Tanous67df0732021-10-26 11:23:56 -0700132 if (!url)
133 {
134 return "None";
135 }
Ed Tanous079360a2022-06-29 10:05:19 -0700136 std::string_view scheme = url->scheme();
Ed Tanous67df0732021-10-26 11:23:56 -0700137 if (scheme == "smb")
138 {
139 return "CIFS";
140 }
141 if (scheme == "https")
142 {
143 return "HTTPS";
144 }
145
146 return "None";
147}
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200148
149/**
150 * @brief Read all known properties from VM object interfaces
151 */
Ed Tanous22db1722021-06-09 10:53:51 -0700152inline void
Michael Shen80f79a42023-08-24 13:41:53 +0000153 vmParseInterfaceObject(const dbus::utility::DBusInterfacesMap& interfaces,
Ed Tanousac106bf2023-06-07 09:24:59 -0700154 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200155{
Ed Tanous8a592812022-06-04 09:06:59 -0700156 for (const auto& [interface, values] : interfaces)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200157 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800158 if (interface == "xyz.openbmc_project.VirtualMedia.MountPoint")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200159 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800160 for (const auto& [property, value] : values)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200161 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800162 if (property == "EndpointId")
163 {
164 const std::string* endpointIdValue =
165 std::get_if<std::string>(&value);
166 if (endpointIdValue == nullptr)
167 {
168 continue;
169 }
170 if (!endpointIdValue->empty())
171 {
172 // Proxy mode
Ed Tanousac106bf2023-06-07 09:24:59 -0700173 asyncResp->res
Ed Tanous711ac7a2021-12-20 09:34:41 -0800174 .jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
175 *endpointIdValue;
Ed Tanousac106bf2023-06-07 09:24:59 -0700176 asyncResp->res.jsonValue["TransferProtocolType"] =
177 "OEM";
Ed Tanous711ac7a2021-12-20 09:34:41 -0800178 }
179 }
180 if (property == "ImageURL")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200181 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100182 const std::string* imageUrlValue =
Ed Tanous711ac7a2021-12-20 09:34:41 -0800183 std::get_if<std::string>(&value);
Ed Tanous26f69762022-01-25 09:49:11 -0800184 if (imageUrlValue != nullptr && !imageUrlValue->empty())
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100185 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100186 std::filesystem::path filePath = *imageUrlValue;
187 if (!filePath.has_filename())
188 {
189 // this will handle https share, which not
190 // necessarily has to have filename given.
Ed Tanousac106bf2023-06-07 09:24:59 -0700191 asyncResp->res.jsonValue["ImageName"] = "";
Anna Platash9e319cf2020-11-17 10:18:31 +0100192 }
193 else
194 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700195 asyncResp->res.jsonValue["ImageName"] =
Anna Platash9e319cf2020-11-17 10:18:31 +0100196 filePath.filename();
197 }
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100198
Ed Tanousac106bf2023-06-07 09:24:59 -0700199 asyncResp->res.jsonValue["Image"] = *imageUrlValue;
200 asyncResp->res.jsonValue["TransferProtocolType"] =
Anna Platash9e319cf2020-11-17 10:18:31 +0100201 getTransferProtocolTypeFromUri(*imageUrlValue);
202
Ed Tanousac106bf2023-06-07 09:24:59 -0700203 asyncResp->res.jsonValue["ConnectedVia"] =
Ed Tanous739b87e2023-02-24 13:13:33 -0800204 virtual_media::ConnectedVia::URI;
Anna Platash9e319cf2020-11-17 10:18:31 +0100205 }
206 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800207 if (property == "WriteProtected")
Anna Platash9e319cf2020-11-17 10:18:31 +0100208 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800209 const bool* writeProtectedValue = std::get_if<bool>(&value);
Ed Tanouse662eae2022-01-25 10:39:19 -0800210 if (writeProtectedValue != nullptr)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200211 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700212 asyncResp->res.jsonValue["WriteProtected"] =
Anna Platash9e319cf2020-11-17 10:18:31 +0100213 *writeProtectedValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200214 }
215 }
216 }
217 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800218 if (interface == "xyz.openbmc_project.VirtualMedia.Process")
219 {
220 for (const auto& [property, value] : values)
221 {
222 if (property == "Active")
223 {
224 const bool* activeValue = std::get_if<bool>(&value);
Ed Tanouse662eae2022-01-25 10:39:19 -0800225 if (activeValue == nullptr)
Ed Tanous711ac7a2021-12-20 09:34:41 -0800226 {
Ed Tanous62598e32023-07-17 17:06:25 -0700227 BMCWEB_LOG_DEBUG("Value Active not found");
Ed Tanous711ac7a2021-12-20 09:34:41 -0800228 return;
229 }
Ed Tanousac106bf2023-06-07 09:24:59 -0700230 asyncResp->res.jsonValue["Inserted"] = *activeValue;
Ed Tanous711ac7a2021-12-20 09:34:41 -0800231
Ed Tanouse05aec52022-01-25 10:28:56 -0800232 if (*activeValue)
Ed Tanous711ac7a2021-12-20 09:34:41 -0800233 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700234 asyncResp->res.jsonValue["ConnectedVia"] =
Ed Tanous739b87e2023-02-24 13:13:33 -0800235 virtual_media::ConnectedVia::Applet;
Ed Tanous711ac7a2021-12-20 09:34:41 -0800236 }
237 }
238 }
239 }
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200240 }
241}
242
243/**
244 * @brief Fill template for Virtual Media Item.
245 */
Ed Tanous22db1722021-06-09 10:53:51 -0700246inline nlohmann::json vmItemTemplate(const std::string& name,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500247 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200248{
249 nlohmann::json item;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700250 item["@odata.id"] = boost::urls::format(
251 "/redfish/v1/Managers/{}/VirtualMedia/{}", name, resName);
Ed Tanous22db1722021-06-09 10:53:51 -0700252
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100253 item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200254 item["Name"] = "Virtual Removable Media";
255 item["Id"] = resName;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200256 item["WriteProtected"] = true;
Ed Tanous739b87e2023-02-24 13:13:33 -0800257 item["ConnectedVia"] = virtual_media::ConnectedVia::NotConnected;
Ed Tanous613dabe2022-07-09 11:17:36 -0700258 item["MediaTypes"] = nlohmann::json::array_t({"CD", "USBStick"});
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200259 item["TransferMethod"] = "Stream";
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100260 item["Oem"]["OpenBMC"]["@odata.type"] =
261 "#OemVirtualMedia.v1_0_0.VirtualMedia";
V-Sanjana15b89722023-05-11 16:27:03 +0530262 item["Oem"]["OpenBMC"]["@odata.id"] = boost::urls::format(
263 "/redfish/v1/Managers/{}/VirtualMedia/{}#/Oem/OpenBMC", name, resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200264
265 return item;
266}
267
268/**
269 * @brief Fills collection data
270 */
Ed Tanousac106bf2023-06-07 09:24:59 -0700271inline void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500272 const std::string& service,
273 const std::string& name)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200274{
Ed Tanous62598e32023-07-17 17:06:25 -0700275 BMCWEB_LOG_DEBUG("Get available Virtual Media resources.");
George Liu5eb468d2023-06-20 17:03:24 +0800276 sdbusplus::message::object_path objPath(
277 "/xyz/openbmc_project/VirtualMedia");
278 dbus::utility::getManagedObjects(
279 service, objPath,
Ed Tanousac106bf2023-06-07 09:24:59 -0700280 [name, asyncResp{std::move(asyncResp)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800281 const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700282 const dbus::utility::ManagedObjectType& subtree) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700283 if (ec)
284 {
Ed Tanous62598e32023-07-17 17:06:25 -0700285 BMCWEB_LOG_DEBUG("DBUS response error");
Ed Tanous002d39b2022-05-31 08:59:27 -0700286 return;
287 }
Ed Tanousac106bf2023-06-07 09:24:59 -0700288 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
Ed Tanous002d39b2022-05-31 08:59:27 -0700289 members = nlohmann::json::array();
290
291 for (const auto& object : subtree)
292 {
293 nlohmann::json item;
294 std::string path = object.first.filename();
295 if (path.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200296 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700297 continue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200298 }
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200299
Ed Tanousef4c65b2023-04-24 15:28:50 -0700300 item["@odata.id"] = boost::urls::format(
301 "/redfish/v1/Managers/{}/VirtualMedia/{}", name, path);
Ed Tanous002d39b2022-05-31 08:59:27 -0700302 members.emplace_back(std::move(item));
303 }
Ed Tanousac106bf2023-06-07 09:24:59 -0700304 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
George Liu5eb468d2023-06-20 17:03:24 +0800305 });
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200306}
307
George Liu70cbdf52023-03-04 12:07:25 +0800308inline void
309 afterGetVmData(const std::string& name, const std::string& /*service*/,
310 const std::string& resName,
311 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
312 const std::pair<sdbusplus::message::object_path,
Michael Shen80f79a42023-08-24 13:41:53 +0000313 dbus::utility::DBusInterfacesMap>& item)
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200314{
315 VmMode mode = parseObjectPathAndGetMode(item.first, resName);
316 if (mode == VmMode::Invalid)
317 {
318 return;
319 }
320
321 asyncResp->res.jsonValue = vmItemTemplate(name, resName);
322
323 // Check if dbus path is Legacy type
324 if (mode == VmMode::Legacy)
325 {
Ed Tanousef4c65b2023-04-24 15:28:50 -0700326 asyncResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
327 ["target"] = boost::urls::format(
328 "/redfish/v1/Managers/{}/VirtualMedia/{}/Actions/VirtualMedia.InsertMedia",
329 name, resName);
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200330 }
331
332 vmParseInterfaceObject(item.second, asyncResp);
333
Ed Tanousef4c65b2023-04-24 15:28:50 -0700334 asyncResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
335 ["target"] = boost::urls::format(
336 "/redfish/v1/Managers/{}/VirtualMedia/{}/Actions/VirtualMedia.EjectMedia",
337 name, resName);
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200338}
339
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200340/**
341 * @brief Fills data for specific resource
342 */
Ed Tanousac106bf2023-06-07 09:24:59 -0700343inline void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500344 const std::string& service, const std::string& name,
345 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200346{
Ed Tanous62598e32023-07-17 17:06:25 -0700347 BMCWEB_LOG_DEBUG("Get Virtual Media resource data.");
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200348
Ed Tanousac106bf2023-06-07 09:24:59 -0700349 findAndParseObject(service, resName, asyncResp,
George Liu70cbdf52023-03-04 12:07:25 +0800350 std::bind_front(afterGetVmData, name));
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200351}
352
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200353/**
Ed Tanous22db1722021-06-09 10:53:51 -0700354 * @brief Transfer protocols supported for InsertMedia action.
355 *
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200356 */
Ed Tanous22db1722021-06-09 10:53:51 -0700357enum class TransferProtocol
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200358{
Ed Tanous22db1722021-06-09 10:53:51 -0700359 https,
360 smb,
361 invalid
362};
363
364/**
365 * @brief Function extracts transfer protocol type from URI.
366 *
367 */
Ed Tanous67df0732021-10-26 11:23:56 -0700368inline std::optional<TransferProtocol>
Ed Tanousd9f466b2023-03-06 15:04:25 -0800369 getTransferProtocolFromUri(boost::urls::url_view imageUri)
Ed Tanous67df0732021-10-26 11:23:56 -0700370{
Ed Tanous079360a2022-06-29 10:05:19 -0700371 std::string_view scheme = imageUri.scheme();
Ed Tanous67df0732021-10-26 11:23:56 -0700372 if (scheme == "smb")
373 {
374 return TransferProtocol::smb;
375 }
376 if (scheme == "https")
377 {
378 return TransferProtocol::https;
379 }
380 if (!scheme.empty())
381 {
382 return TransferProtocol::invalid;
383 }
384
385 return {};
386}
Ed Tanous22db1722021-06-09 10:53:51 -0700387
388/**
389 * @brief Function convert transfer protocol from string param.
390 *
391 */
392inline std::optional<TransferProtocol> getTransferProtocolFromParam(
393 const std::optional<std::string>& transferProtocolType)
394{
Ed Tanouse01d0c32023-06-30 13:21:32 -0700395 if (!transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100396 {
Ed Tanous22db1722021-06-09 10:53:51 -0700397 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100398 }
399
Ed Tanous22db1722021-06-09 10:53:51 -0700400 if (*transferProtocolType == "CIFS")
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200401 {
Ed Tanous22db1722021-06-09 10:53:51 -0700402 return TransferProtocol::smb;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200403 }
404
Ed Tanous22db1722021-06-09 10:53:51 -0700405 if (*transferProtocolType == "HTTPS")
406 {
407 return TransferProtocol::https;
408 }
409
410 return TransferProtocol::invalid;
411}
412
413/**
414 * @brief Function extends URI with transfer protocol type.
415 *
416 */
417inline std::string
418 getUriWithTransferProtocol(const std::string& imageUri,
419 const TransferProtocol& transferProtocol)
420{
421 if (transferProtocol == TransferProtocol::smb)
422 {
423 return "smb://" + imageUri;
424 }
425
426 if (transferProtocol == TransferProtocol::https)
427 {
428 return "https://" + imageUri;
429 }
430
431 return imageUri;
432}
433
Przemyslaw Czarnowski1f2a40c2022-06-24 13:47:08 +0200434struct InsertMediaActionParams
435{
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200436 std::optional<std::string> imageUrl;
Przemyslaw Czarnowski1f2a40c2022-06-24 13:47:08 +0200437 std::optional<std::string> userName;
438 std::optional<std::string> password;
439 std::optional<std::string> transferMethod;
440 std::optional<std::string> transferProtocolType;
441 std::optional<bool> writeProtected = true;
442 std::optional<bool> inserted;
443};
444
Ed Tanous22db1722021-06-09 10:53:51 -0700445template <typename T>
446static void secureCleanup(T& value)
447{
Ed Tanous4ecc6182022-01-07 09:36:26 -0800448 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
Ed Tanous22db1722021-06-09 10:53:51 -0700449 auto raw = const_cast<typename T::value_type*>(value.data());
450 explicit_bzero(raw, value.size() * sizeof(*raw));
451}
452
453class Credentials
454{
455 public:
456 Credentials(std::string&& user, std::string&& password) :
457 userBuf(std::move(user)), passBuf(std::move(password))
458 {}
459
460 ~Credentials()
461 {
462 secureCleanup(userBuf);
463 secureCleanup(passBuf);
464 }
465
466 const std::string& user()
467 {
468 return userBuf;
469 }
470
471 const std::string& password()
472 {
473 return passBuf;
474 }
475
476 Credentials() = delete;
477 Credentials(const Credentials&) = delete;
478 Credentials& operator=(const Credentials&) = delete;
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800479 Credentials(Credentials&&) = delete;
480 Credentials& operator=(Credentials&&) = delete;
Ed Tanous22db1722021-06-09 10:53:51 -0700481
482 private:
483 std::string userBuf;
484 std::string passBuf;
485};
486
487class CredentialsProvider
488{
489 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500490 template <typename T>
Ed Tanous22db1722021-06-09 10:53:51 -0700491 struct Deleter
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100492 {
Ed Tanous22db1722021-06-09 10:53:51 -0700493 void operator()(T* buff) const
494 {
495 if (buff)
496 {
497 secureCleanup(*buff);
498 delete buff;
499 }
500 }
501 };
502
503 using Buffer = std::vector<char>;
504 using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
505 // Using explicit definition instead of std::function to avoid implicit
506 // conversions eg. stack copy instead of reference
507 using FormatterFunc = void(const std::string& username,
508 const std::string& password, Buffer& dest);
509
510 CredentialsProvider(std::string&& user, std::string&& password) :
511 credentials(std::move(user), std::move(password))
512 {}
513
514 const std::string& user()
515 {
516 return credentials.user();
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100517 }
518
Ed Tanous22db1722021-06-09 10:53:51 -0700519 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100520 {
Ed Tanous22db1722021-06-09 10:53:51 -0700521 return credentials.password();
522 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100523
Ed Tanous1917ee92022-06-30 22:30:50 -0700524 SecureBuffer pack(FormatterFunc* formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100525 {
Ed Tanous22db1722021-06-09 10:53:51 -0700526 SecureBuffer packed{new Buffer{}};
Ed Tanouse662eae2022-01-25 10:39:19 -0800527 if (formatter != nullptr)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100528 {
Ed Tanous22db1722021-06-09 10:53:51 -0700529 formatter(credentials.user(), credentials.password(), *packed);
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100530 }
531
Ed Tanous22db1722021-06-09 10:53:51 -0700532 return packed;
533 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100534
Ed Tanous22db1722021-06-09 10:53:51 -0700535 private:
536 Credentials credentials;
537};
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100538
Ed Tanous22db1722021-06-09 10:53:51 -0700539// Wrapper for boost::async_pipe ensuring proper pipe cleanup
Ed Tanous0a483062022-07-11 10:18:50 -0700540class SecurePipe
Ed Tanous22db1722021-06-09 10:53:51 -0700541{
542 public:
543 using unix_fd = sdbusplus::message::unix_fd;
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100544
Ed Tanous0a483062022-07-11 10:18:50 -0700545 SecurePipe(boost::asio::io_context& io,
546 CredentialsProvider::SecureBuffer&& bufferIn) :
547 impl(io),
548 buffer{std::move(bufferIn)}
Ed Tanous22db1722021-06-09 10:53:51 -0700549 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100550
Ed Tanous0a483062022-07-11 10:18:50 -0700551 ~SecurePipe()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100552 {
Ed Tanous22db1722021-06-09 10:53:51 -0700553 // Named pipe needs to be explicitly removed
554 impl.close();
555 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100556
Ed Tanous0a483062022-07-11 10:18:50 -0700557 SecurePipe(const SecurePipe&) = delete;
558 SecurePipe(SecurePipe&&) = delete;
559 SecurePipe& operator=(const SecurePipe&) = delete;
560 SecurePipe& operator=(SecurePipe&&) = delete;
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800561
Ed Tanous0a483062022-07-11 10:18:50 -0700562 unix_fd fd() const
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200563 {
Ed Tanous22db1722021-06-09 10:53:51 -0700564 return unix_fd{impl.native_source()};
565 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100566
Ed Tanous22db1722021-06-09 10:53:51 -0700567 template <typename WriteHandler>
568 void asyncWrite(WriteHandler&& handler)
569 {
Ed Tanous0a483062022-07-11 10:18:50 -0700570 impl.async_write_some(boost::asio::buffer(*buffer),
571 std::forward<WriteHandler>(handler));
Ed Tanous22db1722021-06-09 10:53:51 -0700572 }
573
574 const std::string name;
575 boost::process::async_pipe impl;
Ed Tanous0a483062022-07-11 10:18:50 -0700576 CredentialsProvider::SecureBuffer buffer;
Ed Tanous22db1722021-06-09 10:53:51 -0700577};
578
579/**
580 * @brief Function transceives data with dbus directly.
581 *
582 * All BMC state properties will be retrieved before sending reset request.
583 */
584inline void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
585 const std::string& service, const std::string& name,
586 const std::string& imageUrl, const bool rw,
587 std::string&& userName, std::string&& password)
588{
Ed Tanous22db1722021-06-09 10:53:51 -0700589 constexpr const size_t secretLimit = 1024;
590
591 std::shared_ptr<SecurePipe> secretPipe;
Ed Tanous168e20c2021-12-13 14:39:53 -0800592 dbus::utility::DbusVariantType unixFd = -1;
Ed Tanous22db1722021-06-09 10:53:51 -0700593
594 if (!userName.empty() || !password.empty())
595 {
596 // Encapsulate in safe buffer
597 CredentialsProvider credentials(std::move(userName),
598 std::move(password));
599
600 // Payload must contain data + NULL delimiters
601 if (credentials.user().size() + credentials.password().size() + 2 >
602 secretLimit)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100603 {
Ed Tanous62598e32023-07-17 17:06:25 -0700604 BMCWEB_LOG_ERROR("Credentials too long to handle");
Ed Tanous22db1722021-06-09 10:53:51 -0700605 messages::unrecognizedRequestBody(asyncResp->res);
606 return;
607 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100608
Ed Tanous22db1722021-06-09 10:53:51 -0700609 // Pack secret
610 auto secret = credentials.pack(
611 [](const auto& user, const auto& pass, auto& buff) {
Ed Tanous3544d2a2023-08-06 18:12:20 -0700612 std::ranges::copy(user, std::back_inserter(buff));
Ed Tanous002d39b2022-05-31 08:59:27 -0700613 buff.push_back('\0');
Ed Tanous3544d2a2023-08-06 18:12:20 -0700614 std::ranges::copy(pass, std::back_inserter(buff));
Ed Tanous002d39b2022-05-31 08:59:27 -0700615 buff.push_back('\0');
616 });
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100617
Ed Tanous22db1722021-06-09 10:53:51 -0700618 // Open pipe
619 secretPipe = std::make_shared<SecurePipe>(
620 crow::connections::systemBus->get_io_context(), std::move(secret));
621 unixFd = secretPipe->fd();
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100622
Ed Tanous22db1722021-06-09 10:53:51 -0700623 // Pass secret over pipe
624 secretPipe->asyncWrite(
625 [asyncResp](const boost::system::error_code& ec, std::size_t) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700626 if (ec)
627 {
Ed Tanous62598e32023-07-17 17:06:25 -0700628 BMCWEB_LOG_ERROR("Failed to pass secret: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700629 messages::internalError(asyncResp->res);
630 }
631 });
Ed Tanous22db1722021-06-09 10:53:51 -0700632 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100633
Ed Tanous22db1722021-06-09 10:53:51 -0700634 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800635 [asyncResp, secretPipe](const boost::system::error_code& ec,
Ed Tanous22db1722021-06-09 10:53:51 -0700636 bool success) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700637 if (ec)
638 {
Ed Tanous62598e32023-07-17 17:06:25 -0700639 BMCWEB_LOG_ERROR("Bad D-Bus request error: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700640 messages::internalError(asyncResp->res);
641 }
642 else if (!success)
643 {
Ed Tanous62598e32023-07-17 17:06:25 -0700644 BMCWEB_LOG_ERROR("Service responded with error");
Ed Tanous002d39b2022-05-31 08:59:27 -0700645 messages::generalError(asyncResp->res);
646 }
Ed Tanous22db1722021-06-09 10:53:51 -0700647 },
648 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
649 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
650 unixFd);
651}
652
653/**
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200654 * @brief Function validate parameters of insert media request.
655 *
656 */
657inline void validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
658 const std::string& service,
659 const std::string& resName,
660 InsertMediaActionParams& actionParams)
661{
Ed Tanous62598e32023-07-17 17:06:25 -0700662 BMCWEB_LOG_DEBUG("Validation started");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200663 // required param imageUrl must not be empty
664 if (!actionParams.imageUrl)
665 {
Ed Tanous62598e32023-07-17 17:06:25 -0700666 BMCWEB_LOG_ERROR("Request action parameter Image is empty.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200667
668 messages::propertyValueFormatError(asyncResp->res, "<empty>", "Image");
669
670 return;
671 }
672
673 // optional param inserted must be true
Ed Tanouse01d0c32023-06-30 13:21:32 -0700674 if (actionParams.inserted && !*actionParams.inserted)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200675 {
Ed Tanous62598e32023-07-17 17:06:25 -0700676 BMCWEB_LOG_ERROR(
677 "Request action optional parameter Inserted must be true.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200678
679 messages::actionParameterNotSupported(asyncResp->res, "Inserted",
680 "InsertMedia");
681
682 return;
683 }
684
685 // optional param transferMethod must be stream
Ed Tanouse01d0c32023-06-30 13:21:32 -0700686 if (actionParams.transferMethod &&
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200687 (*actionParams.transferMethod != "Stream"))
688 {
Ed Tanous62598e32023-07-17 17:06:25 -0700689 BMCWEB_LOG_ERROR("Request action optional parameter "
690 "TransferMethod must be Stream.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200691
692 messages::actionParameterNotSupported(asyncResp->res, "TransferMethod",
693 "InsertMedia");
694
695 return;
696 }
697 boost::urls::result<boost::urls::url_view> url =
698 boost::urls::parse_uri(*actionParams.imageUrl);
699 if (!url)
700 {
701 messages::actionParameterValueFormatError(
702 asyncResp->res, *actionParams.imageUrl, "Image", "InsertMedia");
703 return;
704 }
705 std::optional<TransferProtocol> uriTransferProtocolType =
706 getTransferProtocolFromUri(*url);
707
708 std::optional<TransferProtocol> paramTransferProtocolType =
709 getTransferProtocolFromParam(actionParams.transferProtocolType);
710
711 // ImageUrl does not contain valid protocol type
Ed Tanouse01d0c32023-06-30 13:21:32 -0700712 if (uriTransferProtocolType &&
713 *uriTransferProtocolType == TransferProtocol::invalid)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200714 {
Ed Tanous62598e32023-07-17 17:06:25 -0700715 BMCWEB_LOG_ERROR("Request action parameter ImageUrl must "
716 "contain specified protocol type from list: "
717 "(smb, https).");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200718
719 messages::resourceAtUriInUnknownFormat(asyncResp->res, *url);
720
721 return;
722 }
723
724 // transferProtocolType should contain value from list
Ed Tanouse01d0c32023-06-30 13:21:32 -0700725 if (paramTransferProtocolType &&
726 *paramTransferProtocolType == TransferProtocol::invalid)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200727 {
Ed Tanous62598e32023-07-17 17:06:25 -0700728 BMCWEB_LOG_ERROR("Request action parameter TransferProtocolType "
729 "must be provided with value from list: "
730 "(CIFS, HTTPS).");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200731
Ed Tanouse01d0c32023-06-30 13:21:32 -0700732 messages::propertyValueNotInList(
733 asyncResp->res, actionParams.transferProtocolType.value_or(""),
734 "TransferProtocolType");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200735 return;
736 }
737
738 // valid transfer protocol not provided either with URI nor param
Ed Tanouse01d0c32023-06-30 13:21:32 -0700739 if (!uriTransferProtocolType && !paramTransferProtocolType)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200740 {
Ed Tanous62598e32023-07-17 17:06:25 -0700741 BMCWEB_LOG_ERROR("Request action parameter ImageUrl must "
742 "contain specified protocol type or param "
743 "TransferProtocolType must be provided.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200744
745 messages::resourceAtUriInUnknownFormat(asyncResp->res, *url);
746
747 return;
748 }
749
750 // valid transfer protocol provided both with URI and param
Ed Tanouse01d0c32023-06-30 13:21:32 -0700751 if (paramTransferProtocolType && uriTransferProtocolType)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200752 {
753 // check if protocol is the same for URI and param
754 if (*paramTransferProtocolType != *uriTransferProtocolType)
755 {
Ed Tanous62598e32023-07-17 17:06:25 -0700756 BMCWEB_LOG_ERROR("Request action parameter "
757 "TransferProtocolType must contain the "
758 "same protocol type as protocol type "
759 "provided with param imageUrl.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200760
761 messages::actionParameterValueTypeError(
Ed Tanouse01d0c32023-06-30 13:21:32 -0700762 asyncResp->res, actionParams.transferProtocolType.value_or(""),
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200763 "TransferProtocolType", "InsertMedia");
764
765 return;
766 }
767 }
Ed Tanouse01d0c32023-06-30 13:21:32 -0700768 if (!paramTransferProtocolType)
769 {
770 messages::internalError(asyncResp->res);
771 return;
772 }
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200773
774 // validation passed, add protocol to URI if needed
Ed Tanouse01d0c32023-06-30 13:21:32 -0700775 if (!uriTransferProtocolType)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200776 {
777 actionParams.imageUrl = getUriWithTransferProtocol(
778 *actionParams.imageUrl, *paramTransferProtocolType);
779 }
780
Jayaprakash Mutyala452bd8d2023-04-18 12:28:38 +0000781 if (!actionParams.userName)
782 {
783 actionParams.userName = "";
784 }
785
786 if (!actionParams.password)
787 {
788 actionParams.password = "";
789 }
790
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200791 doMountVmLegacy(asyncResp, service, resName, *actionParams.imageUrl,
Ed Tanouse01d0c32023-06-30 13:21:32 -0700792 !(actionParams.writeProtected.value_or(false)),
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200793 std::move(*actionParams.userName),
794 std::move(*actionParams.password));
795}
796
797/**
Ed Tanous22db1722021-06-09 10:53:51 -0700798 * @brief Function transceives data with dbus directly.
799 *
800 * All BMC state properties will be retrieved before sending reset request.
801 */
Ed Tanous24e740a2023-02-24 12:08:58 -0800802inline void doEjectAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
803 const std::string& service, const std::string& name,
804 bool legacy)
Ed Tanous22db1722021-06-09 10:53:51 -0700805{
Ed Tanous22db1722021-06-09 10:53:51 -0700806 // Legacy mount requires parameter with image
807 if (legacy)
808 {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100809 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800810 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700811 if (ec)
812 {
Ed Tanous62598e32023-07-17 17:06:25 -0700813 BMCWEB_LOG_ERROR("Bad D-Bus request error: {}", ec);
Ed Tanous22db1722021-06-09 10:53:51 -0700814
Ed Tanous002d39b2022-05-31 08:59:27 -0700815 messages::internalError(asyncResp->res);
816 return;
817 }
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100818 },
819 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
Ed Tanous22db1722021-06-09 10:53:51 -0700820 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200821 }
Ed Tanous22db1722021-06-09 10:53:51 -0700822 else // proxy
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200823 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200824 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800825 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700826 if (ec)
827 {
Ed Tanous62598e32023-07-17 17:06:25 -0700828 BMCWEB_LOG_ERROR("Bad D-Bus request error: {}", ec);
Ed Tanous22db1722021-06-09 10:53:51 -0700829
Ed Tanous002d39b2022-05-31 08:59:27 -0700830 messages::internalError(asyncResp->res);
831 return;
832 }
Ed Tanous22db1722021-06-09 10:53:51 -0700833 },
834 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
835 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
836 }
837}
838
Ed Tanous96825be2022-06-03 09:43:38 -0700839inline void handleManagersVirtualMediaActionInsertPost(
840 crow::App& app, const crow::Request& req,
841 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
842 const std::string& name, const std::string& resName)
843{
844 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
845 {
846 return;
847 }
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200848
849 constexpr std::string_view action = "VirtualMedia.InsertMedia";
Ed Tanous96825be2022-06-03 09:43:38 -0700850 if (name != "bmc")
851 {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200852 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700853
854 return;
855 }
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200856 InsertMediaActionParams actionParams;
Ed Tanous96825be2022-06-03 09:43:38 -0700857
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200858 // Read obligatory parameters (url of image)
Ed Tanous96825be2022-06-03 09:43:38 -0700859 if (!json_util::readJsonAction(
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200860 req, asyncResp->res, "Image", actionParams.imageUrl,
861 "WriteProtected", actionParams.writeProtected, "UserName",
862 actionParams.userName, "Password", actionParams.password,
863 "Inserted", actionParams.inserted, "TransferMethod",
864 actionParams.transferMethod, "TransferProtocolType",
865 actionParams.transferProtocolType))
Ed Tanous96825be2022-06-03 09:43:38 -0700866 {
867 return;
868 }
869
George Liu2b731192023-01-11 16:27:13 +0800870 dbus::utility::getDbusObject(
871 "/xyz/openbmc_project/VirtualMedia", {},
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200872 [asyncResp, action, actionParams,
George Liu2b731192023-01-11 16:27:13 +0800873 resName](const boost::system::error_code& ec,
Ed Tanous96825be2022-06-03 09:43:38 -0700874 const dbus::utility::MapperGetObject& getObjectType) mutable {
875 if (ec)
876 {
Ed Tanous62598e32023-07-17 17:06:25 -0700877 BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec);
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200878 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700879
880 return;
881 }
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200882
Ed Tanous96825be2022-06-03 09:43:38 -0700883 std::string service = getObjectType.begin()->first;
Ed Tanous62598e32023-07-17 17:06:25 -0700884 BMCWEB_LOG_DEBUG("GetObjectType: {}", service);
Ed Tanous96825be2022-06-03 09:43:38 -0700885
George Liu5eb468d2023-06-20 17:03:24 +0800886 sdbusplus::message::object_path path(
887 "/xyz/openbmc_project/VirtualMedia");
888 dbus::utility::getManagedObjects(
889 service, path,
890 [service, resName, action, actionParams, asyncResp](
891 const boost::system::error_code& ec2,
892 const dbus::utility::ManagedObjectType& subtree) mutable {
Ed Tanous8a592812022-06-04 09:06:59 -0700893 if (ec2)
Ed Tanous96825be2022-06-03 09:43:38 -0700894 {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200895 // Not possible in proxy mode
Ed Tanous62598e32023-07-17 17:06:25 -0700896 BMCWEB_LOG_DEBUG("InsertMedia not "
897 "allowed in proxy mode");
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200898 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700899
900 return;
901 }
Ed Tanous96825be2022-06-03 09:43:38 -0700902 for (const auto& object : subtree)
903 {
Ed Tanous365a73f2023-02-24 12:16:49 -0800904 VmMode mode = parseObjectPathAndGetMode(object.first, resName);
Boleslaw Ogonczyk Makowski5880f0c2023-04-14 15:32:40 +0200905 if (mode == VmMode::Legacy)
Ed Tanous96825be2022-06-03 09:43:38 -0700906 {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200907 validateParams(asyncResp, service, resName, actionParams);
Ed Tanous96825be2022-06-03 09:43:38 -0700908
909 return;
910 }
911 }
Ed Tanous62598e32023-07-17 17:06:25 -0700912 BMCWEB_LOG_DEBUG("Parent item not found");
Ed Tanous96825be2022-06-03 09:43:38 -0700913 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
George Liu5eb468d2023-06-20 17:03:24 +0800914 });
George Liu2b731192023-01-11 16:27:13 +0800915 });
Ed Tanous96825be2022-06-03 09:43:38 -0700916}
917
918inline void handleManagersVirtualMediaActionEject(
919 crow::App& app, const crow::Request& req,
920 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
921 const std::string& managerName, const std::string& resName)
922{
923 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
924 {
925 return;
926 }
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200927
928 constexpr std::string_view action = "VirtualMedia.EjectMedia";
Ed Tanous96825be2022-06-03 09:43:38 -0700929 if (managerName != "bmc")
930 {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200931 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700932
933 return;
934 }
935
George Liu2b731192023-01-11 16:27:13 +0800936 dbus::utility::getDbusObject(
937 "/xyz/openbmc_project/VirtualMedia", {},
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200938 [asyncResp, action,
George Liu2b731192023-01-11 16:27:13 +0800939 resName](const boost::system::error_code& ec2,
Ed Tanous96825be2022-06-03 09:43:38 -0700940 const dbus::utility::MapperGetObject& getObjectType) {
Ed Tanous8a592812022-06-04 09:06:59 -0700941 if (ec2)
Ed Tanous96825be2022-06-03 09:43:38 -0700942 {
Ed Tanous62598e32023-07-17 17:06:25 -0700943 BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec2);
Ed Tanous96825be2022-06-03 09:43:38 -0700944 messages::internalError(asyncResp->res);
945
946 return;
947 }
948 std::string service = getObjectType.begin()->first;
Ed Tanous62598e32023-07-17 17:06:25 -0700949 BMCWEB_LOG_DEBUG("GetObjectType: {}", service);
Ed Tanous96825be2022-06-03 09:43:38 -0700950
George Liu5eb468d2023-06-20 17:03:24 +0800951 sdbusplus::message::object_path path(
952 "/xyz/openbmc_project/VirtualMedia");
953 dbus::utility::getManagedObjects(
954 service, path,
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200955 [resName, service, action,
956 asyncResp](const boost::system::error_code& ec,
957 const dbus::utility::ManagedObjectType& subtree) {
Ed Tanous96825be2022-06-03 09:43:38 -0700958 if (ec)
959 {
Ed Tanous62598e32023-07-17 17:06:25 -0700960 BMCWEB_LOG_ERROR("ObjectMapper : No Service found");
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200961 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700962 return;
963 }
964
965 for (const auto& object : subtree)
966 {
Ed Tanous365a73f2023-02-24 12:16:49 -0800967 VmMode mode = parseObjectPathAndGetMode(object.first, resName);
968 if (mode != VmMode::Invalid)
Ed Tanous96825be2022-06-03 09:43:38 -0700969 {
Ed Tanous365a73f2023-02-24 12:16:49 -0800970 doEjectAction(asyncResp, service, resName,
971 mode == VmMode::Legacy);
Boleslaw Ogonczyk Makowski5880f0c2023-04-14 15:32:40 +0200972 return;
Ed Tanous96825be2022-06-03 09:43:38 -0700973 }
974 }
Ed Tanous62598e32023-07-17 17:06:25 -0700975 BMCWEB_LOG_DEBUG("Parent item not found");
Ed Tanous96825be2022-06-03 09:43:38 -0700976 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
George Liu5eb468d2023-06-20 17:03:24 +0800977 });
George Liu2b731192023-01-11 16:27:13 +0800978 });
Ed Tanous96825be2022-06-03 09:43:38 -0700979}
980
981inline void handleManagersVirtualMediaCollectionGet(
982 crow::App& app, const crow::Request& req,
983 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
984 const std::string& name)
985{
986 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
987 {
988 return;
989 }
990 if (name != "bmc")
991 {
992 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
993
994 return;
995 }
996
997 asyncResp->res.jsonValue["@odata.type"] =
998 "#VirtualMediaCollection.VirtualMediaCollection";
999 asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001000 asyncResp->res.jsonValue["@odata.id"] =
1001 boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia", name);
Ed Tanous96825be2022-06-03 09:43:38 -07001002
George Liu2b731192023-01-11 16:27:13 +08001003 dbus::utility::getDbusObject(
1004 "/xyz/openbmc_project/VirtualMedia", {},
1005 [asyncResp, name](const boost::system::error_code& ec,
Ed Tanous96825be2022-06-03 09:43:38 -07001006 const dbus::utility::MapperGetObject& getObjectType) {
1007 if (ec)
1008 {
Ed Tanous62598e32023-07-17 17:06:25 -07001009 BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec);
Ed Tanous96825be2022-06-03 09:43:38 -07001010 messages::internalError(asyncResp->res);
1011
1012 return;
1013 }
1014 std::string service = getObjectType.begin()->first;
Ed Tanous62598e32023-07-17 17:06:25 -07001015 BMCWEB_LOG_DEBUG("GetObjectType: {}", service);
Ed Tanous96825be2022-06-03 09:43:38 -07001016
1017 getVmResourceList(asyncResp, service, name);
George Liu2b731192023-01-11 16:27:13 +08001018 });
Ed Tanous96825be2022-06-03 09:43:38 -07001019}
1020
1021inline void
1022 handleVirtualMediaGet(crow::App& app, const crow::Request& req,
1023 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1024 const std::string& name, const std::string& resName)
1025{
1026 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1027 {
1028 return;
1029 }
1030 if (name != "bmc")
1031 {
1032 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1033
1034 return;
1035 }
1036
George Liu2b731192023-01-11 16:27:13 +08001037 dbus::utility::getDbusObject(
1038 "/xyz/openbmc_project/VirtualMedia", {},
Ed Tanous96825be2022-06-03 09:43:38 -07001039 [asyncResp, name,
George Liu2b731192023-01-11 16:27:13 +08001040 resName](const boost::system::error_code& ec,
Ed Tanous96825be2022-06-03 09:43:38 -07001041 const dbus::utility::MapperGetObject& getObjectType) {
1042 if (ec)
1043 {
Ed Tanous62598e32023-07-17 17:06:25 -07001044 BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec);
Ed Tanous96825be2022-06-03 09:43:38 -07001045 messages::internalError(asyncResp->res);
1046
1047 return;
1048 }
1049 std::string service = getObjectType.begin()->first;
Ed Tanous62598e32023-07-17 17:06:25 -07001050 BMCWEB_LOG_DEBUG("GetObjectType: {}", service);
Ed Tanous96825be2022-06-03 09:43:38 -07001051
1052 getVmData(asyncResp, service, name, resName);
George Liu2b731192023-01-11 16:27:13 +08001053 });
Ed Tanous96825be2022-06-03 09:43:38 -07001054}
1055
Ed Tanous22db1722021-06-09 10:53:51 -07001056inline void requestNBDVirtualMediaRoutes(App& app)
1057{
George Liu0fda0f12021-11-16 10:06:17 +08001058 BMCWEB_ROUTE(
1059 app,
1060 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.InsertMedia")
Ed Tanoused398212021-06-09 17:05:54 -07001061 .privileges(redfish::privileges::postVirtualMedia)
Ed Tanous96825be2022-06-03 09:43:38 -07001062 .methods(boost::beast::http::verb::post)(std::bind_front(
1063 handleManagersVirtualMediaActionInsertPost, std::ref(app)));
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001064
George Liu0fda0f12021-11-16 10:06:17 +08001065 BMCWEB_ROUTE(
1066 app,
1067 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.EjectMedia")
Ed Tanoused398212021-06-09 17:05:54 -07001068 .privileges(redfish::privileges::postVirtualMedia)
Ed Tanous96825be2022-06-03 09:43:38 -07001069 .methods(boost::beast::http::verb::post)(std::bind_front(
1070 handleManagersVirtualMediaActionEject, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07001071
Ed Tanous22db1722021-06-09 10:53:51 -07001072 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/")
Ed Tanoused398212021-06-09 17:05:54 -07001073 .privileges(redfish::privileges::getVirtualMediaCollection)
Ed Tanous96825be2022-06-03 09:43:38 -07001074 .methods(boost::beast::http::verb::get)(std::bind_front(
1075 handleManagersVirtualMediaCollectionGet, std::ref(app)));
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001076
Ed Tanous22db1722021-06-09 10:53:51 -07001077 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001078 .privileges(redfish::privileges::getVirtualMedia)
Ed Tanous22db1722021-06-09 10:53:51 -07001079 .methods(boost::beast::http::verb::get)(
Ed Tanous96825be2022-06-03 09:43:38 -07001080 std::bind_front(handleVirtualMediaGet, std::ref(app)));
Ed Tanous22db1722021-06-09 10:53:51 -07001081}
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001082
1083} // namespace redfish