blob: 51e953d8078bd26eb170a33bffabdfe62927172e [file] [log] [blame]
Patrick Venture5794fcf2017-10-26 11:11:14 -07001#include "channel.hpp"
Patrick Venture5794fcf2017-10-26 11:11:14 -07002
Johnathan Mantey74a21022018-12-13 13:17:56 -08003#include "user_channel/channel_layer.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07004
Patrick Venture5794fcf2017-10-26 11:11:14 -07005#include <arpa/inet.h>
6
Tom Joseph13227682018-08-10 01:05:21 +05307#include <boost/process/child.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -07008#include <fstream>
Vernon Mauery33250242019-03-12 16:49:26 -07009#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070010#include <ipmid/utils.hpp>
Patrick Venture5794fcf2017-10-26 11:11:14 -070011#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070012#include <phosphor-logging/log.hpp>
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053013#include <set>
Patrick Venture0b02be92018-08-31 11:55:55 -070014#include <string>
15#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture5794fcf2017-10-26 11:11:14 -070016
17using namespace phosphor::logging;
18using namespace sdbusplus::xyz::openbmc_project::Common::Error;
19
Tom Joseph7cbe2282018-03-21 21:17:33 +053020namespace cipher
21{
22
23/** @brief Get the supported Cipher records
24 *
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053025 * The cipher records are read from the JSON file and converted into
26 * 1. cipher suite record format mentioned in the IPMI specification. The
27 * records can be either OEM or standard cipher. Each json entry is parsed and
28 * converted into the cipher record format and pushed into the vector.
29 * 2. Algorithms listed in vector format
Tom Joseph7cbe2282018-03-21 21:17:33 +053030 *
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053031 * @return pair of vector containing 1. all the cipher suite records. 2.
32 * Algorithms supported
Tom Joseph7cbe2282018-03-21 21:17:33 +053033 *
34 */
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053035std::pair<std::vector<uint8_t>, std::vector<uint8_t>> getCipherRecords()
Tom Joseph7cbe2282018-03-21 21:17:33 +053036{
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053037 std::vector<uint8_t> cipherRecords;
38 std::vector<uint8_t> supportedAlgorithmRecords;
39 // create set to get the unique supported algorithms
40 std::set<uint8_t> supportedAlgorithmSet;
Tom Joseph7cbe2282018-03-21 21:17:33 +053041
42 std::ifstream jsonFile(configFile);
43 if (!jsonFile.is_open())
44 {
45 log<level::ERR>("Channel Cipher suites file not found");
46 elog<InternalFailure>();
47 }
48
49 auto data = Json::parse(jsonFile, nullptr, false);
50 if (data.is_discarded())
51 {
52 log<level::ERR>("Parsing channel cipher suites JSON failed");
53 elog<InternalFailure>();
54 }
55
56 for (const auto& record : data)
57 {
58 if (record.find(oem) != record.end())
59 {
60 // OEM cipher suite - 0xC1
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053061 cipherRecords.push_back(oemCipherSuite);
Tom Joseph7cbe2282018-03-21 21:17:33 +053062 // Cipher Suite ID
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053063 cipherRecords.push_back(record.value(cipher, 0));
Tom Joseph7cbe2282018-03-21 21:17:33 +053064 // OEM IANA - 3 bytes
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053065 cipherRecords.push_back(record.value(oem, 0));
66 cipherRecords.push_back(record.value(oem, 0) >> 8);
67 cipherRecords.push_back(record.value(oem, 0) >> 16);
Tom Joseph7cbe2282018-03-21 21:17:33 +053068 }
69 else
70 {
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053071 // Standard cipher suite - 0xC0
72 cipherRecords.push_back(stdCipherSuite);
Tom Joseph7cbe2282018-03-21 21:17:33 +053073 // Cipher Suite ID
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053074 cipherRecords.push_back(record.value(cipher, 0));
Tom Joseph7cbe2282018-03-21 21:17:33 +053075 }
76
77 // Authentication algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053078 cipherRecords.push_back(record.value(auth, 0));
79 supportedAlgorithmSet.insert(record.value(auth, 0));
80
Tom Joseph7cbe2282018-03-21 21:17:33 +053081 // Integrity algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053082 cipherRecords.push_back(record.value(integrity, 0) | integrityTag);
83 supportedAlgorithmSet.insert(record.value(integrity, 0) | integrityTag);
84
Tom Joseph7cbe2282018-03-21 21:17:33 +053085 // Confidentiality algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053086 cipherRecords.push_back(record.value(conf, 0) | confTag);
87 supportedAlgorithmSet.insert(record.value(conf, 0) | confTag);
Tom Joseph7cbe2282018-03-21 21:17:33 +053088 }
89
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053090 // copy the set to supportedAlgorithmRecord which is vector based.
91 std::copy(supportedAlgorithmSet.begin(), supportedAlgorithmSet.end(),
92 std::back_inserter(supportedAlgorithmRecords));
93
94 return std::make_pair(cipherRecords, supportedAlgorithmRecords);
Tom Joseph7cbe2282018-03-21 21:17:33 +053095}
96
Patrick Venture0b02be92018-08-31 11:55:55 -070097} // namespace cipher
Tom Joseph7cbe2282018-03-21 21:17:33 +053098
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +000099/** @brief this command is used to look up what authentication, integrity,
100 * confidentiality algorithms are supported.
101 *
102 * @ param ctx - context pointer
103 * @ param channelNumber - channel number
104 * @ param payloadType - payload type
105 * @ param listIndex - list index
106 * @ param algoSelectBit - list algorithms
107 *
108 * @returns ipmi completion code plus response data
109 * - rspChannel - channel number for authentication algorithm.
110 * - rspRecords - cipher suite records.
111 **/
112ipmi::RspType<uint8_t, // Channel Number
113 std::vector<uint8_t> // Cipher Records
114 >
115 getChannelCipherSuites(ipmi::Context::ptr ctx, uint4_t channelNumber,
116 uint4_t reserved1, uint8_t payloadType,
117 uint6_t listIndex, uint1_t reserved2,
118 uint1_t algoSelectBit)
Tom Joseph7cbe2282018-03-21 21:17:33 +0530119{
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530120 static std::vector<uint8_t> cipherRecords;
121 static std::vector<uint8_t> supportedAlgorithms;
Tom Joseph7cbe2282018-03-21 21:17:33 +0530122 static auto recordInit = false;
123
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000124 uint8_t rspChannel = ipmi::convertCurrentChannelNum(
125 static_cast<uint8_t>(channelNumber), ctx->channel);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530126
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000127 if (!ipmi::isValidChannel(rspChannel) || reserved1 != 0 || reserved2 != 0)
Tom Joseph7cbe2282018-03-21 21:17:33 +0530128 {
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000129 return ipmi::responseInvalidFieldRequest();
Tom Joseph7cbe2282018-03-21 21:17:33 +0530130 }
jayaprakash Mutyala69daefa2019-10-03 19:36:49 +0000131 if (!ipmi::isValidPayloadType(static_cast<ipmi::PayloadType>(payloadType)))
132 {
133 log<level::DEBUG>("Get channel cipher suites - Invalid payload type");
134 constexpr uint8_t ccPayloadTypeNotSupported = 0x80;
135 return ipmi::response(ccPayloadTypeNotSupported);
136 }
Tom Joseph7cbe2282018-03-21 21:17:33 +0530137
Tom Joseph7cbe2282018-03-21 21:17:33 +0530138 if (!recordInit)
139 {
140 try
141 {
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530142 std::tie(cipherRecords, supportedAlgorithms) =
143 cipher::getCipherRecords();
Tom Joseph7cbe2282018-03-21 21:17:33 +0530144 recordInit = true;
145 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700146 catch (const std::exception& e)
Tom Joseph7cbe2282018-03-21 21:17:33 +0530147 {
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000148 return ipmi::responseUnspecifiedError();
Tom Joseph7cbe2282018-03-21 21:17:33 +0530149 }
150 }
151
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000152 const std::vector<uint8_t>& records =
153 algoSelectBit ? cipherRecords : supportedAlgorithms;
154 static constexpr auto respSize = 16;
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530155
Ayushi Smritid7dadc22019-09-03 11:43:45 +0530156 // Session support is available in active LAN channels.
157 if ((ipmi::getChannelSessionSupport(rspChannel) ==
158 ipmi::EChannelSessSupported::none) ||
159 !(ipmi::doesDeviceExist(rspChannel)))
160 {
161 log<level::DEBUG>("Get channel cipher suites - Device does not exist");
162 return ipmi::responseInvalidFieldRequest();
163 }
164
Tom Joseph7cbe2282018-03-21 21:17:33 +0530165 // List index(00h-3Fh), 0h selects the first set of 16, 1h selects the next
166 // set of 16 and so on.
Tom Joseph7cbe2282018-03-21 21:17:33 +0530167
168 // Calculate the number of record data bytes to be returned.
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000169 auto start =
170 std::min(static_cast<size_t>(listIndex) * respSize, records.size());
171 auto end = std::min((static_cast<size_t>(listIndex) * respSize) + respSize,
172 records.size());
Tom Joseph7cbe2282018-03-21 21:17:33 +0530173 auto size = end - start;
174
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000175 std::vector<uint8_t> rspRecords;
176 std::copy_n(records.data() + start, size, std::back_inserter(rspRecords));
Tom Joseph7cbe2282018-03-21 21:17:33 +0530177
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000178 return ipmi::responseSuccess(rspChannel, rspRecords);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530179}
Tom Joseph13227682018-08-10 01:05:21 +0530180
181template <typename... ArgTypes>
182static int executeCmd(const char* path, ArgTypes&&... tArgs)
183{
184 boost::process::child execProg(path, const_cast<char*>(tArgs)...);
185 execProg.wait();
186 return execProg.exit_code();
187}
188
189/** @brief Enable the network IPMI service on the specified ethernet interface.
190 *
191 * @param[in] intf - ethernet interface on which to enable IPMI
192 */
193void enableNetworkIPMI(const std::string& intf)
194{
195 // Check if there is a iptable filter to drop IPMI packets for the
196 // interface.
197 auto retCode =
198 executeCmd("/usr/sbin/iptables", "-C", "INPUT", "-p", "udp", "-i",
199 intf.c_str(), "--dport", "623", "-j", "DROP");
200
201 // If the iptable filter exists, delete the filter.
202 if (!retCode)
203 {
204 auto response =
205 executeCmd("/usr/sbin/iptables", "-D", "INPUT", "-p", "udp", "-i",
206 intf.c_str(), "--dport", "623", "-j", "DROP");
207
208 if (response)
209 {
210 log<level::ERR>("Dropping the iptables filter failed",
211 entry("INTF=%s", intf.c_str()),
212 entry("RETURN_CODE:%d", response));
213 }
214 }
215}
216
217/** @brief Disable the network IPMI service on the specified ethernet interface.
218 *
219 * @param[in] intf - ethernet interface on which to disable IPMI
220 */
221void disableNetworkIPMI(const std::string& intf)
222{
223 // Check if there is a iptable filter to drop IPMI packets for the
224 // interface.
225 auto retCode =
226 executeCmd("/usr/sbin/iptables", "-C", "INPUT", "-p", "udp", "-i",
227 intf.c_str(), "--dport", "623", "-j", "DROP");
228
229 // If the iptable filter does not exist, add filter to drop network IPMI
230 // packets
231 if (retCode)
232 {
233 auto response =
234 executeCmd("/usr/sbin/iptables", "-I", "INPUT", "-p", "udp", "-i",
235 intf.c_str(), "--dport", "623", "-j", "DROP");
236
237 if (response)
238 {
239 log<level::ERR>("Inserting iptables filter failed",
240 entry("INTF=%s", intf.c_str()),
241 entry("RETURN_CODE:%d", response));
242 }
243 }
244}