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*)&paramSize, 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