1 #include "dbus_to_file_handler.hpp"
2
3 #include "common/utils.hpp"
4
5 #include <libpldm/oem/ibm/file_io.h>
6
7 #include <phosphor-logging/lg2.hpp>
8
9 PHOSPHOR_LOG2_USING;
10
11 namespace pldm
12 {
13 namespace requester
14 {
15 namespace oem_ibm
16 {
17 using namespace pldm::utils;
18 using namespace sdbusplus::bus::match::rules;
19
20 static constexpr auto resDumpProgressIntf =
21 "xyz.openbmc_project.Common.Progress";
22 static constexpr auto resDumpStatus =
23 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed";
24
DbusToFileHandler(int,uint8_t mctp_eid,pldm::InstanceIdDb * instanceIdDb,sdbusplus::message::object_path resDumpCurrentObjPath,pldm::requester::Handler<pldm::requester::Request> * handler)25 DbusToFileHandler::DbusToFileHandler(
26 int /* mctp_fd */, uint8_t mctp_eid, pldm::InstanceIdDb* instanceIdDb,
27 sdbusplus::message::object_path resDumpCurrentObjPath,
28 pldm::requester::Handler<pldm::requester::Request>* handler) :
29 mctp_eid(mctp_eid), instanceIdDb(instanceIdDb),
30 resDumpCurrentObjPath(resDumpCurrentObjPath), handler(handler)
31 {}
32
sendNewFileAvailableCmd(uint64_t fileSize)33 void DbusToFileHandler::sendNewFileAvailableCmd(uint64_t fileSize)
34 {
35 if (instanceIdDb == NULL)
36 {
37 error(
38 "Failed to send resource dump parameters as instance ID DB is not set");
39 pldm::utils::reportError(
40 "xyz.openbmc_project.bmc.pldm.InternalFailure");
41 return;
42 }
43 auto instanceId = instanceIdDb->next(mctp_eid);
44 std::vector<uint8_t> requestMsg(
45 sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_REQ_BYTES);
46 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
47 // Need to revisit this logic at the time of multiple resource dump support
48 uint32_t fileHandle = 1;
49
50 auto rc =
51 encode_new_file_req(instanceId, PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS,
52 fileHandle, fileSize, request);
53 if (rc != PLDM_SUCCESS)
54 {
55 instanceIdDb->free(mctp_eid, instanceId);
56 error("Failed to encode new file request with response code '{RC}'",
57 "RC", rc);
58 return;
59 }
60
61 auto newFileAvailableRespHandler = [this](mctp_eid_t /*eid*/,
62 const pldm_msg* response,
63 size_t respMsgLen) {
64 if (response == nullptr || !respMsgLen)
65 {
66 error("Failed to receive response for NewFileAvailable command");
67 return;
68 }
69 uint8_t completionCode{};
70 auto rc = decode_new_file_resp(response, respMsgLen, &completionCode);
71 if (rc || completionCode)
72 {
73 error(
74 "Failed to decode new file available response or remote terminus returned error, response code '{RC}' and completion code '{CC}'",
75 "RC", rc, "CC", completionCode);
76 reportResourceDumpFailure("DecodeNewFileResp");
77 }
78 };
79 rc = handler->registerRequest(
80 mctp_eid, instanceId, PLDM_OEM, PLDM_NEW_FILE_AVAILABLE,
81 std::move(requestMsg), std::move(newFileAvailableRespHandler));
82 if (rc)
83 {
84 error(
85 "Failed to send NewFileAvailable Request to Host, response code '{RC}'",
86 "RC", rc);
87 reportResourceDumpFailure("NewFileAvailableRequest");
88 }
89 }
90
reportResourceDumpFailure(const std::string_view & str)91 void DbusToFileHandler::reportResourceDumpFailure(const std::string_view& str)
92 {
93 std::string s = "xyz.openbmc_project.PLDM.Error.ReportResourceDumpFail.";
94 s += str;
95
96 pldm::utils::reportError(s.c_str());
97
98 PropertyValue value{resDumpStatus};
99 DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
100 "Status", "string"};
101 try
102 {
103 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
104 }
105 catch (const std::exception& e)
106 {
107 error("Failed to set resource dump operation status, error - {ERROR}",
108 "ERROR", e);
109 }
110 }
111
processNewResourceDump(const std::string & vspString,const std::string & resDumpReqPass)112 void DbusToFileHandler::processNewResourceDump(
113 const std::string& vspString, const std::string& resDumpReqPass)
114 {
115 try
116 {
117 std::string objPath = resDumpCurrentObjPath;
118 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant(
119 objPath.c_str(), "Status", resDumpProgressIntf);
120 const auto& curResDumpStatus = std::get<ResDumpStatus>(propVal);
121
122 if (curResDumpStatus !=
123 "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress")
124 {
125 return;
126 }
127 }
128 catch (const sdbusplus::exception_t& e)
129 {
130 error(
131 "Error '{ERROR}' found in getting current resource dump status while initiating a new resource dump with object path '{PATH}' and interface {INTERFACE}",
132 "ERROR", e, "PATH", resDumpCurrentObjPath, "INTERFACE",
133 resDumpProgressIntf);
134 }
135
136 namespace fs = std::filesystem;
137 const fs::path resDumpDirPath = "/var/lib/pldm/resourcedump";
138
139 if (!fs::exists(resDumpDirPath))
140 {
141 fs::create_directories(resDumpDirPath);
142 }
143
144 // Need to reconsider this logic to set the value as "1" when we have the
145 // support to handle multiple resource dumps
146 fs::path resDumpFilePath = resDumpDirPath / "1";
147
148 std::ofstream fileHandle;
149 fileHandle.open(resDumpFilePath, std::ios::out | std::ofstream::binary);
150
151 if (!fileHandle)
152 {
153 error("Failed to open resource dump file '{PATH}'", "PATH",
154 resDumpFilePath);
155 PropertyValue value{resDumpStatus};
156 DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
157 "Status", "string"};
158 try
159 {
160 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
161 }
162 catch (const std::exception& e)
163 {
164 error(
165 "Failed to set resource dump operation status, error - {ERROR}",
166 "ERROR", e);
167 }
168 return;
169 }
170
171 // Fill up the file with resource dump parameters and respective sizes
172 auto fileFunc = [&fileHandle](auto& paramBuf) {
173 uint32_t paramSize = paramBuf.size();
174 fileHandle.write((char*)¶mSize, sizeof(paramSize));
175 fileHandle << paramBuf;
176 };
177 fileFunc(vspString);
178 fileFunc(resDumpReqPass);
179
180 std::string str;
181 if (!resDumpReqPass.empty())
182 {
183 str = getAcfFileContent();
184 }
185
186 fileFunc(str);
187
188 fileHandle.close();
189 size_t fileSize = fs::file_size(resDumpFilePath);
190
191 sendNewFileAvailableCmd(fileSize);
192 }
193
getAcfFileContent()194 std::string DbusToFileHandler::getAcfFileContent()
195 {
196 std::string str;
197 static constexpr auto acfDirPath = "/etc/acf/service.acf";
198 if (fs::exists(acfDirPath))
199 {
200 std::ifstream file;
201 file.open(acfDirPath);
202 std::stringstream acfBuf;
203 acfBuf << file.rdbuf();
204 str = acfBuf.str();
205 file.close();
206 }
207 return str;
208 }
209
newCsrFileAvailable(const std::string & csr,const std::string fileHandle)210 void DbusToFileHandler::newCsrFileAvailable(const std::string& csr,
211 const std::string fileHandle)
212 {
213 namespace fs = std::filesystem;
214 std::string dirPath = "/var/lib/ibm/bmcweb";
215 const fs::path certDirPath = dirPath;
216
217 if (!fs::exists(certDirPath))
218 {
219 fs::create_directories(certDirPath);
220 fs::permissions(certDirPath,
221 fs::perms::others_read | fs::perms::owner_write);
222 }
223
224 fs::path certFilePath = certDirPath / ("CSR_" + fileHandle);
225 std::ofstream certFile;
226
227 certFile.open(certFilePath, std::ios::out | std::ofstream::binary);
228
229 if (!certFile)
230 {
231 error("Failed to open certificate file '{PATH}'", "PATH", certFilePath);
232 return;
233 }
234
235 // Add csr to file
236 certFile << csr << std::endl;
237
238 certFile.close();
239 uint32_t fileSize = fs::file_size(certFilePath);
240
241 newFileAvailableSendToHost(fileSize, (uint32_t)stoi(fileHandle),
242 PLDM_FILE_TYPE_CERT_SIGNING_REQUEST);
243 }
244
newFileAvailableSendToHost(const uint32_t fileSize,const uint32_t fileHandle,const uint16_t type)245 void DbusToFileHandler::newFileAvailableSendToHost(
246 const uint32_t fileSize, const uint32_t fileHandle, const uint16_t type)
247 {
248 if (instanceIdDb == NULL)
249 {
250 error("Failed to send csr to remote terminus.");
251 pldm::utils::reportError(
252 "xyz.openbmc_project.bmc.pldm.InternalFailure");
253 return;
254 }
255 auto instanceId = instanceIdDb->next(mctp_eid);
256 std::vector<uint8_t> requestMsg(
257 sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_REQ_BYTES);
258 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
259
260 auto rc =
261 encode_new_file_req(instanceId, type, fileHandle, fileSize, request);
262 if (rc != PLDM_SUCCESS)
263 {
264 instanceIdDb->free(mctp_eid, instanceId);
265 error("Failed to encode new file request with response code '{RC}'",
266 "RC", rc);
267 return;
268 }
269 auto newFileAvailableRespHandler = [](mctp_eid_t /*eid*/,
270 const pldm_msg* response,
271 size_t respMsgLen) {
272 if (response == nullptr || !respMsgLen)
273 {
274 error(
275 "Failed to receive response for NewFileAvailable command for vmi");
276 return;
277 }
278 uint8_t completionCode{};
279 auto rc = decode_new_file_resp(response, respMsgLen, &completionCode);
280 if (rc || completionCode)
281 {
282 error(
283 "Failed to decode new file available response for vmi or remote terminus returned error, response code '{RC}' and completion code '{CC}'",
284 "RC", rc, "CC", completionCode);
285 pldm::utils::reportError(
286 "xyz.openbmc_project.PLDM.Error.DecodeNewFileResponseFail");
287 }
288 };
289 rc = handler->registerRequest(
290 mctp_eid, instanceId, PLDM_OEM, PLDM_NEW_FILE_AVAILABLE,
291 std::move(requestMsg), std::move(newFileAvailableRespHandler));
292 if (rc)
293 {
294 error(
295 "Failed to send NewFileAvailable Request to Host for vmi, response code '{RC}'",
296 "RC", rc);
297 pldm::utils::reportError(
298 "xyz.openbmc_project.PLDM.Error.NewFileAvailableRequestFail");
299 }
300 }
301
302 } // namespace oem_ibm
303 } // namespace requester
304 } // namespace pldm
305