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