blob: 7383477b3fa030a22c40b241e17a8211a42f4434 [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
John Edward Broadbent7e860f12021-04-08 15:57:16 -070018#include <app.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020019#include <boost/container/flat_map.hpp>
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +010020#include <boost/process/async_pipe.hpp>
21#include <boost/type_traits/has_dereference.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020022#include <utils/json_utils.hpp>
23// for GetObjectType and ManagedObjectType
Ed Tanoused398212021-06-09 17:05:54 -070024
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +020025#include <account_service.hpp>
Anna Platash9e319cf2020-11-17 10:18:31 +010026#include <boost/url/url_view.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070027#include <registries/privilege_registry.hpp>
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020028
29namespace redfish
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020030{
Anna Platash9e319cf2020-11-17 10:18:31 +010031/**
32 * @brief Function extracts transfer protocol name from URI.
33 */
Ed Tanous22db1722021-06-09 10:53:51 -070034inline std::string getTransferProtocolTypeFromUri(const std::string& imageUri)
Anna Platash9e319cf2020-11-17 10:18:31 +010035{
Ed Tanousd32c4fa2021-09-14 13:16:51 -070036 boost::urls::error_code ec;
37 boost::urls::url_view url =
38 boost::urls::parse_uri(boost::string_view(imageUri), ec);
39 if (ec)
Anna Platash9e319cf2020-11-17 10:18:31 +010040 {
Ed Tanousd32c4fa2021-09-14 13:16:51 -070041 return "None";
Anna Platash9e319cf2020-11-17 10:18:31 +010042 }
Ed Tanousd32c4fa2021-09-14 13:16:51 -070043 boost::string_view scheme = url.scheme();
44 if (scheme == "smb")
Anna Platash9e319cf2020-11-17 10:18:31 +010045 {
Ed Tanousd32c4fa2021-09-14 13:16:51 -070046 return "CIFS";
Anna Platash9e319cf2020-11-17 10:18:31 +010047 }
Ed Tanousd32c4fa2021-09-14 13:16:51 -070048 if (scheme == "https")
49 {
50 return "HTTPS";
51 }
52
Anna Platash9e319cf2020-11-17 10:18:31 +010053 return "None";
54}
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020055
56/**
57 * @brief Read all known properties from VM object interfaces
58 */
Ed Tanous22db1722021-06-09 10:53:51 -070059inline void
zhanghch058d1b46d2021-04-01 11:18:24 +080060 vmParseInterfaceObject(const DbusInterfaceType& interface,
61 const std::shared_ptr<bmcweb::AsyncResp>& aResp)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020062{
63 const auto mountPointIface =
64 interface.find("xyz.openbmc_project.VirtualMedia.MountPoint");
65 if (mountPointIface == interface.cend())
66 {
67 BMCWEB_LOG_DEBUG << "Interface MountPoint not found";
68 return;
69 }
70
71 const auto processIface =
72 interface.find("xyz.openbmc_project.VirtualMedia.Process");
73 if (processIface == interface.cend())
74 {
75 BMCWEB_LOG_DEBUG << "Interface Process not found";
76 return;
77 }
78
79 const auto endpointIdProperty = mountPointIface->second.find("EndpointId");
80 if (endpointIdProperty == mountPointIface->second.cend())
81 {
82 BMCWEB_LOG_DEBUG << "Property EndpointId not found";
83 return;
84 }
85
86 const auto activeProperty = processIface->second.find("Active");
87 if (activeProperty == processIface->second.cend())
88 {
89 BMCWEB_LOG_DEBUG << "Property Active not found";
90 return;
91 }
92
Gunnar Mills1214b7e2020-06-04 10:11:30 -050093 const bool* activeValue = std::get_if<bool>(&activeProperty->second);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +020094 if (!activeValue)
95 {
96 BMCWEB_LOG_DEBUG << "Value Active not found";
97 return;
98 }
99
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500100 const std::string* endpointIdValue =
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200101 std::get_if<std::string>(&endpointIdProperty->second);
102 if (endpointIdValue)
103 {
104 if (!endpointIdValue->empty())
105 {
106 // Proxy mode
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100107 aResp->res.jsonValue["Oem"]["OpenBMC"]["WebSocketEndpoint"] =
108 *endpointIdValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200109 aResp->res.jsonValue["TransferProtocolType"] = "OEM";
110 aResp->res.jsonValue["Inserted"] = *activeValue;
111 if (*activeValue == true)
112 {
113 aResp->res.jsonValue["ConnectedVia"] = "Applet";
114 }
115 }
116 else
117 {
118 // Legacy mode
Anna Platash9e319cf2020-11-17 10:18:31 +0100119 for (const auto& property : mountPointIface->second)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200120 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100121 if (property.first == "ImageURL")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200122 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100123 const std::string* imageUrlValue =
124 std::get_if<std::string>(&property.second);
125 if (imageUrlValue && !imageUrlValue->empty())
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100126 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100127 std::filesystem::path filePath = *imageUrlValue;
128 if (!filePath.has_filename())
129 {
130 // this will handle https share, which not
131 // necessarily has to have filename given.
132 aResp->res.jsonValue["ImageName"] = "";
133 }
134 else
135 {
136 aResp->res.jsonValue["ImageName"] =
137 filePath.filename();
138 }
Przemyslaw Czarnowskida4784d2020-11-06 09:58:25 +0100139
Anna Platash9e319cf2020-11-17 10:18:31 +0100140 aResp->res.jsonValue["Image"] = *imageUrlValue;
141 aResp->res.jsonValue["Inserted"] = *activeValue;
142 aResp->res.jsonValue["TransferProtocolType"] =
143 getTransferProtocolTypeFromUri(*imageUrlValue);
144
145 if (*activeValue == true)
146 {
147 aResp->res.jsonValue["ConnectedVia"] = "URI";
148 }
149 }
150 }
151 else if (property.first == "WriteProtected")
152 {
153 const bool* writeProtectedValue =
154 std::get_if<bool>(&property.second);
155 if (writeProtectedValue)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200156 {
Anna Platash9e319cf2020-11-17 10:18:31 +0100157 aResp->res.jsonValue["WriteProtected"] =
158 *writeProtectedValue;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200159 }
160 }
161 }
162 }
163 }
164}
165
166/**
167 * @brief Fill template for Virtual Media Item.
168 */
Ed Tanous22db1722021-06-09 10:53:51 -0700169inline nlohmann::json vmItemTemplate(const std::string& name,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500170 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200171{
172 nlohmann::json item;
Ed Tanous22db1722021-06-09 10:53:51 -0700173
174 std::string id = "/redfish/v1/Managers/";
175 id += name;
176 id += "/VirtualMedia/";
177 id += resName;
178 item["@odata.id"] = std::move(id);
179
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100180 item["@odata.type"] = "#VirtualMedia.v1_3_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200181 item["Name"] = "Virtual Removable Media";
182 item["Id"] = resName;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200183 item["WriteProtected"] = true;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200184 item["MediaTypes"] = {"CD", "USBStick"};
185 item["TransferMethod"] = "Stream";
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100186 item["Oem"]["OpenBMC"]["@odata.type"] =
187 "#OemVirtualMedia.v1_0_0.VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200188
189 return item;
190}
191
192/**
193 * @brief Fills collection data
194 */
Ed Tanous22db1722021-06-09 10:53:51 -0700195inline void getVmResourceList(std::shared_ptr<bmcweb::AsyncResp> aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500196 const std::string& service,
197 const std::string& name)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200198{
199 BMCWEB_LOG_DEBUG << "Get available Virtual Media resources.";
200 crow::connections::systemBus->async_method_call(
201 [name, aResp{std::move(aResp)}](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500202 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200203 if (ec)
204 {
205 BMCWEB_LOG_DEBUG << "DBUS response error";
206 return;
207 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500208 nlohmann::json& members = aResp->res.jsonValue["Members"];
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200209 members = nlohmann::json::array();
210
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500211 for (const auto& object : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200212 {
213 nlohmann::json item;
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000214 std::string path = object.first.filename();
215 if (path.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200216 {
217 continue;
218 }
219
Ed Tanous22db1722021-06-09 10:53:51 -0700220 std::string id = "/redfish/v1/Managers/";
221 id += name;
222 id += "/VirtualMedia/";
223 id += path;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200224
Ed Tanous22db1722021-06-09 10:53:51 -0700225 item["@odata.id"] = std::move(id);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200226 members.emplace_back(std::move(item));
227 }
228 aResp->res.jsonValue["Members@odata.count"] = members.size();
229 },
230 service, "/xyz/openbmc_project/VirtualMedia",
231 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
232}
233
234/**
235 * @brief Fills data for specific resource
236 */
Ed Tanous22db1722021-06-09 10:53:51 -0700237inline void getVmData(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500238 const std::string& service, const std::string& name,
239 const std::string& resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200240{
241 BMCWEB_LOG_DEBUG << "Get Virtual Media resource data.";
242
243 crow::connections::systemBus->async_method_call(
244 [resName, name, aResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500245 ManagedObjectType& subtree) {
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200246 if (ec)
247 {
248 BMCWEB_LOG_DEBUG << "DBUS response error";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200249
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200250 return;
251 }
252
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500253 for (auto& item : subtree)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200254 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000255 std::string thispath = item.first.filename();
256 if (thispath.empty())
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200257 {
258 continue;
259 }
260
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000261 if (thispath != resName)
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200262 {
263 continue;
264 }
265
Przemyslaw Czarnowski1a6258d2021-04-14 11:02:46 +0200266 // "Legacy"/"Proxy"
267 auto mode = item.first.parent_path();
268 // "VirtualMedia"
269 auto type = mode.parent_path();
270 if (mode.filename().empty() || type.filename().empty())
271 {
272 continue;
273 }
274
275 if (type.filename() != "VirtualMedia")
276 {
277 continue;
278 }
279
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200280 aResp->res.jsonValue = vmItemTemplate(name, resName);
Ed Tanous22db1722021-06-09 10:53:51 -0700281 std::string actionsId = "/redfish/v1/Managers/";
282 actionsId += name;
283 actionsId += "/VirtualMedia/";
284 actionsId += resName;
285 actionsId += "/Actions";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200286
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200287 // Check if dbus path is Legacy type
Przemyslaw Czarnowski1a6258d2021-04-14 11:02:46 +0200288 if (mode.filename() == "Legacy")
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200289 {
290 aResp->res.jsonValue["Actions"]["#VirtualMedia.InsertMedia"]
291 ["target"] =
Ed Tanous22db1722021-06-09 10:53:51 -0700292 actionsId + "/VirtualMedia.InsertMedia";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200293 }
294
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200295 vmParseInterfaceObject(item.second, aResp);
296
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200297 aResp->res.jsonValue["Actions"]["#VirtualMedia.EjectMedia"]
298 ["target"] =
Ed Tanous22db1722021-06-09 10:53:51 -0700299 actionsId + "/VirtualMedia.EjectMedia";
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200300
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200301 return;
302 }
303
304 messages::resourceNotFound(
Przemyslaw Czarnowskid04ba322020-01-21 12:41:56 +0100305 aResp->res, "#VirtualMedia.v1_3_0.VirtualMedia", resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +0200306 },
307 service, "/xyz/openbmc_project/VirtualMedia",
308 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
309}
310
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200311/**
Ed Tanous22db1722021-06-09 10:53:51 -0700312 * @brief Transfer protocols supported for InsertMedia action.
313 *
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200314 */
Ed Tanous22db1722021-06-09 10:53:51 -0700315enum class TransferProtocol
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200316{
Ed Tanous22db1722021-06-09 10:53:51 -0700317 https,
318 smb,
319 invalid
320};
321
322/**
323 * @brief Function extracts transfer protocol type from URI.
324 *
325 */
326inline std::optional<TransferProtocol>
327 getTransferProtocolFromUri(const std::string& imageUri)
328{
Ed Tanousd32c4fa2021-09-14 13:16:51 -0700329 boost::urls::error_code ec;
330 boost::urls::url_view url =
331 boost::urls::parse_uri(boost::string_view(imageUri), ec);
332 if (ec)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200333 {
Ed Tanousd32c4fa2021-09-14 13:16:51 -0700334 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100335 }
Ed Tanousd32c4fa2021-09-14 13:16:51 -0700336
337 boost::string_view scheme = url.scheme();
338 if (scheme == "smb")
Agata Olenderc6f4e012020-03-11 15:19:07 +0100339 {
Ed Tanousd32c4fa2021-09-14 13:16:51 -0700340 return TransferProtocol::smb;
341 }
342 if (scheme == "https")
343 {
344 return TransferProtocol::https;
345 }
346 if (!scheme.empty())
347 {
348 return TransferProtocol::invalid;
Agata Olenderc6f4e012020-03-11 15:19:07 +0100349 }
350
Ed Tanous22db1722021-06-09 10:53:51 -0700351 return {};
352}
353
354/**
355 * @brief Function convert transfer protocol from string param.
356 *
357 */
358inline std::optional<TransferProtocol> getTransferProtocolFromParam(
359 const std::optional<std::string>& transferProtocolType)
360{
361 if (transferProtocolType == std::nullopt)
Agata Olenderc6f4e012020-03-11 15:19:07 +0100362 {
Ed Tanous22db1722021-06-09 10:53:51 -0700363 return {};
Agata Olenderc6f4e012020-03-11 15:19:07 +0100364 }
365
Ed Tanous22db1722021-06-09 10:53:51 -0700366 if (*transferProtocolType == "CIFS")
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200367 {
Ed Tanous22db1722021-06-09 10:53:51 -0700368 return TransferProtocol::smb;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200369 }
370
Ed Tanous22db1722021-06-09 10:53:51 -0700371 if (*transferProtocolType == "HTTPS")
372 {
373 return TransferProtocol::https;
374 }
375
376 return TransferProtocol::invalid;
377}
378
379/**
380 * @brief Function extends URI with transfer protocol type.
381 *
382 */
383inline std::string
384 getUriWithTransferProtocol(const std::string& imageUri,
385 const TransferProtocol& transferProtocol)
386{
387 if (transferProtocol == TransferProtocol::smb)
388 {
389 return "smb://" + imageUri;
390 }
391
392 if (transferProtocol == TransferProtocol::https)
393 {
394 return "https://" + imageUri;
395 }
396
397 return imageUri;
398}
399
400/**
401 * @brief Function validate parameters of insert media request.
402 *
403 */
404inline bool
405 validateParams(crow::Response& res, std::string& imageUrl,
406 const std::optional<bool>& inserted,
407 const std::optional<std::string>& transferMethod,
408 const std::optional<std::string>& transferProtocolType)
409{
410 BMCWEB_LOG_DEBUG << "Validation started";
411 // required param imageUrl must not be empty
412 if (imageUrl.empty())
413 {
414 BMCWEB_LOG_ERROR << "Request action parameter Image is empty.";
415
416 messages::propertyValueFormatError(res, "<empty>", "Image");
417
418 return false;
419 }
420
421 // optional param inserted must be true
422 if ((inserted != std::nullopt) && (*inserted != true))
423 {
424 BMCWEB_LOG_ERROR
425 << "Request action optional parameter Inserted must be true.";
426
427 messages::actionParameterNotSupported(res, "Inserted", "InsertMedia");
428
429 return false;
430 }
431
432 // optional param transferMethod must be stream
433 if ((transferMethod != std::nullopt) && (*transferMethod != "Stream"))
434 {
435 BMCWEB_LOG_ERROR << "Request action optional parameter "
436 "TransferMethod must be Stream.";
437
438 messages::actionParameterNotSupported(res, "TransferMethod",
439 "InsertMedia");
440
441 return false;
442 }
443
444 std::optional<TransferProtocol> uriTransferProtocolType =
445 getTransferProtocolFromUri(imageUrl);
446
447 std::optional<TransferProtocol> paramTransferProtocolType =
448 getTransferProtocolFromParam(transferProtocolType);
449
450 // ImageUrl does not contain valid protocol type
451 if (*uriTransferProtocolType == TransferProtocol::invalid)
452 {
453 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
454 "contain specified protocol type from list: "
455 "(smb, https).";
456
457 messages::resourceAtUriInUnknownFormat(res, imageUrl);
458
459 return false;
460 }
461
462 // transferProtocolType should contain value from list
463 if (*paramTransferProtocolType == TransferProtocol::invalid)
464 {
465 BMCWEB_LOG_ERROR << "Request action parameter TransferProtocolType "
466 "must be provided with value from list: "
467 "(CIFS, HTTPS).";
468
469 messages::propertyValueNotInList(res, *transferProtocolType,
470 "TransferProtocolType");
471 return false;
472 }
473
474 // valid transfer protocol not provided either with URI nor param
475 if ((uriTransferProtocolType == std::nullopt) &&
476 (paramTransferProtocolType == std::nullopt))
477 {
478 BMCWEB_LOG_ERROR << "Request action parameter ImageUrl must "
479 "contain specified protocol type or param "
480 "TransferProtocolType must be provided.";
481
482 messages::resourceAtUriInUnknownFormat(res, imageUrl);
483
484 return false;
485 }
486
487 // valid transfer protocol provided both with URI and param
488 if ((paramTransferProtocolType != std::nullopt) &&
489 (uriTransferProtocolType != std::nullopt))
490 {
491 // check if protocol is the same for URI and param
492 if (*paramTransferProtocolType != *uriTransferProtocolType)
493 {
494 BMCWEB_LOG_ERROR << "Request action parameter "
495 "TransferProtocolType must contain the "
496 "same protocol type as protocol type "
497 "provided with param imageUrl.";
498
499 messages::actionParameterValueTypeError(res, *transferProtocolType,
500 "TransferProtocolType",
501 "InsertMedia");
502
503 return false;
504 }
505 }
506
507 // validation passed
508 // add protocol to URI if needed
509 if (uriTransferProtocolType == std::nullopt)
510 {
511 imageUrl =
512 getUriWithTransferProtocol(imageUrl, *paramTransferProtocolType);
513 }
514
515 return true;
516}
517
518template <typename T>
519static void secureCleanup(T& value)
520{
521 auto raw = const_cast<typename T::value_type*>(value.data());
522 explicit_bzero(raw, value.size() * sizeof(*raw));
523}
524
525class Credentials
526{
527 public:
528 Credentials(std::string&& user, std::string&& password) :
529 userBuf(std::move(user)), passBuf(std::move(password))
530 {}
531
532 ~Credentials()
533 {
534 secureCleanup(userBuf);
535 secureCleanup(passBuf);
536 }
537
538 const std::string& user()
539 {
540 return userBuf;
541 }
542
543 const std::string& password()
544 {
545 return passBuf;
546 }
547
548 Credentials() = delete;
549 Credentials(const Credentials&) = delete;
550 Credentials& operator=(const Credentials&) = delete;
551
552 private:
553 std::string userBuf;
554 std::string passBuf;
555};
556
557class CredentialsProvider
558{
559 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500560 template <typename T>
Ed Tanous22db1722021-06-09 10:53:51 -0700561 struct Deleter
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100562 {
Ed Tanous22db1722021-06-09 10:53:51 -0700563 void operator()(T* buff) const
564 {
565 if (buff)
566 {
567 secureCleanup(*buff);
568 delete buff;
569 }
570 }
571 };
572
573 using Buffer = std::vector<char>;
574 using SecureBuffer = std::unique_ptr<Buffer, Deleter<Buffer>>;
575 // Using explicit definition instead of std::function to avoid implicit
576 // conversions eg. stack copy instead of reference
577 using FormatterFunc = void(const std::string& username,
578 const std::string& password, Buffer& dest);
579
580 CredentialsProvider(std::string&& user, std::string&& password) :
581 credentials(std::move(user), std::move(password))
582 {}
583
584 const std::string& user()
585 {
586 return credentials.user();
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100587 }
588
Ed Tanous22db1722021-06-09 10:53:51 -0700589 const std::string& password()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100590 {
Ed Tanous22db1722021-06-09 10:53:51 -0700591 return credentials.password();
592 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100593
Ed Tanous22db1722021-06-09 10:53:51 -0700594 SecureBuffer pack(FormatterFunc formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100595 {
Ed Tanous22db1722021-06-09 10:53:51 -0700596 SecureBuffer packed{new Buffer{}};
597 if (formatter)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100598 {
Ed Tanous22db1722021-06-09 10:53:51 -0700599 formatter(credentials.user(), credentials.password(), *packed);
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100600 }
601
Ed Tanous22db1722021-06-09 10:53:51 -0700602 return packed;
603 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100604
Ed Tanous22db1722021-06-09 10:53:51 -0700605 private:
606 Credentials credentials;
607};
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100608
Ed Tanous22db1722021-06-09 10:53:51 -0700609// Wrapper for boost::async_pipe ensuring proper pipe cleanup
610template <typename Buffer>
611class Pipe
612{
613 public:
614 using unix_fd = sdbusplus::message::unix_fd;
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100615
Ed Tanous22db1722021-06-09 10:53:51 -0700616 Pipe(boost::asio::io_context& io, Buffer&& buffer) :
617 impl(io), buffer{std::move(buffer)}
618 {}
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100619
Ed Tanous22db1722021-06-09 10:53:51 -0700620 ~Pipe()
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100621 {
Ed Tanous22db1722021-06-09 10:53:51 -0700622 // Named pipe needs to be explicitly removed
623 impl.close();
624 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100625
Ed Tanous22db1722021-06-09 10:53:51 -0700626 unix_fd fd()
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200627 {
Ed Tanous22db1722021-06-09 10:53:51 -0700628 return unix_fd{impl.native_source()};
629 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100630
Ed Tanous22db1722021-06-09 10:53:51 -0700631 template <typename WriteHandler>
632 void asyncWrite(WriteHandler&& handler)
633 {
634 impl.async_write_some(data(), std::forward<WriteHandler>(handler));
635 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100636
Ed Tanous22db1722021-06-09 10:53:51 -0700637 private:
638 // Specialization for pointer types
639 template <typename B = Buffer>
640 typename std::enable_if<boost::has_dereference<B>::value,
641 boost::asio::const_buffer>::type
642 data()
643 {
644 return boost::asio::buffer(*buffer);
645 }
646
647 template <typename B = Buffer>
648 typename std::enable_if<!boost::has_dereference<B>::value,
649 boost::asio::const_buffer>::type
650 data()
651 {
652 return boost::asio::buffer(buffer);
653 }
654
655 const std::string name;
656 boost::process::async_pipe impl;
657 Buffer buffer;
658};
659
660/**
661 * @brief Function transceives data with dbus directly.
662 *
663 * All BMC state properties will be retrieved before sending reset request.
664 */
665inline void doMountVmLegacy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
666 const std::string& service, const std::string& name,
667 const std::string& imageUrl, const bool rw,
668 std::string&& userName, std::string&& password)
669{
670 using SecurePipe = Pipe<CredentialsProvider::SecureBuffer>;
671 constexpr const size_t secretLimit = 1024;
672
673 std::shared_ptr<SecurePipe> secretPipe;
674 std::variant<int, SecurePipe::unix_fd> unixFd = -1;
675
676 if (!userName.empty() || !password.empty())
677 {
678 // Encapsulate in safe buffer
679 CredentialsProvider credentials(std::move(userName),
680 std::move(password));
681
682 // Payload must contain data + NULL delimiters
683 if (credentials.user().size() + credentials.password().size() + 2 >
684 secretLimit)
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100685 {
Ed Tanous22db1722021-06-09 10:53:51 -0700686 BMCWEB_LOG_ERROR << "Credentials too long to handle";
687 messages::unrecognizedRequestBody(asyncResp->res);
688 return;
689 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100690
Ed Tanous22db1722021-06-09 10:53:51 -0700691 // Pack secret
692 auto secret = credentials.pack(
693 [](const auto& user, const auto& pass, auto& buff) {
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100694 std::copy(user.begin(), user.end(), std::back_inserter(buff));
695 buff.push_back('\0');
696 std::copy(pass.begin(), pass.end(), std::back_inserter(buff));
697 buff.push_back('\0');
698 });
699
Ed Tanous22db1722021-06-09 10:53:51 -0700700 // Open pipe
701 secretPipe = std::make_shared<SecurePipe>(
702 crow::connections::systemBus->get_io_context(), std::move(secret));
703 unixFd = secretPipe->fd();
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100704
Ed Tanous22db1722021-06-09 10:53:51 -0700705 // Pass secret over pipe
706 secretPipe->asyncWrite(
707 [asyncResp](const boost::system::error_code& ec, std::size_t) {
708 if (ec)
709 {
710 BMCWEB_LOG_ERROR << "Failed to pass secret: " << ec;
711 messages::internalError(asyncResp->res);
712 }
713 });
714 }
Adrian Ambrożewicz988fb7b2020-01-13 18:52:46 +0100715
Ed Tanous22db1722021-06-09 10:53:51 -0700716 crow::connections::systemBus->async_method_call(
717 [asyncResp, secretPipe](const boost::system::error_code ec,
718 bool success) {
719 if (ec)
720 {
721 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
722 messages::internalError(asyncResp->res);
723 }
724 else if (!success)
725 {
726 BMCWEB_LOG_ERROR << "Service responded with error";
727 messages::generalError(asyncResp->res);
728 }
729 },
730 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
731 "xyz.openbmc_project.VirtualMedia.Legacy", "Mount", imageUrl, rw,
732 unixFd);
733}
734
735/**
736 * @brief Function transceives data with dbus directly.
737 *
738 * All BMC state properties will be retrieved before sending reset request.
739 */
740inline void doVmAction(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
741 const std::string& service, const std::string& name,
742 bool legacy)
743{
744
745 // Legacy mount requires parameter with image
746 if (legacy)
747 {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100748 crow::connections::systemBus->async_method_call(
Ed Tanous22db1722021-06-09 10:53:51 -0700749 [asyncResp](const boost::system::error_code ec) {
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100750 if (ec)
751 {
752 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
Ed Tanous22db1722021-06-09 10:53:51 -0700753
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100754 messages::internalError(asyncResp->res);
Ed Tanous22db1722021-06-09 10:53:51 -0700755 return;
Adrian Ambrożewiczd6da5be2020-01-13 18:31:01 +0100756 }
757 },
758 service, "/xyz/openbmc_project/VirtualMedia/Legacy/" + name,
Ed Tanous22db1722021-06-09 10:53:51 -0700759 "xyz.openbmc_project.VirtualMedia.Legacy", "Unmount");
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200760 }
Ed Tanous22db1722021-06-09 10:53:51 -0700761 else // proxy
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200762 {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200763 crow::connections::systemBus->async_method_call(
Ed Tanous22db1722021-06-09 10:53:51 -0700764 [asyncResp](const boost::system::error_code ec) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200765 if (ec)
766 {
Ed Tanous22db1722021-06-09 10:53:51 -0700767 BMCWEB_LOG_ERROR << "Bad D-Bus request error: " << ec;
768
zhanghch058d1b46d2021-04-01 11:18:24 +0800769 messages::internalError(asyncResp->res);
Ed Tanous22db1722021-06-09 10:53:51 -0700770 return;
771 }
772 },
773 service, "/xyz/openbmc_project/VirtualMedia/Proxy/" + name,
774 "xyz.openbmc_project.VirtualMedia.Proxy", "Unmount");
775 }
776}
777
778inline void requestNBDVirtualMediaRoutes(App& app)
779{
780 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
781 "VirtualMedia.InsertMedia")
Ed Tanoused398212021-06-09 17:05:54 -0700782 .privileges(redfish::privileges::postVirtualMedia)
Ed Tanous22db1722021-06-09 10:53:51 -0700783 .methods(boost::beast::http::verb::post)(
784 [](const crow::Request& req,
785 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
786 const std::string& name, const std::string& resName) {
787 if (name != "bmc")
788 {
789 messages::resourceNotFound(asyncResp->res,
790 "VirtualMedia.Insert", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200791
792 return;
793 }
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200794
795 crow::connections::systemBus->async_method_call(
Ed Tanous22db1722021-06-09 10:53:51 -0700796 [asyncResp, req,
797 resName](const boost::system::error_code ec,
798 const GetObjectType& getObjectType) {
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200799 if (ec)
800 {
Ed Tanous22db1722021-06-09 10:53:51 -0700801 BMCWEB_LOG_ERROR
802 << "ObjectMapper::GetObject call failed: "
803 << ec;
804 messages::internalError(asyncResp->res);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200805
806 return;
807 }
Ed Tanous22db1722021-06-09 10:53:51 -0700808 std::string service = getObjectType.begin()->first;
809 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200810
Ed Tanous22db1722021-06-09 10:53:51 -0700811 crow::connections::systemBus->async_method_call(
812 [service, resName, req,
813 asyncResp](const boost::system::error_code ec,
814 ManagedObjectType& subtree) {
815 if (ec)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200816 {
Ed Tanous22db1722021-06-09 10:53:51 -0700817 BMCWEB_LOG_DEBUG << "DBUS response error";
818
819 return;
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200820 }
821
Ed Tanous22db1722021-06-09 10:53:51 -0700822 for (const auto& object : subtree)
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200823 {
Ed Tanous22db1722021-06-09 10:53:51 -0700824 const std::string& path =
825 static_cast<const std::string&>(
826 object.first);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200827
Ed Tanous22db1722021-06-09 10:53:51 -0700828 std::size_t lastIndex = path.rfind('/');
829 if (lastIndex == std::string::npos)
830 {
831 continue;
832 }
833
834 lastIndex += 1;
835
836 if (path.substr(lastIndex) == resName)
837 {
838 lastIndex = path.rfind("Proxy");
839 if (lastIndex != std::string::npos)
840 {
841 // Not possible in proxy mode
842 BMCWEB_LOG_DEBUG
843 << "InsertMedia not "
844 "allowed in proxy mode";
845 messages::resourceNotFound(
846 asyncResp->res,
847 "VirtualMedia.InsertMedia",
848 resName);
849
850 return;
851 }
852
853 lastIndex = path.rfind("Legacy");
854 if (lastIndex == std::string::npos)
855 {
856 continue;
857 }
858
859 // Legacy mode
860 std::string imageUrl;
861 std::optional<std::string> userName;
862 std::optional<std::string> password;
863 std::optional<std::string>
864 transferMethod;
865 std::optional<std::string>
866 transferProtocolType;
867 std::optional<bool> writeProtected =
868 true;
869 std::optional<bool> inserted;
870
871 // Read obligatory parameters (url of
872 // image)
873 if (!json_util::readJson(
874 req, asyncResp->res, "Image",
875 imageUrl, "WriteProtected",
876 writeProtected, "UserName",
877 userName, "Password", password,
878 "Inserted", inserted,
879 "TransferMethod",
880 transferMethod,
881 "TransferProtocolType",
882 transferProtocolType))
883 {
884 BMCWEB_LOG_DEBUG
885 << "Image is not provided";
886 return;
887 }
888
889 bool paramsValid = validateParams(
890 asyncResp->res, imageUrl, inserted,
891 transferMethod,
892 transferProtocolType);
893
894 if (paramsValid == false)
895 {
896 return;
897 }
898
899 // manager is irrelevant for
900 // VirtualMedia dbus calls
901 doMountVmLegacy(asyncResp, service,
902 resName, imageUrl,
903 !(*writeProtected),
904 std::move(*userName),
905 std::move(*password));
906
907 return;
908 }
909 }
910 BMCWEB_LOG_DEBUG << "Parent item not found";
911 messages::resourceNotFound(
912 asyncResp->res, "VirtualMedia", resName);
913 },
914 service, "/xyz/openbmc_project/VirtualMedia",
915 "org.freedesktop.DBus.ObjectManager",
916 "GetManagedObjects");
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200917 },
Ed Tanous22db1722021-06-09 10:53:51 -0700918 "xyz.openbmc_project.ObjectMapper",
919 "/xyz/openbmc_project/object_mapper",
920 "xyz.openbmc_project.ObjectMapper", "GetObject",
921 "/xyz/openbmc_project/VirtualMedia",
922 std::array<const char*, 0>());
923 });
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200924
Ed Tanous22db1722021-06-09 10:53:51 -0700925 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/Actions/"
926 "VirtualMedia.EjectMedia")
Ed Tanoused398212021-06-09 17:05:54 -0700927 .privileges(redfish::privileges::postVirtualMedia)
Ed Tanous22db1722021-06-09 10:53:51 -0700928 .methods(boost::beast::http::verb::post)(
929 [](const crow::Request& req,
930 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
931 const std::string& name, const std::string& resName) {
932 if (name != "bmc")
933 {
934 messages::resourceNotFound(asyncResp->res,
935 "VirtualMedia.Eject", resName);
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200936
Ed Tanous22db1722021-06-09 10:53:51 -0700937 return;
938 }
Przemyslaw Czarnowskie13c2762019-09-02 17:32:43 +0200939
Ed Tanous22db1722021-06-09 10:53:51 -0700940 crow::connections::systemBus->async_method_call(
941 [asyncResp, req,
942 resName](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500943 const GetObjectType& getObjectType) {
Ed Tanous22db1722021-06-09 10:53:51 -0700944 if (ec)
945 {
946 BMCWEB_LOG_ERROR
947 << "ObjectMapper::GetObject call failed: "
948 << ec;
949 messages::internalError(asyncResp->res);
950
951 return;
952 }
953 std::string service = getObjectType.begin()->first;
954 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
955
956 crow::connections::systemBus->async_method_call(
957 [resName, service, req, asyncResp{asyncResp}](
958 const boost::system::error_code ec,
959 ManagedObjectType& subtree) {
960 if (ec)
961 {
962 BMCWEB_LOG_DEBUG << "DBUS response error";
963
964 return;
965 }
966
967 for (const auto& object : subtree)
968 {
969 const std::string& path =
970 static_cast<const std::string&>(
971 object.first);
972
973 std::size_t lastIndex = path.rfind('/');
974 if (lastIndex == std::string::npos)
975 {
976 continue;
977 }
978
979 lastIndex += 1;
980
981 if (path.substr(lastIndex) == resName)
982 {
983 lastIndex = path.rfind("Proxy");
984 if (lastIndex != std::string::npos)
985 {
986 // Proxy mode
987 doVmAction(asyncResp, service,
988 resName, false);
989 }
990
991 lastIndex = path.rfind("Legacy");
992 if (lastIndex != std::string::npos)
993 {
994 // Legacy mode
995 doVmAction(asyncResp, service,
996 resName, true);
997 }
998
999 return;
1000 }
1001 }
1002 BMCWEB_LOG_DEBUG << "Parent item not found";
1003 messages::resourceNotFound(
1004 asyncResp->res, "VirtualMedia", resName);
1005 },
1006 service, "/xyz/openbmc_project/VirtualMedia",
1007 "org.freedesktop.DBus.ObjectManager",
1008 "GetManagedObjects");
1009 },
1010 "xyz.openbmc_project.ObjectMapper",
1011 "/xyz/openbmc_project/object_mapper",
1012 "xyz.openbmc_project.ObjectMapper", "GetObject",
1013 "/xyz/openbmc_project/VirtualMedia",
1014 std::array<const char*, 0>());
1015 });
1016 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/")
Ed Tanoused398212021-06-09 17:05:54 -07001017 .privileges(redfish::privileges::getVirtualMediaCollection)
Ed Tanous22db1722021-06-09 10:53:51 -07001018 .methods(boost::beast::http::verb::get)(
1019 [](const crow::Request& /* req */,
1020 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1021 const std::string& name) {
1022 if (name != "bmc")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001023 {
Ed Tanous22db1722021-06-09 10:53:51 -07001024 messages::resourceNotFound(asyncResp->res, "VirtualMedia",
1025 name);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001026
1027 return;
1028 }
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001029
Ed Tanous22db1722021-06-09 10:53:51 -07001030 asyncResp->res.jsonValue["@odata.type"] =
1031 "#VirtualMediaCollection.VirtualMediaCollection";
1032 asyncResp->res.jsonValue["Name"] = "Virtual Media Services";
1033 asyncResp->res.jsonValue["@odata.id"] =
1034 "/redfish/v1/Managers/" + name + "/VirtualMedia";
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001035
Ed Tanous22db1722021-06-09 10:53:51 -07001036 crow::connections::systemBus->async_method_call(
1037 [asyncResp, name](const boost::system::error_code ec,
1038 const GetObjectType& getObjectType) {
1039 if (ec)
1040 {
1041 BMCWEB_LOG_ERROR
1042 << "ObjectMapper::GetObject call failed: "
1043 << ec;
1044 messages::internalError(asyncResp->res);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001045
Ed Tanous22db1722021-06-09 10:53:51 -07001046 return;
1047 }
1048 std::string service = getObjectType.begin()->first;
1049 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001050
Ed Tanous22db1722021-06-09 10:53:51 -07001051 getVmResourceList(asyncResp, service, name);
1052 },
1053 "xyz.openbmc_project.ObjectMapper",
1054 "/xyz/openbmc_project/object_mapper",
1055 "xyz.openbmc_project.ObjectMapper", "GetObject",
1056 "/xyz/openbmc_project/VirtualMedia",
1057 std::array<const char*, 0>());
1058 });
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001059
Ed Tanous22db1722021-06-09 10:53:51 -07001060 BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/VirtualMedia/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001061 .privileges(redfish::privileges::getVirtualMedia)
Ed Tanous22db1722021-06-09 10:53:51 -07001062 .methods(boost::beast::http::verb::get)(
1063 [](const crow::Request& /* req */,
1064 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1065 const std::string& name, const std::string& resName) {
1066 if (name != "bmc")
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001067 {
Ed Tanous22db1722021-06-09 10:53:51 -07001068 messages::resourceNotFound(asyncResp->res, "VirtualMedia",
1069 resName);
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001070
1071 return;
1072 }
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001073
Ed Tanous22db1722021-06-09 10:53:51 -07001074 crow::connections::systemBus->async_method_call(
1075 [asyncResp, name,
1076 resName](const boost::system::error_code ec,
1077 const GetObjectType& getObjectType) {
1078 if (ec)
1079 {
1080 BMCWEB_LOG_ERROR
1081 << "ObjectMapper::GetObject call failed: "
1082 << ec;
1083 messages::internalError(asyncResp->res);
1084
1085 return;
1086 }
1087 std::string service = getObjectType.begin()->first;
1088 BMCWEB_LOG_DEBUG << "GetObjectType: " << service;
1089
1090 getVmData(asyncResp, service, name, resName);
1091 },
1092 "xyz.openbmc_project.ObjectMapper",
1093 "/xyz/openbmc_project/object_mapper",
1094 "xyz.openbmc_project.ObjectMapper", "GetObject",
1095 "/xyz/openbmc_project/VirtualMedia",
1096 std::array<const char*, 0>());
1097 });
1098}
Przemyslaw Czarnowski107077d2019-07-11 10:16:43 +02001099
1100} // namespace redfish