blob: d17ee28826904d3b08b635373e69192b3727dff4 [file] [log] [blame]
Ed Tanous40e9b922024-09-10 13:50:16 -07001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -07003#pragma once
4
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08005#include "app.hpp"
6#include "async_resp.hpp"
7#include "dbus_utility.hpp"
8#include "error_messages.hpp"
9#include "utils/collection.hpp"
10#include "utils/hex_utils.hpp"
11#include "utils/json_utils.hpp"
12
George Liue99073f2022-12-09 11:06:16 +080013#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070014#include <boost/url/format.hpp>
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -070015#include <nlohmann/json.hpp>
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070016
George Liu7a1dbc42022-12-07 16:03:22 +080017#include <array>
18#include <string_view>
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070019#include <vector>
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -070020
21namespace crow
22{
23namespace google_api
24{
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070025
Nan Zhou30aacdd2022-07-03 05:02:36 +000026inline void
27 handleGoogleV1Get(const crow::Request& /*req*/,
28 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070029{
30 asyncResp->res.jsonValue["@odata.type"] =
31 "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot";
32 asyncResp->res.jsonValue["@odata.id"] = "/google/v1";
33 asyncResp->res.jsonValue["Id"] = "Google Rest RootService";
34 asyncResp->res.jsonValue["Name"] = "Google Service Root";
35 asyncResp->res.jsonValue["Version"] = "1.0.0";
36 asyncResp->res.jsonValue["RootOfTrustCollection"]["@odata.id"] =
Nan Zhoucd027592022-07-03 05:18:29 +000037 "/google/v1/RootOfTrustCollection";
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070038}
39
Nan Zhou30aacdd2022-07-03 05:02:36 +000040inline void handleRootOfTrustCollectionGet(
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070041 const crow::Request& /*req*/,
42 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
43{
Nan Zhoucd027592022-07-03 05:18:29 +000044 asyncResp->res.jsonValue["@odata.id"] = "/google/v1/RootOfTrustCollection";
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070045 asyncResp->res.jsonValue["@odata.type"] =
46 "#RootOfTrustCollection.RootOfTrustCollection";
George Liu7a1dbc42022-12-07 16:03:22 +080047 const std::array<std::string_view, 1> interfaces{
48 "xyz.openbmc_project.Control.Hoth"};
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070049 redfish::collection_util::getCollectionMembers(
Willy Tuae9031f2022-09-27 05:48:07 +000050 asyncResp, boost::urls::url("/google/v1/RootOfTrustCollection"),
George Liu7a1dbc42022-12-07 16:03:22 +080051 interfaces, "/xyz/openbmc_project");
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070052}
53
54// Helper struct to identify a resolved D-Bus object interface
55struct ResolvedEntity
56{
57 std::string id;
58 std::string service;
59 std::string object;
Nan Zhou16a55352022-07-03 05:06:08 +000060 std::string interface;
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070061};
62
63using ResolvedEntityHandler = std::function<void(
64 const std::string&, const std::shared_ptr<bmcweb::AsyncResp>&,
65 const ResolvedEntity&)>;
66
Nan Zhou30aacdd2022-07-03 05:02:36 +000067inline void hothGetSubtreeCallback(
68 const std::string& command,
69 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
70 const std::string& rotId, const ResolvedEntityHandler& entityHandler,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080071 const boost::system::error_code& ec,
Nan Zhou30aacdd2022-07-03 05:02:36 +000072 const dbus::utility::MapperGetSubTreeResponse& subtree)
73{
74 if (ec)
75 {
76 redfish::messages::internalError(asyncResp->res);
77 return;
78 }
Nan Zhou5600f022022-07-03 16:22:38 +000079 for (const auto& [path, services] : subtree)
Nan Zhou30aacdd2022-07-03 05:02:36 +000080 {
Nan Zhou5600f022022-07-03 16:22:38 +000081 sdbusplus::message::object_path objPath(path);
82 if (objPath.filename() != rotId || services.empty())
Nan Zhou30aacdd2022-07-03 05:02:36 +000083 {
84 continue;
85 }
86
Nan Zhoucd027592022-07-03 05:18:29 +000087 ResolvedEntity resolvedEntity = {
88 .id = rotId,
Nan Zhou5600f022022-07-03 16:22:38 +000089 .service = services[0].first,
90 .object = path,
Nan Zhoucd027592022-07-03 05:18:29 +000091 .interface = "xyz.openbmc_project.Control.Hoth"};
Nan Zhou30aacdd2022-07-03 05:02:36 +000092 entityHandler(command, asyncResp, resolvedEntity);
93 return;
94 }
95
96 // Couldn't find an object with that name. return an error
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +080097 redfish::messages::resourceNotFound(asyncResp->res, "RootOfTrust", rotId);
Nan Zhou30aacdd2022-07-03 05:02:36 +000098}
99
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700100inline void resolveRoT(const std::string& command,
101 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
102 const std::string& rotId,
103 ResolvedEntityHandler&& entityHandler)
104{
George Liu7a1dbc42022-12-07 16:03:22 +0800105 constexpr std::array<std::string_view, 1> hothIfaces = {
Nan Zhoucd027592022-07-03 05:18:29 +0000106 "xyz.openbmc_project.Control.Hoth"};
George Liue99073f2022-12-09 11:06:16 +0800107 dbus::utility::getSubTree(
108 "/xyz/openbmc_project", 0, hothIfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700109 [command, asyncResp, rotId, entityHandler{std::move(entityHandler)}](
George Liue99073f2022-12-09 11:06:16 +0800110 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700111 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400112 hothGetSubtreeCallback(command, asyncResp, rotId, entityHandler, ec,
113 subtree);
114 });
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700115}
116
117inline void populateRootOfTrustEntity(
118 const std::string& /*unused*/,
119 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
120 const ResolvedEntity& resolvedEntity)
121{
122 asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700123 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
124 "/google/v1/RootOfTrustCollection/{}", resolvedEntity.id);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700125
126 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
127 asyncResp->res.jsonValue["Id"] = resolvedEntity.id;
128 // Need to fix this later to a stabler property.
129 asyncResp->res.jsonValue["Name"] = resolvedEntity.id;
130 asyncResp->res.jsonValue["Description"] = "Google Root Of Trust";
131 asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] =
132 "/google/v1/RootOfTrustCollection/" + resolvedEntity.id +
133 "/Actions/RootOfTrust.SendCommand";
134
135 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
136 resolvedEntity.id;
137 asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] =
138 "Embedded";
139}
140
Nan Zhou30aacdd2022-07-03 05:02:36 +0000141inline void
142 handleRootOfTrustGet(const crow::Request& /*req*/,
143 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
144 const std::string& param)
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700145{
Nan Zhou30aacdd2022-07-03 05:02:36 +0000146 std::string emptyCommand;
147 resolveRoT(emptyCommand, asyncResp, param, populateRootOfTrustEntity);
148}
149
150inline void
151 invocationCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800152 const boost::system::error_code& ec,
Nan Zhou30aacdd2022-07-03 05:02:36 +0000153 const std::vector<uint8_t>& responseBytes)
154{
155 if (ec)
156 {
Ed Tanous62598e32023-07-17 17:06:25 -0700157 BMCWEB_LOG_ERROR("RootOfTrust.Actions.SendCommand failed: {}",
158 ec.message());
Nan Zhou30aacdd2022-07-03 05:02:36 +0000159 redfish::messages::internalError(asyncResp->res);
160 return;
161 }
162
163 asyncResp->res.jsonValue["CommandResponse"] =
164 bytesToHexString(responseBytes);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700165}
166
167inline void
168 invokeRoTCommand(const std::string& command,
169 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
170 const ResolvedEntity& resolvedEntity)
171{
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700172 std::vector<uint8_t> bytes = hexStringToBytes(command);
173 if (bytes.empty())
174 {
Ed Tanous62598e32023-07-17 17:06:25 -0700175 BMCWEB_LOG_DEBUG("Invalid command: {}", command);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700176 redfish::messages::actionParameterValueTypeError(command, "Command",
177 "SendCommand");
178 return;
179 }
180
181 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800182 [asyncResp{asyncResp}](const boost::system::error_code& ec,
Nan Zhou30aacdd2022-07-03 05:02:36 +0000183 const std::vector<uint8_t>& responseBytes) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400184 invocationCallback(asyncResp, ec, responseBytes);
185 },
Nan Zhou30aacdd2022-07-03 05:02:36 +0000186 resolvedEntity.service, resolvedEntity.object, resolvedEntity.interface,
187 "SendHostCommand", bytes);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700188}
189
Nan Zhou30aacdd2022-07-03 05:02:36 +0000190inline void handleRoTSendCommandPost(
191 const crow::Request& request,
192 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
193 const std::string& rotId)
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700194{
195 std::string command;
196 if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command",
197 command))
198 {
Ed Tanous62598e32023-07-17 17:06:25 -0700199 BMCWEB_LOG_DEBUG("Missing property Command.");
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700200 redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand",
201 "Command");
202 return;
203 }
204
205 resolveRoT(command, asyncResp, rotId, invokeRoTCommand);
206}
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -0700207
208inline void requestRoutes(App& app)
209{
210 BMCWEB_ROUTE(app, "/google/v1/")
Nan Zhou30aacdd2022-07-03 05:02:36 +0000211 .methods(boost::beast::http::verb::get)(handleGoogleV1Get);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700212
213 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection")
214 .privileges({{"ConfigureManager"}})
Nan Zhou30aacdd2022-07-03 05:02:36 +0000215 .methods(boost::beast::http::verb::get)(handleRootOfTrustCollectionGet);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700216
217 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/<str>")
218 .privileges({{"ConfigureManager"}})
Nan Zhou30aacdd2022-07-03 05:02:36 +0000219 .methods(boost::beast::http::verb::get)(handleRootOfTrustGet);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700220
221 BMCWEB_ROUTE(
222 app,
223 "/google/v1/RootOfTrustCollection/<str>/Actions/RootOfTrust.SendCommand")
224 .privileges({{"ConfigureManager"}})
Nan Zhou30aacdd2022-07-03 05:02:36 +0000225 .methods(boost::beast::http::verb::post)(handleRoTSendCommandPost);
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -0700226}
227
228} // namespace google_api
229} // namespace crow