blob: b43a8a5ab9c31778f6ee33b6701d7f8337f7d009 [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{
Ed Tanous002d39b2022-05-31 08:59:27 -070065 auto validateFunc =
66 [command, asyncResp, rotId,
67 entityHandler{std::forward<ResolvedEntityHandler>(entityHandler)}](
68 const boost::system::error_code ec,
69 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070070 if (ec)
71 {
72 redfish::messages::internalError(asyncResp->res);
73 return;
74 }
75 // Iterate over all retrieved ObjectPaths.
76 for (const std::pair<
77 std::string,
78 std::vector<std::pair<std::string, std::vector<std::string>>>>&
79 object : subtree)
80 {
81 sdbusplus::message::object_path objPath(object.first);
82 if (objPath.filename() != rotId || object.second.empty())
83 {
84 continue;
85 }
86
87 ResolvedEntity resolvedEntity = {.id = rotId,
88 .service = object.second[0].first,
89 .object = object.first,
90 .interface = hothInterface};
91 entityHandler(command, asyncResp, resolvedEntity);
92 return;
93 }
94
95 // Couldn't find an object with that name. return an error
96 redfish::messages::resourceNotFound(
97 asyncResp->res, "#RootOfTrust.v1_0_0.RootOfTrust", rotId);
98 };
99
100 std::array<std::string, 1> hothIfaces = {hothInterface};
101 crow::connections::systemBus->async_method_call(
102 validateFunc, "xyz.openbmc_project.ObjectMapper",
103 "/xyz/openbmc_project/object_mapper",
104 "xyz.openbmc_project.ObjectMapper", "GetSubTree", hothSearchPath,
105 /*depth=*/0, hothIfaces);
106}
107
108inline void populateRootOfTrustEntity(
109 const std::string& /*unused*/,
110 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
111 const ResolvedEntity& resolvedEntity)
112{
113 asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust";
114 asyncResp->res.jsonValue["@odata.id"] =
115 "/google/v1/RootOfTrustCollection/" + resolvedEntity.id;
116
117 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
118 asyncResp->res.jsonValue["Id"] = resolvedEntity.id;
119 // Need to fix this later to a stabler property.
120 asyncResp->res.jsonValue["Name"] = resolvedEntity.id;
121 asyncResp->res.jsonValue["Description"] = "Google Root Of Trust";
122 asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] =
123 "/google/v1/RootOfTrustCollection/" + resolvedEntity.id +
124 "/Actions/RootOfTrust.SendCommand";
125
126 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
127 resolvedEntity.id;
128 asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] =
129 "Embedded";
130}
131
132inline void getRootOfTrust(const crow::Request& /*unused*/,
133 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
134 const std::string& param)
135{
136 resolveRoT("" /*Empty command*/, asyncResp, param,
137 populateRootOfTrustEntity);
138}
139
140inline void
141 invokeRoTCommand(const std::string& command,
142 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
143 const ResolvedEntity& resolvedEntity)
144{
145 auto handleFunc = [asyncResp](const boost::system::error_code ec,
146 std::vector<uint8_t>& responseBytes) {
147 if (ec)
148 {
149 BMCWEB_LOG_ERROR << "RootOfTrust.Actions.SendCommand failed: "
150 << ec.message();
151 redfish::messages::internalError(asyncResp->res);
152 return;
153 }
154
155 asyncResp->res.jsonValue["CommandResponse"] =
156 bytesToHexString(responseBytes);
157 };
158 std::vector<uint8_t> bytes = hexStringToBytes(command);
159 if (bytes.empty())
160 {
161 BMCWEB_LOG_DEBUG << "Invalid command: " << command;
162 redfish::messages::actionParameterValueTypeError(command, "Command",
163 "SendCommand");
164 return;
165 }
166
167 crow::connections::systemBus->async_method_call(
168 handleFunc, resolvedEntity.service, resolvedEntity.object,
169 resolvedEntity.interface, "SendHostCommand", bytes);
170}
171
172inline void sendRoTCommand(const crow::Request& request,
173 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
174 const std::string& rotId)
175{
176 std::string command;
177 if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command",
178 command))
179 {
180 BMCWEB_LOG_DEBUG << "Missing property Command.";
181 redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand",
182 "Command");
183 return;
184 }
185
186 resolveRoT(command, asyncResp, rotId, invokeRoTCommand);
187}
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -0700188
189inline void requestRoutes(App& app)
190{
191 BMCWEB_ROUTE(app, "/google/v1/")
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700192 .methods(boost::beast::http::verb::get)(getGoogleV1);
193
194 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection")
195 .privileges({{"ConfigureManager"}})
196 .methods(boost::beast::http::verb::get)(getRootOfTrustCollection);
197
198 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/<str>")
199 .privileges({{"ConfigureManager"}})
200 .methods(boost::beast::http::verb::get)(getRootOfTrust);
201
202 BMCWEB_ROUTE(
203 app,
204 "/google/v1/RootOfTrustCollection/<str>/Actions/RootOfTrust.SendCommand")
205 .privileges({{"ConfigureManager"}})
206 .methods(boost::beast::http::verb::post)(sendRoTCommand);
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -0700207}
208
209} // namespace google_api
210} // namespace crow