summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/google/google_service_root.hpp202
1 files changed, 192 insertions, 10 deletions
diff --git a/include/google/google_service_root.hpp b/include/google/google_service_root.hpp
index a80a50071b..42d2af9ddd 100644
--- a/include/google/google_service_root.hpp
+++ b/include/google/google_service_root.hpp
@@ -2,26 +2,208 @@
#include <app.hpp>
#include <async_resp.hpp>
+#include <error_messages.hpp>
#include <nlohmann/json.hpp>
+#include <utils/collection.hpp>
+#include <utils/hex_utils.hpp>
+#include <utils/json_utils.hpp>
+
+#include <vector>
namespace crow
{
namespace google_api
{
+constexpr const char* hothSearchPath = "/xyz/openbmc_project";
+constexpr const char* hothInterface = "xyz.openbmc_project.Control.Hoth";
+constexpr const char* rotCollectionPrefix = "/google/v1/RootOfTrustCollection";
+
+inline void getGoogleV1(const crow::Request& /*req*/,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot";
+ asyncResp->res.jsonValue["@odata.id"] = "/google/v1";
+ asyncResp->res.jsonValue["Id"] = "Google Rest RootService";
+ asyncResp->res.jsonValue["Name"] = "Google Service Root";
+ asyncResp->res.jsonValue["Version"] = "1.0.0";
+ asyncResp->res.jsonValue["RootOfTrustCollection"]["@odata.id"] =
+ rotCollectionPrefix;
+}
+
+inline void getRootOfTrustCollection(
+ const crow::Request& /*req*/,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
+{
+ asyncResp->res.jsonValue["@odata.id"] = rotCollectionPrefix;
+ asyncResp->res.jsonValue["@odata.type"] =
+ "#RootOfTrustCollection.RootOfTrustCollection";
+ redfish::collection_util::getCollectionMembers(
+ asyncResp, rotCollectionPrefix, std::vector<const char*>{hothInterface},
+ hothSearchPath);
+}
+
+// Helper struct to identify a resolved D-Bus object interface
+struct ResolvedEntity
+{
+ std::string id;
+ std::string service;
+ std::string object;
+ const char* interface;
+};
+
+using ResolvedEntityHandler = std::function<void(
+ const std::string&, const std::shared_ptr<bmcweb::AsyncResp>&,
+ const ResolvedEntity&)>;
+
+inline void resolveRoT(const std::string& command,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& rotId,
+ ResolvedEntityHandler&& entityHandler)
+{
+ auto validateFunc = [command, asyncResp, rotId,
+ entityHandler{std::forward<ResolvedEntityHandler>(
+ entityHandler)}](
+ const boost::system::error_code ec,
+ const crow::openbmc_mapper::GetSubTreeType&
+ subtree) {
+ if (ec)
+ {
+ redfish::messages::internalError(asyncResp->res);
+ return;
+ }
+ // Iterate over all retrieved ObjectPaths.
+ for (const std::pair<
+ std::string,
+ std::vector<std::pair<std::string, std::vector<std::string>>>>&
+ object : subtree)
+ {
+ sdbusplus::message::object_path objPath(object.first);
+ if (objPath.filename() != rotId || object.second.empty())
+ {
+ continue;
+ }
+
+ ResolvedEntity resolvedEntity = {.id = rotId,
+ .service = object.second[0].first,
+ .object = object.first,
+ .interface = hothInterface};
+ entityHandler(command, asyncResp, resolvedEntity);
+ return;
+ }
+
+ // Couldn't find an object with that name. return an error
+ redfish::messages::resourceNotFound(
+ asyncResp->res, "#RootOfTrust.v1_0_0.RootOfTrust", rotId);
+ };
+
+ std::array<std::string, 1> hothIfaces = {hothInterface};
+ crow::connections::systemBus->async_method_call(
+ validateFunc, "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", hothSearchPath,
+ /*depth=*/0, hothIfaces);
+}
+
+inline void populateRootOfTrustEntity(
+ const std::string& /*unused*/,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const ResolvedEntity& resolvedEntity)
+{
+ asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust";
+ asyncResp->res.jsonValue["@odata.id"] =
+ "/google/v1/RootOfTrustCollection/" + resolvedEntity.id;
+
+ asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
+ asyncResp->res.jsonValue["Id"] = resolvedEntity.id;
+ // Need to fix this later to a stabler property.
+ asyncResp->res.jsonValue["Name"] = resolvedEntity.id;
+ asyncResp->res.jsonValue["Description"] = "Google Root Of Trust";
+ asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] =
+ "/google/v1/RootOfTrustCollection/" + resolvedEntity.id +
+ "/Actions/RootOfTrust.SendCommand";
+
+ asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
+ resolvedEntity.id;
+ asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] =
+ "Embedded";
+}
+
+inline void getRootOfTrust(const crow::Request& /*unused*/,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& param)
+{
+ resolveRoT("" /*Empty command*/, asyncResp, param,
+ populateRootOfTrustEntity);
+}
+
+inline void
+ invokeRoTCommand(const std::string& command,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const ResolvedEntity& resolvedEntity)
+{
+ auto handleFunc = [asyncResp](const boost::system::error_code ec,
+ std::vector<uint8_t>& responseBytes) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "RootOfTrust.Actions.SendCommand failed: "
+ << ec.message();
+ redfish::messages::internalError(asyncResp->res);
+ return;
+ }
+
+ asyncResp->res.jsonValue["CommandResponse"] =
+ bytesToHexString(responseBytes);
+ };
+ std::vector<uint8_t> bytes = hexStringToBytes(command);
+ if (bytes.empty())
+ {
+ BMCWEB_LOG_DEBUG << "Invalid command: " << command;
+ redfish::messages::actionParameterValueTypeError(command, "Command",
+ "SendCommand");
+ return;
+ }
+
+ crow::connections::systemBus->async_method_call(
+ handleFunc, resolvedEntity.service, resolvedEntity.object,
+ resolvedEntity.interface, "SendHostCommand", bytes);
+}
+
+inline void sendRoTCommand(const crow::Request& request,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& rotId)
+{
+ std::string command;
+ if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command",
+ command))
+ {
+ BMCWEB_LOG_DEBUG << "Missing property Command.";
+ redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand",
+ "Command");
+ return;
+ }
+
+ resolveRoT(command, asyncResp, rotId, invokeRoTCommand);
+}
inline void requestRoutes(App& app)
{
BMCWEB_ROUTE(app, "/google/v1/")
- .methods(boost::beast::http::verb::get)(
- [](const crow::Request&,
- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
- asyncResp->res.jsonValue["@odata.type"] =
- "#GoogleServiceRoot.v1_0_0.GoogleServiceRoot";
- asyncResp->res.jsonValue["@odata.id"] = "/google/v1";
- asyncResp->res.jsonValue["Id"] = "Google Rest RootService";
- asyncResp->res.jsonValue["Name"] = "Google Service Root";
- asyncResp->res.jsonValue["Version"] = "1.0.0";
- });
+ .methods(boost::beast::http::verb::get)(getGoogleV1);
+
+ BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection")
+ .privileges({{"ConfigureManager"}})
+ .methods(boost::beast::http::verb::get)(getRootOfTrustCollection);
+
+ BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/<str>")
+ .privileges({{"ConfigureManager"}})
+ .methods(boost::beast::http::verb::get)(getRootOfTrust);
+
+ BMCWEB_ROUTE(
+ app,
+ "/google/v1/RootOfTrustCollection/<str>/Actions/RootOfTrust.SendCommand")
+ .privileges({{"ConfigureManager"}})
+ .methods(boost::beast::http::verb::post)(sendRoTCommand);
}
} // namespace google_api