blob: 3d21af7b735e13f2f2c3c029bbb021c188e2be0c [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"
Ed Tanousd7857202025-01-28 15:32:26 -08009#include "http_request.hpp"
10#include "logging.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080011#include "utils/collection.hpp"
12#include "utils/hex_utils.hpp"
13#include "utils/json_utils.hpp"
14
Ed Tanousd7857202025-01-28 15:32:26 -080015#include <boost/beast/http/verb.hpp>
George Liue99073f2022-12-09 11:06:16 +080016#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070017#include <boost/url/format.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080018#include <boost/url/url.hpp>
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -070019#include <nlohmann/json.hpp>
Ed Tanousd7857202025-01-28 15:32:26 -080020#include <sdbusplus/message/native_types.hpp>
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070021
George Liu7a1dbc42022-12-07 16:03:22 +080022#include <array>
Ed Tanousd7857202025-01-28 15:32:26 -080023#include <cstdint>
24#include <functional>
25#include <memory>
George Liu7a1dbc42022-12-07 16:03:22 +080026#include <string_view>
Ed Tanousd7857202025-01-28 15:32:26 -080027#include <utility>
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070028#include <vector>
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -070029
30namespace crow
31{
32namespace google_api
33{
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070034
Patrick Williams504af5a2025-02-03 14:29:03 -050035inline void handleGoogleV1Get(
36 const crow::Request& /*req*/,
37 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070038{
39 asyncResp->res.jsonValue["@odata.type"] =
40 "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot";
41 asyncResp->res.jsonValue["@odata.id"] = "/google/v1";
42 asyncResp->res.jsonValue["Id"] = "Google Rest RootService";
43 asyncResp->res.jsonValue["Name"] = "Google Service Root";
44 asyncResp->res.jsonValue["Version"] = "1.0.0";
45 asyncResp->res.jsonValue["RootOfTrustCollection"]["@odata.id"] =
Nan Zhoucd027592022-07-03 05:18:29 +000046 "/google/v1/RootOfTrustCollection";
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070047}
48
Nan Zhou30aacdd2022-07-03 05:02:36 +000049inline void handleRootOfTrustCollectionGet(
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070050 const crow::Request& /*req*/,
51 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
52{
Nan Zhoucd027592022-07-03 05:18:29 +000053 asyncResp->res.jsonValue["@odata.id"] = "/google/v1/RootOfTrustCollection";
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070054 asyncResp->res.jsonValue["@odata.type"] =
55 "#RootOfTrustCollection.RootOfTrustCollection";
George Liu7a1dbc42022-12-07 16:03:22 +080056 const std::array<std::string_view, 1> interfaces{
57 "xyz.openbmc_project.Control.Hoth"};
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070058 redfish::collection_util::getCollectionMembers(
Willy Tuae9031f2022-09-27 05:48:07 +000059 asyncResp, boost::urls::url("/google/v1/RootOfTrustCollection"),
George Liu7a1dbc42022-12-07 16:03:22 +080060 interfaces, "/xyz/openbmc_project");
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070061}
62
63// Helper struct to identify a resolved D-Bus object interface
64struct ResolvedEntity
65{
66 std::string id;
67 std::string service;
68 std::string object;
Nan Zhou16a55352022-07-03 05:06:08 +000069 std::string interface;
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -070070};
71
72using ResolvedEntityHandler = std::function<void(
73 const std::string&, const std::shared_ptr<bmcweb::AsyncResp>&,
74 const ResolvedEntity&)>;
75
Nan Zhou30aacdd2022-07-03 05:02:36 +000076inline void hothGetSubtreeCallback(
77 const std::string& command,
78 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
79 const std::string& rotId, const ResolvedEntityHandler& entityHandler,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080080 const boost::system::error_code& ec,
Nan Zhou30aacdd2022-07-03 05:02:36 +000081 const dbus::utility::MapperGetSubTreeResponse& subtree)
82{
83 if (ec)
84 {
85 redfish::messages::internalError(asyncResp->res);
86 return;
87 }
Nan Zhou5600f022022-07-03 16:22:38 +000088 for (const auto& [path, services] : subtree)
Nan Zhou30aacdd2022-07-03 05:02:36 +000089 {
Nan Zhou5600f022022-07-03 16:22:38 +000090 sdbusplus::message::object_path objPath(path);
91 if (objPath.filename() != rotId || services.empty())
Nan Zhou30aacdd2022-07-03 05:02:36 +000092 {
93 continue;
94 }
95
Nan Zhoucd027592022-07-03 05:18:29 +000096 ResolvedEntity resolvedEntity = {
97 .id = rotId,
Nan Zhou5600f022022-07-03 16:22:38 +000098 .service = services[0].first,
99 .object = path,
Nan Zhoucd027592022-07-03 05:18:29 +0000100 .interface = "xyz.openbmc_project.Control.Hoth"};
Nan Zhou30aacdd2022-07-03 05:02:36 +0000101 entityHandler(command, asyncResp, resolvedEntity);
102 return;
103 }
104
105 // Couldn't find an object with that name. return an error
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800106 redfish::messages::resourceNotFound(asyncResp->res, "RootOfTrust", rotId);
Nan Zhou30aacdd2022-07-03 05:02:36 +0000107}
108
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700109inline void resolveRoT(const std::string& command,
110 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
111 const std::string& rotId,
112 ResolvedEntityHandler&& entityHandler)
113{
George Liu7a1dbc42022-12-07 16:03:22 +0800114 constexpr std::array<std::string_view, 1> hothIfaces = {
Nan Zhoucd027592022-07-03 05:18:29 +0000115 "xyz.openbmc_project.Control.Hoth"};
George Liue99073f2022-12-09 11:06:16 +0800116 dbus::utility::getSubTree(
117 "/xyz/openbmc_project", 0, hothIfaces,
Ed Tanous8cb2c022024-03-27 16:31:46 -0700118 [command, asyncResp, rotId, entityHandler{std::move(entityHandler)}](
George Liue99073f2022-12-09 11:06:16 +0800119 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700120 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400121 hothGetSubtreeCallback(command, asyncResp, rotId, entityHandler, ec,
122 subtree);
123 });
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700124}
125
126inline void populateRootOfTrustEntity(
127 const std::string& /*unused*/,
128 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
129 const ResolvedEntity& resolvedEntity)
130{
131 asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700132 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
133 "/google/v1/RootOfTrustCollection/{}", resolvedEntity.id);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700134
135 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
136 asyncResp->res.jsonValue["Id"] = resolvedEntity.id;
137 // Need to fix this later to a stabler property.
138 asyncResp->res.jsonValue["Name"] = resolvedEntity.id;
139 asyncResp->res.jsonValue["Description"] = "Google Root Of Trust";
140 asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] =
141 "/google/v1/RootOfTrustCollection/" + resolvedEntity.id +
142 "/Actions/RootOfTrust.SendCommand";
143
144 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
145 resolvedEntity.id;
146 asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] =
147 "Embedded";
148}
149
Patrick Williams504af5a2025-02-03 14:29:03 -0500150inline void handleRootOfTrustGet(
151 const crow::Request& /*req*/,
152 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
153 const std::string& param)
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700154{
Nan Zhou30aacdd2022-07-03 05:02:36 +0000155 std::string emptyCommand;
156 resolveRoT(emptyCommand, asyncResp, param, populateRootOfTrustEntity);
157}
158
Patrick Williams504af5a2025-02-03 14:29:03 -0500159inline void invocationCallback(
160 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
161 const boost::system::error_code& ec,
162 const std::vector<uint8_t>& responseBytes)
Nan Zhou30aacdd2022-07-03 05:02:36 +0000163{
164 if (ec)
165 {
Ed Tanous62598e32023-07-17 17:06:25 -0700166 BMCWEB_LOG_ERROR("RootOfTrust.Actions.SendCommand failed: {}",
167 ec.message());
Nan Zhou30aacdd2022-07-03 05:02:36 +0000168 redfish::messages::internalError(asyncResp->res);
169 return;
170 }
171
172 asyncResp->res.jsonValue["CommandResponse"] =
173 bytesToHexString(responseBytes);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700174}
175
Patrick Williams504af5a2025-02-03 14:29:03 -0500176inline void invokeRoTCommand(
177 const std::string& command,
178 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
179 const ResolvedEntity& resolvedEntity)
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700180{
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700181 std::vector<uint8_t> bytes = hexStringToBytes(command);
182 if (bytes.empty())
183 {
Ed Tanous62598e32023-07-17 17:06:25 -0700184 BMCWEB_LOG_DEBUG("Invalid command: {}", command);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700185 redfish::messages::actionParameterValueTypeError(command, "Command",
186 "SendCommand");
187 return;
188 }
189
Ed Tanous177612a2025-02-14 15:16:09 -0800190 dbus::utility::async_method_call(
191 asyncResp,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800192 [asyncResp{asyncResp}](const boost::system::error_code& ec,
Nan Zhou30aacdd2022-07-03 05:02:36 +0000193 const std::vector<uint8_t>& responseBytes) {
Patrick Williamsbd79bce2024-08-16 15:22:20 -0400194 invocationCallback(asyncResp, ec, responseBytes);
195 },
Nan Zhou30aacdd2022-07-03 05:02:36 +0000196 resolvedEntity.service, resolvedEntity.object, resolvedEntity.interface,
197 "SendHostCommand", bytes);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700198}
199
Nan Zhou30aacdd2022-07-03 05:02:36 +0000200inline void handleRoTSendCommandPost(
201 const crow::Request& request,
202 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
203 const std::string& rotId)
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700204{
205 std::string command;
206 if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command",
207 command))
208 {
Ed Tanous62598e32023-07-17 17:06:25 -0700209 BMCWEB_LOG_DEBUG("Missing property Command.");
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700210 redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand",
211 "Command");
212 return;
213 }
214
215 resolveRoT(command, asyncResp, rotId, invokeRoTCommand);
216}
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -0700217
218inline void requestRoutes(App& app)
219{
220 BMCWEB_ROUTE(app, "/google/v1/")
Nan Zhou30aacdd2022-07-03 05:02:36 +0000221 .methods(boost::beast::http::verb::get)(handleGoogleV1Get);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700222
223 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection")
224 .privileges({{"ConfigureManager"}})
Nan Zhou30aacdd2022-07-03 05:02:36 +0000225 .methods(boost::beast::http::verb::get)(handleRootOfTrustCollectionGet);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700226
227 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/<str>")
228 .privileges({{"ConfigureManager"}})
Nan Zhou30aacdd2022-07-03 05:02:36 +0000229 .methods(boost::beast::http::verb::get)(handleRootOfTrustGet);
Vidya Satyamsetti4cee35e2022-04-21 14:53:44 -0700230
231 BMCWEB_ROUTE(
232 app,
233 "/google/v1/RootOfTrustCollection/<str>/Actions/RootOfTrust.SendCommand")
234 .privileges({{"ConfigureManager"}})
Nan Zhou30aacdd2022-07-03 05:02:36 +0000235 .methods(boost::beast::http::verb::post)(handleRoTSendCommandPost);
Feras Aldahlawi735ef6d2021-03-19 14:01:46 -0700236}
237
238} // namespace google_api
239} // namespace crow