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