blob: 9ef45e719ab838483a7ff5826428bcf0469fb27f [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>
32#include <string_view>
33
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020034namespace redfish
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020035{
Ed Tanous365a73f2023-02-24 12:16:49 -080036
37enum class VmMode
38{
39 Invalid,
40 Legacy,
41 Proxy
42};
43
44inline VmMode
45 parseObjectPathAndGetMode(const sdbusplus::message::object_path& itemPath,
46 const std::string& resName)
47{
48 std::string thisPath = itemPath.filename();
Ed Tanous62598e32023-07-17 17:06:25 -070049 BMCWEB_LOG_DEBUG("Filename: {}, ThisPath: {}", itemPath.str, thisPath);
Ed Tanous365a73f2023-02-24 12:16:49 -080050
51 if (thisPath.empty())
52 {
53 return VmMode::Invalid;
54 }
55
56 if (thisPath != resName)
57 {
58 return VmMode::Invalid;
59 }
60
61 auto mode = itemPath.parent_path();
62 auto type = mode.parent_path();
63
64 if (mode.filename().empty() || type.filename().empty())
65 {
66 return VmMode::Invalid;
67 }
68
69 if (type.filename() != "VirtualMedia")
70 {
71 return VmMode::Invalid;
72 }
73 std::string modeStr = mode.filename();
74 if (modeStr == "Legacy")
75 {
76 return VmMode::Legacy;
77 }
78 if (modeStr == "Proxy")
79 {
80 return VmMode::Proxy;
81 }
82 return VmMode::Invalid;
83}
84
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +020085using CheckItemHandler =
86 std::function<void(const std::string& service, const std::string& resName,
87 const std::shared_ptr<bmcweb::AsyncResp>&,
George Liu70cbdf52023-03-04 12:07:25 +080088 const std::pair<sdbusplus::message::object_path,
89 dbus::utility::DBusInteracesMap>&)>;
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +020090
Ed Tanousac106bf2023-06-07 09:24:59 -070091inline void
92 findAndParseObject(const std::string& service, const std::string& resName,
93 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
94 CheckItemHandler&& handler)
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +020095{
George Liu5eb468d2023-06-20 17:03:24 +080096 sdbusplus::message::object_path path("/xyz/openbmc_project/VirtualMedia");
97 dbus::utility::getManagedObjects(
98 service, path,
Ed Tanousac106bf2023-06-07 09:24:59 -070099 [service, resName, asyncResp,
Lakshmi Yadlapati746c5b82023-03-06 16:07:28 -0600100 handler](const boost::system::error_code& ec,
George Liu70cbdf52023-03-04 12:07:25 +0800101 const dbus::utility::ManagedObjectType& subtree) {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200102 if (ec)
103 {
Ed Tanous62598e32023-07-17 17:06:25 -0700104 BMCWEB_LOG_DEBUG("DBUS response error");
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200105
106 return;
107 }
108
George Liu70cbdf52023-03-04 12:07:25 +0800109 for (const auto& item : subtree)
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200110 {
111 VmMode mode = parseObjectPathAndGetMode(item.first, resName);
112 if (mode != VmMode::Invalid)
113 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700114 handler(service, resName, asyncResp, item);
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200115 return;
116 }
117 }
118
Ed Tanous62598e32023-07-17 17:06:25 -0700119 BMCWEB_LOG_DEBUG("Parent item not found");
Ed Tanousac106bf2023-06-07 09:24:59 -0700120 asyncResp->res.result(boost::beast::http::status::not_found);
George Liu5eb468d2023-06-20 17:03:24 +0800121 });
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200122}
123
Anna Platash9e319cf2020-11-17 10:18:31 +0100124/**
125 * @brief Function extracts transfer protocol name from URI.
126 */
Ed Tanous67df0732021-10-26 11:23:56 -0700127inline std::string getTransferProtocolTypeFromUri(const std::string& imageUri)
128{
129 boost::urls::result<boost::urls::url_view> url =
Ed Tanous079360a2022-06-29 10:05:19 -0700130 boost::urls::parse_uri(imageUri);
Ed Tanous67df0732021-10-26 11:23:56 -0700131 if (!url)
132 {
133 return "None";
134 }
Ed Tanous079360a2022-06-29 10:05:19 -0700135 std::string_view scheme = url->scheme();
Ed Tanous67df0732021-10-26 11:23:56 -0700136 if (scheme == "smb")
137 {
138 return "CIFS";
139 }
140 if (scheme == "https")
141 {
142 return "HTTPS";
143 }
144
145 return "None";
146}
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200147
148/**
149 * @brief Read all known properties from VM object interfaces
150 */
Ed Tanous22db1722021-06-09 10:53:51 -0700151inline void
Ed Tanous8a592812022-06-04 09:06:59 -0700152 vmParseInterfaceObject(const dbus::utility::DBusInteracesMap& interfaces,
Ed Tanousac106bf2023-06-07 09:24:59 -0700153 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200154{
Ed Tanous8a592812022-06-04 09:06:59 -0700155 for (const auto& [interface, values] : interfaces)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200156 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800157 if (interface == "xyz.openbmc_project.VirtualMedia.MountPoint")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200158 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800159 for (const auto& [property, value] : values)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200160 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800161 if (property == "EndpointId")
162 {
163 const std::string* endpointIdValue =
164 std::get_if<std::string>(&value);
165 if (endpointIdValue == nullptr)
166 {
167 continue;
168 }
169 if (!endpointIdValue->empty())
170 {
171 // Proxy mode
Ed Tanousac106bf2023-06-07 09:24:59 -0700172 asyncResp->res
Ed Tanous711ac7a2021-12-20 09:34:41 -0800173 .jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
174 *endpointIdValue;
Ed Tanousac106bf2023-06-07 09:24:59 -0700175 asyncResp->res.jsonValue["TransferProtocolType"] =
176 "OEM";
Ed Tanous711ac7a2021-12-20 09:34:41 -0800177 }
178 }
179 if (property == "ImageURL")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200180 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100181 const std::string* imageUrlValue =
Ed Tanous711ac7a2021-12-20 09:34:41 -0800182 std::get_if<std::string>(&value);
Ed Tanous26f69762022-01-25 09:49:11 -0800183 if (imageUrlValue != nullptr && !imageUrlValue->empty())
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100184 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100185 std::filesystem::path filePath = *imageUrlValue;
186 if (!filePath.has_filename())
187 {
188 // this will handle https share, which not
189 // necessarily has to have filename given.
Ed Tanousac106bf2023-06-07 09:24:59 -0700190 asyncResp->res.jsonValue["ImageName"] = "";
Anna Platash9e319cf2020-11-17 10:18:31 +0100191 }
192 else
193 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700194 asyncResp->res.jsonValue["ImageName"] =
Anna Platash9e319cf2020-11-17 10:18:31 +0100195 filePath.filename();
196 }
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100197
Ed Tanousac106bf2023-06-07 09:24:59 -0700198 asyncResp->res.jsonValue["Image"] = *imageUrlValue;
199 asyncResp->res.jsonValue["TransferProtocolType"] =
Anna Platash9e319cf2020-11-17 10:18:31 +0100200 getTransferProtocolTypeFromUri(*imageUrlValue);
201
Ed Tanousac106bf2023-06-07 09:24:59 -0700202 asyncResp->res.jsonValue["ConnectedVia"] =
Ed Tanous739b87e2023-02-24 13:13:33 -0800203 virtual_media::ConnectedVia::URI;
Anna Platash9e319cf2020-11-17 10:18:31 +0100204 }
205 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800206 if (property == "WriteProtected")
Anna Platash9e319cf2020-11-17 10:18:31 +0100207 {
Ed Tanous711ac7a2021-12-20 09:34:41 -0800208 const bool* writeProtectedValue = std::get_if<bool>(&value);
Ed Tanouse662eae2022-01-25 10:39:19 -0800209 if (writeProtectedValue != nullptr)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200210 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700211 asyncResp->res.jsonValue["WriteProtected"] =
Anna Platash9e319cf2020-11-17 10:18:31 +0100212 *writeProtectedValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200213 }
214 }
215 }
216 }
Ed Tanous711ac7a2021-12-20 09:34:41 -0800217 if (interface == "xyz.openbmc_project.VirtualMedia.Process")
218 {
219 for (const auto& [property, value] : values)
220 {
221 if (property == "Active")
222 {
223 const bool* activeValue = std::get_if<bool>(&value);
Ed Tanouse662eae2022-01-25 10:39:19 -0800224 if (activeValue == nullptr)
Ed Tanous711ac7a2021-12-20 09:34:41 -0800225 {
Ed Tanous62598e32023-07-17 17:06:25 -0700226 BMCWEB_LOG_DEBUG("Value Active not found");
Ed Tanous711ac7a2021-12-20 09:34:41 -0800227 return;
228 }
Ed Tanousac106bf2023-06-07 09:24:59 -0700229 asyncResp->res.jsonValue["Inserted"] = *activeValue;
Ed Tanous711ac7a2021-12-20 09:34:41 -0800230
Ed Tanouse05aec52022-01-25 10:28:56 -0800231 if (*activeValue)
Ed Tanous711ac7a2021-12-20 09:34:41 -0800232 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700233 asyncResp->res.jsonValue["ConnectedVia"] =
Ed Tanous739b87e2023-02-24 13:13:33 -0800234 virtual_media::ConnectedVia::Applet;
Ed Tanous711ac7a2021-12-20 09:34:41 -0800235 }
236 }
237 }
238 }
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200239 }
240}
241
242/**
243 * @brief Fill template for Virtual Media Item.
244 */
Ed Tanous22db1722021-06-09 10:53:51 -0700245inline nlohmann::json vmItemTemplate(const std::string& name,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500246 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200247{
248 nlohmann::json item;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700249 item["@odata.id"] = boost::urls::format(
250 "/redfish/v1/Managers/{}/VirtualMedia/{}", name, resName);
Ed Tanous22db1722021-06-09 10:53:51 -0700251
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100252 item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200253 item["Name"] = "Virtual Removable Media";
254 item["Id"] = resName;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200255 item["WriteProtected"] = true;
Ed Tanous739b87e2023-02-24 13:13:33 -0800256 item["ConnectedVia"] = virtual_media::ConnectedVia::NotConnected;
Ed Tanous613dabe2022-07-09 11:17:36 -0700257 item["MediaTypes"] = nlohmann::json::array_t({"CD", "USBStick"});
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200258 item["TransferMethod"] = "Stream";
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100259 item["Oem"]["OpenBMC"]["@odata.type"] =
260 "#OemVirtualMedia.v1_0_0.VirtualMedia";
V-Sanjana15b89722023-05-11 16:27:03 +0530261 item["Oem"]["OpenBMC"]["@odata.id"] = boost::urls::format(
262 "/redfish/v1/Managers/{}/VirtualMedia/{}#/Oem/OpenBMC", name, resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200263
264 return item;
265}
266
267/**
268 * @brief Fills collection data
269 */
Ed Tanousac106bf2023-06-07 09:24:59 -0700270inline void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500271 const std::string& service,
272 const std::string& name)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200273{
Ed Tanous62598e32023-07-17 17:06:25 -0700274 BMCWEB_LOG_DEBUG("Get available Virtual Media resources.");
George Liu5eb468d2023-06-20 17:03:24 +0800275 sdbusplus::message::object_path objPath(
276 "/xyz/openbmc_project/VirtualMedia");
277 dbus::utility::getManagedObjects(
278 service, objPath,
Ed Tanousac106bf2023-06-07 09:24:59 -0700279 [name, asyncResp{std::move(asyncResp)}](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800280 const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700281 const dbus::utility::ManagedObjectType& subtree) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700282 if (ec)
283 {
Ed Tanous62598e32023-07-17 17:06:25 -0700284 BMCWEB_LOG_DEBUG("DBUS response error");
Ed Tanous002d39b2022-05-31 08:59:27 -0700285 return;
286 }
Ed Tanousac106bf2023-06-07 09:24:59 -0700287 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
Ed Tanous002d39b2022-05-31 08:59:27 -0700288 members = nlohmann::json::array();
289
290 for (const auto& object : subtree)
291 {
292 nlohmann::json item;
293 std::string path = object.first.filename();
294 if (path.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200295 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700296 continue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200297 }
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200298
Ed Tanousef4c65b2023-04-24 15:28:50 -0700299 item["@odata.id"] = boost::urls::format(
300 "/redfish/v1/Managers/{}/VirtualMedia/{}", name, path);
Ed Tanous002d39b2022-05-31 08:59:27 -0700301 members.emplace_back(std::move(item));
302 }
Ed Tanousac106bf2023-06-07 09:24:59 -0700303 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
George Liu5eb468d2023-06-20 17:03:24 +0800304 });
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200305}
306
George Liu70cbdf52023-03-04 12:07:25 +0800307inline void
308 afterGetVmData(const std::string& name, const std::string& /*service*/,
309 const std::string& resName,
310 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
311 const std::pair<sdbusplus::message::object_path,
312 dbus::utility::DBusInteracesMap>& item)
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200313{
314 VmMode mode = parseObjectPathAndGetMode(item.first, resName);
315 if (mode == VmMode::Invalid)
316 {
317 return;
318 }
319
320 asyncResp->res.jsonValue = vmItemTemplate(name, resName);
321
322 // Check if dbus path is Legacy type
323 if (mode == VmMode::Legacy)
324 {
Ed Tanousef4c65b2023-04-24 15:28:50 -0700325 asyncResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
326 ["target"] = boost::urls::format(
327 "/redfish/v1/Managers/{}/VirtualMedia/{}/Actions/VirtualMedia.InsertMedia",
328 name, resName);
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200329 }
330
331 vmParseInterfaceObject(item.second, asyncResp);
332
Ed Tanousef4c65b2023-04-24 15:28:50 -0700333 asyncResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
334 ["target"] = boost::urls::format(
335 "/redfish/v1/Managers/{}/VirtualMedia/{}/Actions/VirtualMedia.EjectMedia",
336 name, resName);
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200337}
338
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200339/**
340 * @brief Fills data for specific resource
341 */
Ed Tanousac106bf2023-06-07 09:24:59 -0700342inline void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500343 const std::string& service, const std::string& name,
344 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200345{
Ed Tanous62598e32023-07-17 17:06:25 -0700346 BMCWEB_LOG_DEBUG("Get Virtual Media resource data.");
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200347
Ed Tanousac106bf2023-06-07 09:24:59 -0700348 findAndParseObject(service, resName, asyncResp,
George Liu70cbdf52023-03-04 12:07:25 +0800349 std::bind_front(afterGetVmData, name));
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200350}
351
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200352/**
Ed Tanous22db1722021-06-09 10:53:51 -0700353 * @brief Transfer protocols supported for InsertMedia action.
354 *
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200355 */
Ed Tanous22db1722021-06-09 10:53:51 -0700356enum class TransferProtocol
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200357{
Ed Tanous22db1722021-06-09 10:53:51 -0700358 https,
359 smb,
360 invalid
361};
362
363/**
364 * @brief Function extracts transfer protocol type from URI.
365 *
366 */
Ed Tanous67df0732021-10-26 11:23:56 -0700367inline std::optional<TransferProtocol>
Ed Tanousd9f466b2023-03-06 15:04:25 -0800368 getTransferProtocolFromUri(boost::urls::url_view imageUri)
Ed Tanous67df0732021-10-26 11:23:56 -0700369{
Ed Tanous079360a2022-06-29 10:05:19 -0700370 std::string_view scheme = imageUri.scheme();
Ed Tanous67df0732021-10-26 11:23:56 -0700371 if (scheme == "smb")
372 {
373 return TransferProtocol::smb;
374 }
375 if (scheme == "https")
376 {
377 return TransferProtocol::https;
378 }
379 if (!scheme.empty())
380 {
381 return TransferProtocol::invalid;
382 }
383
384 return {};
385}
Ed Tanous22db1722021-06-09 10:53:51 -0700386
387/**
388 * @brief Function convert transfer protocol from string param.
389 *
390 */
391inline std::optional<TransferProtocol> getTransferProtocolFromParam(
392 const std::optional<std::string>& transferProtocolType)
393{
Ed Tanouse01d0c32023-06-30 13:21:32 -0700394 if (!transferProtocolType)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100395 {
Ed Tanous22db1722021-06-09 10:53:51 -0700396 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100397 }
398
Ed Tanous22db1722021-06-09 10:53:51 -0700399 if (*transferProtocolType == "CIFS")
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200400 {
Ed Tanous22db1722021-06-09 10:53:51 -0700401 return TransferProtocol::smb;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200402 }
403
Ed Tanous22db1722021-06-09 10:53:51 -0700404 if (*transferProtocolType == "HTTPS")
405 {
406 return TransferProtocol::https;
407 }
408
409 return TransferProtocol::invalid;
410}
411
412/**
413 * @brief Function extends URI with transfer protocol type.
414 *
415 */
416inline std::string
417 getUriWithTransferProtocol(const std::string& imageUri,
418 const TransferProtocol& transferProtocol)
419{
420 if (transferProtocol == TransferProtocol::smb)
421 {
422 return "smb://" + imageUri;
423 }
424
425 if (transferProtocol == TransferProtocol::https)
426 {
427 return "https://" + imageUri;
428 }
429
430 return imageUri;
431}
432
Przemyslaw Czarnowski1f2a40c2022-06-24 13:47:08 +0200433struct InsertMediaActionParams
434{
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200435 std::optional<std::string> imageUrl;
Przemyslaw Czarnowski1f2a40c2022-06-24 13:47:08 +0200436 std::optional<std::string> userName;
437 std::optional<std::string> password;
438 std::optional<std::string> transferMethod;
439 std::optional<std::string> transferProtocolType;
440 std::optional<bool> writeProtected = true;
441 std::optional<bool> inserted;
442};
443
Ed Tanous22db1722021-06-09 10:53:51 -0700444template <typename T>
445static void secureCleanup(T& value)
446{
Ed Tanous4ecc6182022-01-07 09:36:26 -0800447 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
Ed Tanous22db1722021-06-09 10:53:51 -0700448 auto raw = const_cast<typename T::value_type*>(value.data());
449 explicit_bzero(raw, value.size() * sizeof(*raw));
450}
451
452class Credentials
453{
454 public:
455 Credentials(std::string&& user, std::string&& password) :
456 userBuf(std::move(user)), passBuf(std::move(password))
457 {}
458
459 ~Credentials()
460 {
461 secureCleanup(userBuf);
462 secureCleanup(passBuf);
463 }
464
465 const std::string& user()
466 {
467 return userBuf;
468 }
469
470 const std::string& password()
471 {
472 return passBuf;
473 }
474
475 Credentials() = delete;
476 Credentials(const Credentials&) = delete;
477 Credentials& operator=(const Credentials&) = delete;
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800478 Credentials(Credentials&&) = delete;
479 Credentials& operator=(Credentials&&) = delete;
Ed Tanous22db1722021-06-09 10:53:51 -0700480
481 private:
482 std::string userBuf;
483 std::string passBuf;
484};
485
486class CredentialsProvider
487{
488 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500489 template <typename T>
Ed Tanous22db1722021-06-09 10:53:51 -0700490 struct Deleter
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100491 {
Ed Tanous22db1722021-06-09 10:53:51 -0700492 void operator()(T* buff) const
493 {
494 if (buff)
495 {
496 secureCleanup(*buff);
497 delete buff;
498 }
499 }
500 };
501
502 using Buffer = std::vector<char>;
503 using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
504 // Using explicit definition instead of std::function to avoid implicit
505 // conversions eg. stack copy instead of reference
506 using FormatterFunc = void(const std::string& username,
507 const std::string& password, Buffer& dest);
508
509 CredentialsProvider(std::string&& user, std::string&& password) :
510 credentials(std::move(user), std::move(password))
511 {}
512
513 const std::string& user()
514 {
515 return credentials.user();
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100516 }
517
Ed Tanous22db1722021-06-09 10:53:51 -0700518 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100519 {
Ed Tanous22db1722021-06-09 10:53:51 -0700520 return credentials.password();
521 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100522
Ed Tanous1917ee92022-06-30 22:30:50 -0700523 SecureBuffer pack(FormatterFunc* formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100524 {
Ed Tanous22db1722021-06-09 10:53:51 -0700525 SecureBuffer packed{new Buffer{}};
Ed Tanouse662eae2022-01-25 10:39:19 -0800526 if (formatter != nullptr)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100527 {
Ed Tanous22db1722021-06-09 10:53:51 -0700528 formatter(credentials.user(), credentials.password(), *packed);
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100529 }
530
Ed Tanous22db1722021-06-09 10:53:51 -0700531 return packed;
532 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100533
Ed Tanous22db1722021-06-09 10:53:51 -0700534 private:
535 Credentials credentials;
536};
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100537
Ed Tanous22db1722021-06-09 10:53:51 -0700538// Wrapper for boost::async_pipe ensuring proper pipe cleanup
Ed Tanous0a483062022-07-11 10:18:50 -0700539class SecurePipe
Ed Tanous22db1722021-06-09 10:53:51 -0700540{
541 public:
542 using unix_fd = sdbusplus::message::unix_fd;
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100543
Ed Tanous0a483062022-07-11 10:18:50 -0700544 SecurePipe(boost::asio::io_context& io,
545 CredentialsProvider::SecureBuffer&& bufferIn) :
546 impl(io),
547 buffer{std::move(bufferIn)}
Ed Tanous22db1722021-06-09 10:53:51 -0700548 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100549
Ed Tanous0a483062022-07-11 10:18:50 -0700550 ~SecurePipe()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100551 {
Ed Tanous22db1722021-06-09 10:53:51 -0700552 // Named pipe needs to be explicitly removed
553 impl.close();
554 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100555
Ed Tanous0a483062022-07-11 10:18:50 -0700556 SecurePipe(const SecurePipe&) = delete;
557 SecurePipe(SecurePipe&&) = delete;
558 SecurePipe& operator=(const SecurePipe&) = delete;
559 SecurePipe& operator=(SecurePipe&&) = delete;
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800560
Ed Tanous0a483062022-07-11 10:18:50 -0700561 unix_fd fd() const
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200562 {
Ed Tanous22db1722021-06-09 10:53:51 -0700563 return unix_fd{impl.native_source()};
564 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100565
Ed Tanous22db1722021-06-09 10:53:51 -0700566 template <typename WriteHandler>
567 void asyncWrite(WriteHandler&& handler)
568 {
Ed Tanous0a483062022-07-11 10:18:50 -0700569 impl.async_write_some(boost::asio::buffer(*buffer),
570 std::forward<WriteHandler>(handler));
Ed Tanous22db1722021-06-09 10:53:51 -0700571 }
572
573 const std::string name;
574 boost::process::async_pipe impl;
Ed Tanous0a483062022-07-11 10:18:50 -0700575 CredentialsProvider::SecureBuffer buffer;
Ed Tanous22db1722021-06-09 10:53:51 -0700576};
577
578/**
579 * @brief Function transceives data with dbus directly.
580 *
581 * All BMC state properties will be retrieved before sending reset request.
582 */
583inline void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
584 const std::string& service, const std::string& name,
585 const std::string& imageUrl, const bool rw,
586 std::string&& userName, std::string&& password)
587{
Ed Tanous22db1722021-06-09 10:53:51 -0700588 constexpr const size_t secretLimit = 1024;
589
590 std::shared_ptr<SecurePipe> secretPipe;
Ed Tanous168e20c2021-12-13 14:39:53 -0800591 dbus::utility::DbusVariantType unixFd = -1;
Ed Tanous22db1722021-06-09 10:53:51 -0700592
593 if (!userName.empty() || !password.empty())
594 {
595 // Encapsulate in safe buffer
596 CredentialsProvider credentials(std::move(userName),
597 std::move(password));
598
599 // Payload must contain data + NULL delimiters
600 if (credentials.user().size() + credentials.password().size() + 2 >
601 secretLimit)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100602 {
Ed Tanous62598e32023-07-17 17:06:25 -0700603 BMCWEB_LOG_ERROR("Credentials too long to handle");
Ed Tanous22db1722021-06-09 10:53:51 -0700604 messages::unrecognizedRequestBody(asyncResp->res);
605 return;
606 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100607
Ed Tanous22db1722021-06-09 10:53:51 -0700608 // Pack secret
609 auto secret = credentials.pack(
610 [](const auto& user, const auto& pass, auto& buff) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700611 std::copy(user.begin(), user.end(), std::back_inserter(buff));
612 buff.push_back('\0');
613 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
614 buff.push_back('\0');
615 });
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100616
Ed Tanous22db1722021-06-09 10:53:51 -0700617 // Open pipe
618 secretPipe = std::make_shared<SecurePipe>(
619 crow::connections::systemBus->get_io_context(), std::move(secret));
620 unixFd = secretPipe->fd();
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100621
Ed Tanous22db1722021-06-09 10:53:51 -0700622 // Pass secret over pipe
623 secretPipe->asyncWrite(
624 [asyncResp](const boost::system::error_code& ec, std::size_t) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700625 if (ec)
626 {
Ed Tanous62598e32023-07-17 17:06:25 -0700627 BMCWEB_LOG_ERROR("Failed to pass secret: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700628 messages::internalError(asyncResp->res);
629 }
630 });
Ed Tanous22db1722021-06-09 10:53:51 -0700631 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100632
Ed Tanous22db1722021-06-09 10:53:51 -0700633 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800634 [asyncResp, secretPipe](const boost::system::error_code& ec,
Ed Tanous22db1722021-06-09 10:53:51 -0700635 bool success) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700636 if (ec)
637 {
Ed Tanous62598e32023-07-17 17:06:25 -0700638 BMCWEB_LOG_ERROR("Bad D-Bus request error: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700639 messages::internalError(asyncResp->res);
640 }
641 else if (!success)
642 {
Ed Tanous62598e32023-07-17 17:06:25 -0700643 BMCWEB_LOG_ERROR("Service responded with error");
Ed Tanous002d39b2022-05-31 08:59:27 -0700644 messages::generalError(asyncResp->res);
645 }
Ed Tanous22db1722021-06-09 10:53:51 -0700646 },
647 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
648 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
649 unixFd);
650}
651
652/**
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200653 * @brief Function validate parameters of insert media request.
654 *
655 */
656inline void validateParams(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
657 const std::string& service,
658 const std::string& resName,
659 InsertMediaActionParams& actionParams)
660{
Ed Tanous62598e32023-07-17 17:06:25 -0700661 BMCWEB_LOG_DEBUG("Validation started");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200662 // required param imageUrl must not be empty
663 if (!actionParams.imageUrl)
664 {
Ed Tanous62598e32023-07-17 17:06:25 -0700665 BMCWEB_LOG_ERROR("Request action parameter Image is empty.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200666
667 messages::propertyValueFormatError(asyncResp->res, "<empty>", "Image");
668
669 return;
670 }
671
672 // optional param inserted must be true
Ed Tanouse01d0c32023-06-30 13:21:32 -0700673 if (actionParams.inserted && !*actionParams.inserted)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200674 {
Ed Tanous62598e32023-07-17 17:06:25 -0700675 BMCWEB_LOG_ERROR(
676 "Request action optional parameter Inserted must be true.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200677
678 messages::actionParameterNotSupported(asyncResp->res, "Inserted",
679 "InsertMedia");
680
681 return;
682 }
683
684 // optional param transferMethod must be stream
Ed Tanouse01d0c32023-06-30 13:21:32 -0700685 if (actionParams.transferMethod &&
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200686 (*actionParams.transferMethod != "Stream"))
687 {
Ed Tanous62598e32023-07-17 17:06:25 -0700688 BMCWEB_LOG_ERROR("Request action optional parameter "
689 "TransferMethod must be Stream.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200690
691 messages::actionParameterNotSupported(asyncResp->res, "TransferMethod",
692 "InsertMedia");
693
694 return;
695 }
696 boost::urls::result<boost::urls::url_view> url =
697 boost::urls::parse_uri(*actionParams.imageUrl);
698 if (!url)
699 {
700 messages::actionParameterValueFormatError(
701 asyncResp->res, *actionParams.imageUrl, "Image", "InsertMedia");
702 return;
703 }
704 std::optional<TransferProtocol> uriTransferProtocolType =
705 getTransferProtocolFromUri(*url);
706
707 std::optional<TransferProtocol> paramTransferProtocolType =
708 getTransferProtocolFromParam(actionParams.transferProtocolType);
709
710 // ImageUrl does not contain valid protocol type
Ed Tanouse01d0c32023-06-30 13:21:32 -0700711 if (uriTransferProtocolType &&
712 *uriTransferProtocolType == TransferProtocol::invalid)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200713 {
Ed Tanous62598e32023-07-17 17:06:25 -0700714 BMCWEB_LOG_ERROR("Request action parameter ImageUrl must "
715 "contain specified protocol type from list: "
716 "(smb, https).");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200717
718 messages::resourceAtUriInUnknownFormat(asyncResp->res, *url);
719
720 return;
721 }
722
723 // transferProtocolType should contain value from list
Ed Tanouse01d0c32023-06-30 13:21:32 -0700724 if (paramTransferProtocolType &&
725 *paramTransferProtocolType == TransferProtocol::invalid)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200726 {
Ed Tanous62598e32023-07-17 17:06:25 -0700727 BMCWEB_LOG_ERROR("Request action parameter TransferProtocolType "
728 "must be provided with value from list: "
729 "(CIFS, HTTPS).");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200730
Ed Tanouse01d0c32023-06-30 13:21:32 -0700731 messages::propertyValueNotInList(
732 asyncResp->res, actionParams.transferProtocolType.value_or(""),
733 "TransferProtocolType");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200734 return;
735 }
736
737 // valid transfer protocol not provided either with URI nor param
Ed Tanouse01d0c32023-06-30 13:21:32 -0700738 if (!uriTransferProtocolType && !paramTransferProtocolType)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200739 {
Ed Tanous62598e32023-07-17 17:06:25 -0700740 BMCWEB_LOG_ERROR("Request action parameter ImageUrl must "
741 "contain specified protocol type or param "
742 "TransferProtocolType must be provided.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200743
744 messages::resourceAtUriInUnknownFormat(asyncResp->res, *url);
745
746 return;
747 }
748
749 // valid transfer protocol provided both with URI and param
Ed Tanouse01d0c32023-06-30 13:21:32 -0700750 if (paramTransferProtocolType && uriTransferProtocolType)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200751 {
752 // check if protocol is the same for URI and param
753 if (*paramTransferProtocolType != *uriTransferProtocolType)
754 {
Ed Tanous62598e32023-07-17 17:06:25 -0700755 BMCWEB_LOG_ERROR("Request action parameter "
756 "TransferProtocolType must contain the "
757 "same protocol type as protocol type "
758 "provided with param imageUrl.");
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200759
760 messages::actionParameterValueTypeError(
Ed Tanouse01d0c32023-06-30 13:21:32 -0700761 asyncResp->res, actionParams.transferProtocolType.value_or(""),
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200762 "TransferProtocolType", "InsertMedia");
763
764 return;
765 }
766 }
Ed Tanouse01d0c32023-06-30 13:21:32 -0700767 if (!paramTransferProtocolType)
768 {
769 messages::internalError(asyncResp->res);
770 return;
771 }
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200772
773 // validation passed, add protocol to URI if needed
Ed Tanouse01d0c32023-06-30 13:21:32 -0700774 if (!uriTransferProtocolType)
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200775 {
776 actionParams.imageUrl = getUriWithTransferProtocol(
777 *actionParams.imageUrl, *paramTransferProtocolType);
778 }
779
Jayaprakash Mutyala452bd8d2023-04-18 12:28:38 +0000780 if (!actionParams.userName)
781 {
782 actionParams.userName = "";
783 }
784
785 if (!actionParams.password)
786 {
787 actionParams.password = "";
788 }
789
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200790 doMountVmLegacy(asyncResp, service, resName, *actionParams.imageUrl,
Ed Tanouse01d0c32023-06-30 13:21:32 -0700791 !(actionParams.writeProtected.value_or(false)),
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200792 std::move(*actionParams.userName),
793 std::move(*actionParams.password));
794}
795
796/**
Ed Tanous22db1722021-06-09 10:53:51 -0700797 * @brief Function transceives data with dbus directly.
798 *
799 * All BMC state properties will be retrieved before sending reset request.
800 */
Ed Tanous24e740a2023-02-24 12:08:58 -0800801inline void doEjectAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
802 const std::string& service, const std::string& name,
803 bool legacy)
Ed Tanous22db1722021-06-09 10:53:51 -0700804{
Ed Tanous22db1722021-06-09 10:53:51 -0700805 // Legacy mount requires parameter with image
806 if (legacy)
807 {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100808 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800809 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700810 if (ec)
811 {
Ed Tanous62598e32023-07-17 17:06:25 -0700812 BMCWEB_LOG_ERROR("Bad D-Bus request error: {}", ec);
Ed Tanous22db1722021-06-09 10:53:51 -0700813
Ed Tanous002d39b2022-05-31 08:59:27 -0700814 messages::internalError(asyncResp->res);
815 return;
816 }
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100817 },
818 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
Ed Tanous22db1722021-06-09 10:53:51 -0700819 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200820 }
Ed Tanous22db1722021-06-09 10:53:51 -0700821 else // proxy
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200822 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200823 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800824 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700825 if (ec)
826 {
Ed Tanous62598e32023-07-17 17:06:25 -0700827 BMCWEB_LOG_ERROR("Bad D-Bus request error: {}", ec);
Ed Tanous22db1722021-06-09 10:53:51 -0700828
Ed Tanous002d39b2022-05-31 08:59:27 -0700829 messages::internalError(asyncResp->res);
830 return;
831 }
Ed Tanous22db1722021-06-09 10:53:51 -0700832 },
833 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
834 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
835 }
836}
837
Ed Tanous96825be2022-06-03 09:43:38 -0700838inline void handleManagersVirtualMediaActionInsertPost(
839 crow::App& app, const crow::Request& req,
840 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
841 const std::string& name, const std::string& resName)
842{
843 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
844 {
845 return;
846 }
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200847
848 constexpr std::string_view action = "VirtualMedia.InsertMedia";
Ed Tanous96825be2022-06-03 09:43:38 -0700849 if (name != "bmc")
850 {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200851 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700852
853 return;
854 }
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200855 InsertMediaActionParams actionParams;
Ed Tanous96825be2022-06-03 09:43:38 -0700856
Przemyslaw Czarnowski120fa862022-06-24 15:10:48 +0200857 // Read obligatory parameters (url of image)
Ed Tanous96825be2022-06-03 09:43:38 -0700858 if (!json_util::readJsonAction(
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200859 req, asyncResp->res, "Image", actionParams.imageUrl,
860 "WriteProtected", actionParams.writeProtected, "UserName",
861 actionParams.userName, "Password", actionParams.password,
862 "Inserted", actionParams.inserted, "TransferMethod",
863 actionParams.transferMethod, "TransferProtocolType",
864 actionParams.transferProtocolType))
Ed Tanous96825be2022-06-03 09:43:38 -0700865 {
866 return;
867 }
868
George Liu2b731192023-01-11 16:27:13 +0800869 dbus::utility::getDbusObject(
870 "/xyz/openbmc_project/VirtualMedia", {},
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200871 [asyncResp, action, actionParams,
George Liu2b731192023-01-11 16:27:13 +0800872 resName](const boost::system::error_code& ec,
Ed Tanous96825be2022-06-03 09:43:38 -0700873 const dbus::utility::MapperGetObject& getObjectType) mutable {
874 if (ec)
875 {
Ed Tanous62598e32023-07-17 17:06:25 -0700876 BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec);
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200877 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700878
879 return;
880 }
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200881
Ed Tanous96825be2022-06-03 09:43:38 -0700882 std::string service = getObjectType.begin()->first;
Ed Tanous62598e32023-07-17 17:06:25 -0700883 BMCWEB_LOG_DEBUG("GetObjectType: {}", service);
Ed Tanous96825be2022-06-03 09:43:38 -0700884
George Liu5eb468d2023-06-20 17:03:24 +0800885 sdbusplus::message::object_path path(
886 "/xyz/openbmc_project/VirtualMedia");
887 dbus::utility::getManagedObjects(
888 service, path,
889 [service, resName, action, actionParams, asyncResp](
890 const boost::system::error_code& ec2,
891 const dbus::utility::ManagedObjectType& subtree) mutable {
Ed Tanous8a592812022-06-04 09:06:59 -0700892 if (ec2)
Ed Tanous96825be2022-06-03 09:43:38 -0700893 {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200894 // Not possible in proxy mode
Ed Tanous62598e32023-07-17 17:06:25 -0700895 BMCWEB_LOG_DEBUG("InsertMedia not "
896 "allowed in proxy mode");
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200897 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700898
899 return;
900 }
Ed Tanous96825be2022-06-03 09:43:38 -0700901 for (const auto& object : subtree)
902 {
Ed Tanous365a73f2023-02-24 12:16:49 -0800903 VmMode mode = parseObjectPathAndGetMode(object.first, resName);
Boleslaw Ogonczyk Makowski5880f0c2023-04-14 15:32:40 +0200904 if (mode == VmMode::Legacy)
Ed Tanous96825be2022-06-03 09:43:38 -0700905 {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200906 validateParams(asyncResp, service, resName, actionParams);
Ed Tanous96825be2022-06-03 09:43:38 -0700907
908 return;
909 }
910 }
Ed Tanous62598e32023-07-17 17:06:25 -0700911 BMCWEB_LOG_DEBUG("Parent item not found");
Ed Tanous96825be2022-06-03 09:43:38 -0700912 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
George Liu5eb468d2023-06-20 17:03:24 +0800913 });
George Liu2b731192023-01-11 16:27:13 +0800914 });
Ed Tanous96825be2022-06-03 09:43:38 -0700915}
916
917inline void handleManagersVirtualMediaActionEject(
918 crow::App& app, const crow::Request& req,
919 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
920 const std::string& managerName, const std::string& resName)
921{
922 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
923 {
924 return;
925 }
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200926
927 constexpr std::string_view action = "VirtualMedia.EjectMedia";
Ed Tanous96825be2022-06-03 09:43:38 -0700928 if (managerName != "bmc")
929 {
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200930 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700931
932 return;
933 }
934
George Liu2b731192023-01-11 16:27:13 +0800935 dbus::utility::getDbusObject(
936 "/xyz/openbmc_project/VirtualMedia", {},
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200937 [asyncResp, action,
George Liu2b731192023-01-11 16:27:13 +0800938 resName](const boost::system::error_code& ec2,
Ed Tanous96825be2022-06-03 09:43:38 -0700939 const dbus::utility::MapperGetObject& getObjectType) {
Ed Tanous8a592812022-06-04 09:06:59 -0700940 if (ec2)
Ed Tanous96825be2022-06-03 09:43:38 -0700941 {
Ed Tanous62598e32023-07-17 17:06:25 -0700942 BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec2);
Ed Tanous96825be2022-06-03 09:43:38 -0700943 messages::internalError(asyncResp->res);
944
945 return;
946 }
947 std::string service = getObjectType.begin()->first;
Ed Tanous62598e32023-07-17 17:06:25 -0700948 BMCWEB_LOG_DEBUG("GetObjectType: {}", service);
Ed Tanous96825be2022-06-03 09:43:38 -0700949
George Liu5eb468d2023-06-20 17:03:24 +0800950 sdbusplus::message::object_path path(
951 "/xyz/openbmc_project/VirtualMedia");
952 dbus::utility::getManagedObjects(
953 service, path,
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200954 [resName, service, action,
955 asyncResp](const boost::system::error_code& ec,
956 const dbus::utility::ManagedObjectType& subtree) {
Ed Tanous96825be2022-06-03 09:43:38 -0700957 if (ec)
958 {
Ed Tanous62598e32023-07-17 17:06:25 -0700959 BMCWEB_LOG_ERROR("ObjectMapper : No Service found");
Przemyslaw Czarnowski79fdf632022-06-28 18:11:59 +0200960 messages::resourceNotFound(asyncResp->res, action, resName);
Ed Tanous96825be2022-06-03 09:43:38 -0700961 return;
962 }
963
964 for (const auto& object : subtree)
965 {
Ed Tanous365a73f2023-02-24 12:16:49 -0800966 VmMode mode = parseObjectPathAndGetMode(object.first, resName);
967 if (mode != VmMode::Invalid)
Ed Tanous96825be2022-06-03 09:43:38 -0700968 {
Ed Tanous365a73f2023-02-24 12:16:49 -0800969 doEjectAction(asyncResp, service, resName,
970 mode == VmMode::Legacy);
Boleslaw Ogonczyk Makowski5880f0c2023-04-14 15:32:40 +0200971 return;
Ed Tanous96825be2022-06-03 09:43:38 -0700972 }
973 }
Ed Tanous62598e32023-07-17 17:06:25 -0700974 BMCWEB_LOG_DEBUG("Parent item not found");
Ed Tanous96825be2022-06-03 09:43:38 -0700975 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
George Liu5eb468d2023-06-20 17:03:24 +0800976 });
George Liu2b731192023-01-11 16:27:13 +0800977 });
Ed Tanous96825be2022-06-03 09:43:38 -0700978}
979
980inline void handleManagersVirtualMediaCollectionGet(
981 crow::App& app, const crow::Request& req,
982 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
983 const std::string& name)
984{
985 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
986 {
987 return;
988 }
989 if (name != "bmc")
990 {
991 messages::resourceNotFound(asyncResp->res, "VirtualMedia", name);
992
993 return;
994 }
995
996 asyncResp->res.jsonValue["@odata.type"] =
997 "#VirtualMediaCollection.VirtualMediaCollection";
998 asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700999 asyncResp->res.jsonValue["@odata.id"] =
1000 boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia", name);
Ed Tanous96825be2022-06-03 09:43:38 -07001001
George Liu2b731192023-01-11 16:27:13 +08001002 dbus::utility::getDbusObject(
1003 "/xyz/openbmc_project/VirtualMedia", {},
1004 [asyncResp, name](const boost::system::error_code& ec,
Ed Tanous96825be2022-06-03 09:43:38 -07001005 const dbus::utility::MapperGetObject& getObjectType) {
1006 if (ec)
1007 {
Ed Tanous62598e32023-07-17 17:06:25 -07001008 BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec);
Ed Tanous96825be2022-06-03 09:43:38 -07001009 messages::internalError(asyncResp->res);
1010
1011 return;
1012 }
1013 std::string service = getObjectType.begin()->first;
Ed Tanous62598e32023-07-17 17:06:25 -07001014 BMCWEB_LOG_DEBUG("GetObjectType: {}", service);
Ed Tanous96825be2022-06-03 09:43:38 -07001015
1016 getVmResourceList(asyncResp, service, name);
George Liu2b731192023-01-11 16:27:13 +08001017 });
Ed Tanous96825be2022-06-03 09:43:38 -07001018}
1019
1020inline void
1021 handleVirtualMediaGet(crow::App& app, const crow::Request& req,
1022 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1023 const std::string& name, const std::string& resName)
1024{
1025 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1026 {
1027 return;
1028 }
1029 if (name != "bmc")
1030 {
1031 messages::resourceNotFound(asyncResp->res, "VirtualMedia", resName);
1032
1033 return;
1034 }
1035
George Liu2b731192023-01-11 16:27:13 +08001036 dbus::utility::getDbusObject(
1037 "/xyz/openbmc_project/VirtualMedia", {},
Ed Tanous96825be2022-06-03 09:43:38 -07001038 [asyncResp, name,
George Liu2b731192023-01-11 16:27:13 +08001039 resName](const boost::system::error_code& ec,
Ed Tanous96825be2022-06-03 09:43:38 -07001040 const dbus::utility::MapperGetObject& getObjectType) {
1041 if (ec)
1042 {
Ed Tanous62598e32023-07-17 17:06:25 -07001043 BMCWEB_LOG_ERROR("ObjectMapper::GetObject call failed: {}", ec);
Ed Tanous96825be2022-06-03 09:43:38 -07001044 messages::internalError(asyncResp->res);
1045
1046 return;
1047 }
1048 std::string service = getObjectType.begin()->first;
Ed Tanous62598e32023-07-17 17:06:25 -07001049 BMCWEB_LOG_DEBUG("GetObjectType: {}", service);
Ed Tanous96825be2022-06-03 09:43:38 -07001050
1051 getVmData(asyncResp, service, name, resName);
George Liu2b731192023-01-11 16:27:13 +08001052 });
Ed Tanous96825be2022-06-03 09:43:38 -07001053}
1054
Ed Tanous22db1722021-06-09 10:53:51 -07001055inline void requestNBDVirtualMediaRoutes(App& app)
1056{
George Liu0fda0f12021-11-16 10:06:17 +08001057 BMCWEB_ROUTE(
1058 app,
1059 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.InsertMedia")
Ed Tanoused398212021-06-09 17:05:54 -07001060 .privileges(redfish::privileges::postVirtualMedia)
Ed Tanous96825be2022-06-03 09:43:38 -07001061 .methods(boost::beast::http::verb::post)(std::bind_front(
1062 handleManagersVirtualMediaActionInsertPost, std::ref(app)));
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +02001063
George Liu0fda0f12021-11-16 10:06:17 +08001064 BMCWEB_ROUTE(
1065 app,
1066 "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/VirtualMedia.EjectMedia")
Ed Tanoused398212021-06-09 17:05:54 -07001067 .privileges(redfish::privileges::postVirtualMedia)
Ed Tanous96825be2022-06-03 09:43:38 -07001068 .methods(boost::beast::http::verb::post)(std::bind_front(
1069 handleManagersVirtualMediaActionEject, std::ref(app)));
Ed Tanous002d39b2022-05-31 08:59:27 -07001070
Ed Tanous22db1722021-06-09 10:53:51 -07001071 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/")
Ed Tanoused398212021-06-09 17:05:54 -07001072 .privileges(redfish::privileges::getVirtualMediaCollection)
Ed Tanous96825be2022-06-03 09:43:38 -07001073 .methods(boost::beast::http::verb::get)(std::bind_front(
1074 handleManagersVirtualMediaCollectionGet, std::ref(app)));
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001075
Ed Tanous22db1722021-06-09 10:53:51 -07001076 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001077 .privileges(redfish::privileges::getVirtualMedia)
Ed Tanous22db1722021-06-09 10:53:51 -07001078 .methods(boost::beast::http::verb::get)(
Ed Tanous96825be2022-06-03 09:43:38 -07001079 std::bind_front(handleVirtualMediaGet, std::ref(app)));
Ed Tanous22db1722021-06-09 10:53:51 -07001080}
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001081
1082} // namespace redfish