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, boost::urls::url("/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(asyncResp->res, "RootOfTrust", rotId); 89 } 90 91 inline void resolveRoT(const std::string& command, 92 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 93 const std::string& rotId, 94 ResolvedEntityHandler&& entityHandler) 95 { 96 97 std::array<std::string, 1> hothIfaces = { 98 "xyz.openbmc_project.Control.Hoth"}; 99 crow::connections::systemBus->async_method_call( 100 [command, asyncResp, rotId, 101 entityHandler{std::forward<ResolvedEntityHandler>(entityHandler)}]( 102 const boost::system::error_code ec, 103 const dbus::utility::MapperGetSubTreeResponse& subtree) { 104 hothGetSubtreeCallback(command, asyncResp, rotId, entityHandler, ec, 105 subtree); 106 }, 107 "xyz.openbmc_project.ObjectMapper", 108 "/xyz/openbmc_project/object_mapper", 109 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 110 "/xyz/openbmc_project", 111 /*depth=*/0, hothIfaces); 112 } 113 114 inline void populateRootOfTrustEntity( 115 const std::string& /*unused*/, 116 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 117 const ResolvedEntity& resolvedEntity) 118 { 119 asyncResp->res.jsonValue["@odata.type"] = "#RootOfTrust.v1_0_0.RootOfTrust"; 120 asyncResp->res.jsonValue["@odata.id"] = 121 "/google/v1/RootOfTrustCollection/" + resolvedEntity.id; 122 123 asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 124 asyncResp->res.jsonValue["Id"] = resolvedEntity.id; 125 // Need to fix this later to a stabler property. 126 asyncResp->res.jsonValue["Name"] = resolvedEntity.id; 127 asyncResp->res.jsonValue["Description"] = "Google Root Of Trust"; 128 asyncResp->res.jsonValue["Actions"]["#RootOfTrust.SendCommand"]["target"] = 129 "/google/v1/RootOfTrustCollection/" + resolvedEntity.id + 130 "/Actions/RootOfTrust.SendCommand"; 131 132 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 133 resolvedEntity.id; 134 asyncResp->res.jsonValue["Location"]["PartLocation"]["LocationType"] = 135 "Embedded"; 136 } 137 138 inline void 139 handleRootOfTrustGet(const crow::Request& /*req*/, 140 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 141 const std::string& param) 142 { 143 std::string emptyCommand; 144 resolveRoT(emptyCommand, asyncResp, param, populateRootOfTrustEntity); 145 } 146 147 inline void 148 invocationCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 149 const boost::system::error_code ec, 150 const std::vector<uint8_t>& responseBytes) 151 { 152 if (ec) 153 { 154 BMCWEB_LOG_ERROR << "RootOfTrust.Actions.SendCommand failed: " 155 << ec.message(); 156 redfish::messages::internalError(asyncResp->res); 157 return; 158 } 159 160 asyncResp->res.jsonValue["CommandResponse"] = 161 bytesToHexString(responseBytes); 162 } 163 164 inline void 165 invokeRoTCommand(const std::string& command, 166 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 167 const ResolvedEntity& resolvedEntity) 168 { 169 std::vector<uint8_t> bytes = hexStringToBytes(command); 170 if (bytes.empty()) 171 { 172 BMCWEB_LOG_DEBUG << "Invalid command: " << command; 173 redfish::messages::actionParameterValueTypeError(command, "Command", 174 "SendCommand"); 175 return; 176 } 177 178 crow::connections::systemBus->async_method_call( 179 [asyncResp{asyncResp}](const boost::system::error_code ec, 180 const std::vector<uint8_t>& responseBytes) { 181 invocationCallback(asyncResp, ec, responseBytes); 182 }, 183 resolvedEntity.service, resolvedEntity.object, resolvedEntity.interface, 184 "SendHostCommand", bytes); 185 } 186 187 inline void handleRoTSendCommandPost( 188 const crow::Request& request, 189 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 190 const std::string& rotId) 191 { 192 std::string command; 193 if (!redfish::json_util::readJsonAction(request, asyncResp->res, "Command", 194 command)) 195 { 196 BMCWEB_LOG_DEBUG << "Missing property Command."; 197 redfish::messages::actionParameterMissing(asyncResp->res, "SendCommand", 198 "Command"); 199 return; 200 } 201 202 resolveRoT(command, asyncResp, rotId, invokeRoTCommand); 203 } 204 205 inline void requestRoutes(App& app) 206 { 207 BMCWEB_ROUTE(app, "/google/v1/") 208 .methods(boost::beast::http::verb::get)(handleGoogleV1Get); 209 210 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection") 211 .privileges({{"ConfigureManager"}}) 212 .methods(boost::beast::http::verb::get)(handleRootOfTrustCollectionGet); 213 214 BMCWEB_ROUTE(app, "/google/v1/RootOfTrustCollection/<str>") 215 .privileges({{"ConfigureManager"}}) 216 .methods(boost::beast::http::verb::get)(handleRootOfTrustGet); 217 218 BMCWEB_ROUTE( 219 app, 220 "/google/v1/RootOfTrustCollection/<str>/Actions/RootOfTrust.SendCommand") 221 .privileges({{"ConfigureManager"}}) 222 .methods(boost::beast::http::verb::post)(handleRoTSendCommandPost); 223 } 224 225 } // namespace google_api 226 } // namespace crow 227