1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 // SPDX-FileCopyrightText: Copyright 2018 Intel Corporation 4 5 #pragma once 6 7 #include "app.hpp" 8 #include "async_resp.hpp" 9 #include "error_messages.hpp" 10 #include "http_body.hpp" 11 #include "http_response.hpp" 12 #include "logging.hpp" 13 14 #include <asm-generic/errno.h> 15 #include <systemd/sd-bus.h> 16 #include <unistd.h> 17 18 #include <boost/beast/http/field.hpp> 19 #include <boost/beast/http/status.hpp> 20 #include <boost/beast/http/verb.hpp> 21 #include <boost/system/linux_error.hpp> 22 #include <boost/url/format.hpp> 23 #include <boost/url/url.hpp> 24 #include <sdbusplus/message.hpp> 25 #include <sdbusplus/message/native_types.hpp> 26 #include <sdbusplus/unpack_properties.hpp> 27 28 #include <cstdio> 29 #include <format> 30 #include <memory> 31 #include <string> 32 33 namespace redfish 34 { 35 namespace log_services_utils 36 { 37 38 inline bool checkSizeLimit(int fd, crow::Response& res) 39 { 40 long long int size = lseek(fd, 0, SEEK_END); 41 if (size <= 0) 42 { 43 BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}", 44 size); 45 messages::internalError(res); 46 return false; 47 } 48 49 // Arbitrary max size of 20MB to accommodate BMC dumps 50 constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL; 51 if (size > maxFileSize) 52 { 53 BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}", 54 size, maxFileSize); 55 messages::internalError(res); 56 return false; 57 } 58 off_t rc = lseek(fd, 0, SEEK_SET); 59 if (rc < 0) 60 { 61 BMCWEB_LOG_ERROR("Failed to reset file offset to 0"); 62 messages::internalError(res); 63 return false; 64 } 65 return true; 66 } 67 68 inline void downloadEntryCallback( 69 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 70 const std::string& entryID, const std::string& downloadEntryType, 71 const boost::system::error_code& ec, 72 const sdbusplus::message::unix_fd& unixfd) 73 { 74 if (ec.value() == EBADR) 75 { 76 messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID); 77 return; 78 } 79 if (ec) 80 { 81 BMCWEB_LOG_ERROR("DBUS response error: {}", ec); 82 messages::internalError(asyncResp->res); 83 return; 84 } 85 86 // Make sure we know how to process the retrieved entry attachment 87 if ((downloadEntryType != "BMC") && (downloadEntryType != "System")) 88 { 89 BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}", 90 downloadEntryType); 91 messages::internalError(asyncResp->res); 92 } 93 94 int fd = -1; 95 fd = dup(unixfd); 96 if (fd < 0) 97 { 98 BMCWEB_LOG_ERROR("Failed to open file"); 99 messages::internalError(asyncResp->res); 100 return; 101 } 102 if (!checkSizeLimit(fd, asyncResp->res)) 103 { 104 close(fd); 105 return; 106 } 107 if (downloadEntryType == "System") 108 { 109 if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64)) 110 { 111 messages::internalError(asyncResp->res); 112 close(fd); 113 return; 114 } 115 asyncResp->res.addHeader( 116 boost::beast::http::field::content_transfer_encoding, "Base64"); 117 return; 118 } 119 if (!asyncResp->res.openFd(fd)) 120 { 121 messages::internalError(asyncResp->res); 122 close(fd); 123 return; 124 } 125 asyncResp->res.addHeader(boost::beast::http::field::content_type, 126 "application/octet-stream"); 127 } 128 } // namespace log_services_utils 129 } // namespace redfish 130