blob: 441ddcf509fa4f21feeee2521c69f2fbf5c6c7fe [file] [log] [blame]
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -07001#pragma once
2
3#include <app.hpp>
4#include <async_resp.hpp>
Jiaqing Zhaob6a55182022-05-20 11:47:46 +08005#include <dbus_utility.hpp>
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -07006#include <error_messages.hpp>
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -07007#include <nlohmann/json.hpp>
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -07008#include <utils/collection.hpp>
9#include <utils/hex_utils.hpp>
10#include <utils/json_utils.hpp>
11
12#include <vector>
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -070013
14namespace crow
15{
16namespace google_api
17{
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070018constexpr const char* hothSearchPath = "/xyz/openbmc_project";
19constexpr const char* hothInterface = "xyz.openbmc_project.Control.Hoth";
20constexpr const char* rotCollectionPrefix = "/google/v1/RootOfTrustCollection";
21
22inline void getGoogleV1(const crow::Request& /*req*/,
23 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
24{
25 asyncResp->res.jsonValue["@odata.type"] =
26 "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot";
27 asyncResp->res.jsonValue["@odata.id"] = "/google/v1";
28 asyncResp->res.jsonValue["Id"] = "Google Rest RootService";
29 asyncResp->res.jsonValue["Name"] = "Google Service Root";
30 asyncResp->res.jsonValue["Version"] = "1.0.0";
31 asyncResp->res.jsonValue["RootOfTrustCollection"]["@odata.id"] =
32 rotCollectionPrefix;
33}
34
35inline void getRootOfTrustCollection(
36 const crow::Request& /*req*/,
37 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
38{
39 asyncResp->res.jsonValue["@odata.id"] = rotCollectionPrefix;
40 asyncResp->res.jsonValue["@odata.type"] =
41 "#RootOfTrustCollection.RootOfTrustCollection";
42 redfish::collection_util::getCollectionMembers(
43 asyncResp, rotCollectionPrefix, std::vector<const char*>{hothInterface},
44 hothSearchPath);
45}
46
47// Helper struct to identify a resolved D-Bus object interface
48struct ResolvedEntity
49{
50 std::string id;
51 std::string service;
52 std::string object;
53 const char* interface;
54};
55
56using ResolvedEntityHandler = std::function<void(
57 const std::string&, const std::shared_ptr<bmcweb::AsyncResp>&,
58 const ResolvedEntity&)>;
59
60inline void resolveRoT(const std::string& command,
61 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
62 const std::string& rotId,
63 ResolvedEntityHandler&& entityHandler)
64{
65 auto validateFunc = [command, asyncResp, rotId,
66 entityHandler{std::forward<ResolvedEntityHandler>(
67 entityHandler)}](
68 const boost::system::error_code ec,
Jiaqing Zhaob6a55182022-05-20 11:47:46 +080069 const dbus::utility::MapperGetSubTreeResponse&
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070070 subtree) {
71 if (ec)
72 {
73 redfish::messages::internalError(asyncResp->res);
74 return;
75 }
76 // Iterate over all retrieved ObjectPaths.
77 for (const std::pair<
78 std::string,
79 std::vector<std::pair<std::string, std::vector<std::string>>>>&
80 object : subtree)
81 {
82 sdbusplus::message::object_path objPath(object.first);
83 if (objPath.filename() != rotId || object.second.empty())
84 {
85 continue;
86 }
87
88 ResolvedEntity resolvedEntity = {.id = rotId,
89 .service = object.second[0].first,
90 .object = object.first,
91 .interface = hothInterface};
92 entityHandler(command, asyncResp, resolvedEntity);
93 return;
94 }
95
96 // Couldn't find an object with that name. return an error
97 redfish::messages::resourceNotFound(
98 asyncResp->res, "#RootOfTrust.v1_0_0.RootOfTrust", rotId);
99 };
100
101 std::array<std::string, 1> hothIfaces = {hothInterface};
102 crow::connections::systemBus->async_method_call(
103 validateFunc, "xyz.openbmc_project.ObjectMapper",
104 "/xyz/openbmc_project/object_mapper",
105 "xyz.openbmc_project.ObjectMapper", "GetSubTree", hothSearchPath,
106 /*depth=*/0, hothIfaces);
107}
108
109inline void populateRootOfTrustEntity(
110 const std::string& /*unused*/,
111 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
112 const ResolvedEntity& resolvedEntity)
113{
114 asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust";
115 asyncResp->res.jsonValue["@odata.id"] =
116 "/google/v1/RootOfTrustCollection/" + resolvedEntity.id;
117
118 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
119 asyncResp->res.jsonValue["Id"] = resolvedEntity.id;
120 // Need to fix this later to a stabler property.
121 asyncResp->res.jsonValue["Name"] = resolvedEntity.id;
122 asyncResp->res.jsonValue["Description"] = "Google Root Of Trust";
123 asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] =
124 "/google/v1/RootOfTrustCollection/" + resolvedEntity.id +
125 "/Actions/RootOfTrust.SendCommand";
126
127 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
128 resolvedEntity.id;
129 asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] =
130 "Embedded";
131}
132
133inline void getRootOfTrust(const crow::Request& /*unused*/,
134 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
135 const std::string& param)
136{
137 resolveRoT("" /*Empty command*/, asyncResp, param,
138 populateRootOfTrustEntity);
139}
140
141inline void
142 invokeRoTCommand(const std::string& command,
143 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
144 const ResolvedEntity& resolvedEntity)
145{
146 auto handleFunc = [asyncResp](const boost::system::error_code ec,
147 std::vector<uint8_t>& responseBytes) {
148 if (ec)
149 {
150 BMCWEB_LOG_ERROR << "RootOfTrust.Actions.SendCommand failed: "
151 << ec.message();
152 redfish::messages::internalError(asyncResp->res);
153 return;
154 }
155
156 asyncResp->res.jsonValue["CommandResponse"] =
157 bytesToHexString(responseBytes);
158 };
159 std::vector<uint8_t> bytes = hexStringToBytes(command);
160 if (bytes.empty())
161 {
162 BMCWEB_LOG_DEBUG << "Invalid command: " << command;
163 redfish::messages::actionParameterValueTypeError(command, "Command",
164 "SendCommand");
165 return;
166 }
167
168 crow::connections::systemBus->async_method_call(
169 handleFunc, resolvedEntity.service, resolvedEntity.object,
170 resolvedEntity.interface, "SendHostCommand", bytes);
171}
172
173inline void sendRoTCommand(const crow::Request& request,
174 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
175 const std::string& rotId)
176{
177 std::string command;
178 if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command",
179 command))
180 {
181 BMCWEB_LOG_DEBUG << "Missing property Command.";
182 redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand",
183 "Command");
184 return;
185 }
186
187 resolveRoT(command, asyncResp, rotId, invokeRoTCommand);
188}
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -0700189
190inline void requestRoutes(App& app)
191{
192 BMCWEB_ROUTE(app, "/google/v1/")
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700193 .methods(boost::beast::http::verb::get)(getGoogleV1);
194
195 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection")
196 .privileges({{"ConfigureManager"}})
197 .methods(boost::beast::http::verb::get)(getRootOfTrustCollection);
198
199 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/<str>")
200 .privileges({{"ConfigureManager"}})
201 .methods(boost::beast::http::verb::get)(getRootOfTrust);
202
203 BMCWEB_ROUTE(
204 app,
205 "/google/v1/RootOfTrustCollection/<str>/Actions/RootOfTrust.SendCommand")
206 .privileges({{"ConfigureManager"}})
207 .methods(boost::beast::http::verb::post)(sendRoTCommand);
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -0700208}
209
210} // namespace google_api
211} // namespace crow