blob: 42d2af9ddd48faa540eb8b58cdd8602594dddc44 [file] [log] [blame]
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -07001#pragma once
2
3#include <app.hpp>
4#include <async_resp.hpp>
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -07005#include <error_messages.hpp>
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -07006#include <nlohmann/json.hpp>
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -07007#include <utils/collection.hpp>
8#include <utils/hex_utils.hpp>
9#include <utils/json_utils.hpp>
10
11#include <vector>
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -070012
13namespace crow
14{
15namespace google_api
16{
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070017constexpr const char* hothSearchPath = "/xyz/openbmc_project";
18constexpr const char* hothInterface = "xyz.openbmc_project.Control.Hoth";
19constexpr const char* rotCollectionPrefix = "/google/v1/RootOfTrustCollection";
20
21inline void getGoogleV1(const crow::Request& /*req*/,
22 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
23{
24 asyncResp->res.jsonValue["@odata.type"] =
25 "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot";
26 asyncResp->res.jsonValue["@odata.id"] = "/google/v1";
27 asyncResp->res.jsonValue["Id"] = "Google Rest RootService";
28 asyncResp->res.jsonValue["Name"] = "Google Service Root";
29 asyncResp->res.jsonValue["Version"] = "1.0.0";
30 asyncResp->res.jsonValue["RootOfTrustCollection"]["@odata.id"] =
31 rotCollectionPrefix;
32}
33
34inline void getRootOfTrustCollection(
35 const crow::Request& /*req*/,
36 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
37{
38 asyncResp->res.jsonValue["@odata.id"] = rotCollectionPrefix;
39 asyncResp->res.jsonValue["@odata.type"] =
40 "#RootOfTrustCollection.RootOfTrustCollection";
41 redfish::collection_util::getCollectionMembers(
42 asyncResp, rotCollectionPrefix, std::vector<const char*>{hothInterface},
43 hothSearchPath);
44}
45
46// Helper struct to identify a resolved D-Bus object interface
47struct ResolvedEntity
48{
49 std::string id;
50 std::string service;
51 std::string object;
52 const char* interface;
53};
54
55using ResolvedEntityHandler = std::function<void(
56 const std::string&, const std::shared_ptr<bmcweb::AsyncResp>&,
57 const ResolvedEntity&)>;
58
59inline void resolveRoT(const std::string& command,
60 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
61 const std::string& rotId,
62 ResolvedEntityHandler&& entityHandler)
63{
64 auto validateFunc = [command, asyncResp, rotId,
65 entityHandler{std::forward<ResolvedEntityHandler>(
66 entityHandler)}](
67 const boost::system::error_code ec,
68 const crow::openbmc_mapper::GetSubTreeType&
69 subtree) {
70 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