blob: 7006c92cf66a5f9428cbf63f1a8e6f1906597e15 [file] [log] [blame]
Patrick Venture5794fcf2017-10-26 11:11:14 -07001#include "channel.hpp"
Patrick Venture5794fcf2017-10-26 11:11:14 -07002
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include "transporthandler.hpp"
Johnathan Mantey74a21022018-12-13 13:17:56 -08004#include "user_channel/channel_layer.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07005
Patrick Venture5794fcf2017-10-26 11:11:14 -07006#include <arpa/inet.h>
7
Tom Joseph13227682018-08-10 01:05:21 +05308#include <boost/process/child.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <fstream>
Vernon Mauery33250242019-03-12 16:49:26 -070010#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070011#include <ipmid/utils.hpp>
Patrick Venture5794fcf2017-10-26 11:11:14 -070012#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070013#include <phosphor-logging/log.hpp>
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053014#include <set>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <string>
16#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture5794fcf2017-10-26 11:11:14 -070017
18using namespace phosphor::logging;
19using namespace sdbusplus::xyz::openbmc_project::Common::Error;
20
Tom Joseph7cbe2282018-03-21 21:17:33 +053021namespace cipher
22{
23
24/** @brief Get the supported Cipher records
25 *
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053026 * The cipher records are read from the JSON file and converted into
27 * 1. cipher suite record format mentioned in the IPMI specification. The
28 * records can be either OEM or standard cipher. Each json entry is parsed and
29 * converted into the cipher record format and pushed into the vector.
30 * 2. Algorithms listed in vector format
Tom Joseph7cbe2282018-03-21 21:17:33 +053031 *
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053032 * @return pair of vector containing 1. all the cipher suite records. 2.
33 * Algorithms supported
Tom Joseph7cbe2282018-03-21 21:17:33 +053034 *
35 */
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053036std::pair<std::vector<uint8_t>, std::vector<uint8_t>> getCipherRecords()
Tom Joseph7cbe2282018-03-21 21:17:33 +053037{
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053038 std::vector<uint8_t> cipherRecords;
39 std::vector<uint8_t> supportedAlgorithmRecords;
40 // create set to get the unique supported algorithms
41 std::set<uint8_t> supportedAlgorithmSet;
Tom Joseph7cbe2282018-03-21 21:17:33 +053042
43 std::ifstream jsonFile(configFile);
44 if (!jsonFile.is_open())
45 {
46 log<level::ERR>("Channel Cipher suites file not found");
47 elog<InternalFailure>();
48 }
49
50 auto data = Json::parse(jsonFile, nullptr, false);
51 if (data.is_discarded())
52 {
53 log<level::ERR>("Parsing channel cipher suites JSON failed");
54 elog<InternalFailure>();
55 }
56
57 for (const auto& record : data)
58 {
59 if (record.find(oem) != record.end())
60 {
61 // OEM cipher suite - 0xC1
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053062 cipherRecords.push_back(oemCipherSuite);
Tom Joseph7cbe2282018-03-21 21:17:33 +053063 // Cipher Suite ID
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053064 cipherRecords.push_back(record.value(cipher, 0));
Tom Joseph7cbe2282018-03-21 21:17:33 +053065 // OEM IANA - 3 bytes
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053066 cipherRecords.push_back(record.value(oem, 0));
67 cipherRecords.push_back(record.value(oem, 0) >> 8);
68 cipherRecords.push_back(record.value(oem, 0) >> 16);
Tom Joseph7cbe2282018-03-21 21:17:33 +053069 }
70 else
71 {
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053072 // Standard cipher suite - 0xC0
73 cipherRecords.push_back(stdCipherSuite);
Tom Joseph7cbe2282018-03-21 21:17:33 +053074 // Cipher Suite ID
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053075 cipherRecords.push_back(record.value(cipher, 0));
Tom Joseph7cbe2282018-03-21 21:17:33 +053076 }
77
78 // Authentication algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053079 cipherRecords.push_back(record.value(auth, 0));
80 supportedAlgorithmSet.insert(record.value(auth, 0));
81
Tom Joseph7cbe2282018-03-21 21:17:33 +053082 // Integrity algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053083 cipherRecords.push_back(record.value(integrity, 0) | integrityTag);
84 supportedAlgorithmSet.insert(record.value(integrity, 0) | integrityTag);
85
Tom Joseph7cbe2282018-03-21 21:17:33 +053086 // Confidentiality algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053087 cipherRecords.push_back(record.value(conf, 0) | confTag);
88 supportedAlgorithmSet.insert(record.value(conf, 0) | confTag);
Tom Joseph7cbe2282018-03-21 21:17:33 +053089 }
90
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053091 // copy the set to supportedAlgorithmRecord which is vector based.
92 std::copy(supportedAlgorithmSet.begin(), supportedAlgorithmSet.end(),
93 std::back_inserter(supportedAlgorithmRecords));
94
95 return std::make_pair(cipherRecords, supportedAlgorithmRecords);
Tom Joseph7cbe2282018-03-21 21:17:33 +053096}
97
Patrick Venture0b02be92018-08-31 11:55:55 -070098} // namespace cipher
Tom Joseph7cbe2282018-03-21 21:17:33 +053099
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000100/** @brief this command is used to look up what authentication, integrity,
101 * confidentiality algorithms are supported.
102 *
103 * @ param ctx - context pointer
104 * @ param channelNumber - channel number
105 * @ param payloadType - payload type
106 * @ param listIndex - list index
107 * @ param algoSelectBit - list algorithms
108 *
109 * @returns ipmi completion code plus response data
110 * - rspChannel - channel number for authentication algorithm.
111 * - rspRecords - cipher suite records.
112 **/
113ipmi::RspType<uint8_t, // Channel Number
114 std::vector<uint8_t> // Cipher Records
115 >
116 getChannelCipherSuites(ipmi::Context::ptr ctx, uint4_t channelNumber,
117 uint4_t reserved1, uint8_t payloadType,
118 uint6_t listIndex, uint1_t reserved2,
119 uint1_t algoSelectBit)
Tom Joseph7cbe2282018-03-21 21:17:33 +0530120{
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530121 static std::vector<uint8_t> cipherRecords;
122 static std::vector<uint8_t> supportedAlgorithms;
Tom Joseph7cbe2282018-03-21 21:17:33 +0530123 static auto recordInit = false;
124
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000125 uint8_t rspChannel = ipmi::convertCurrentChannelNum(
126 static_cast<uint8_t>(channelNumber), ctx->channel);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530127
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000128 if (!ipmi::isValidChannel(rspChannel) || reserved1 != 0 || reserved2 != 0)
Tom Joseph7cbe2282018-03-21 21:17:33 +0530129 {
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000130 return ipmi::responseInvalidFieldRequest();
Tom Joseph7cbe2282018-03-21 21:17:33 +0530131 }
132
Tom Joseph7cbe2282018-03-21 21:17:33 +0530133 if (!recordInit)
134 {
135 try
136 {
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530137 std::tie(cipherRecords, supportedAlgorithms) =
138 cipher::getCipherRecords();
Tom Joseph7cbe2282018-03-21 21:17:33 +0530139 recordInit = true;
140 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700141 catch (const std::exception& e)
Tom Joseph7cbe2282018-03-21 21:17:33 +0530142 {
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000143 return ipmi::responseUnspecifiedError();
Tom Joseph7cbe2282018-03-21 21:17:33 +0530144 }
145 }
146
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000147 const std::vector<uint8_t>& records =
148 algoSelectBit ? cipherRecords : supportedAlgorithms;
149 static constexpr auto respSize = 16;
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530150
Ayushi Smritid7dadc22019-09-03 11:43:45 +0530151 // Session support is available in active LAN channels.
152 if ((ipmi::getChannelSessionSupport(rspChannel) ==
153 ipmi::EChannelSessSupported::none) ||
154 !(ipmi::doesDeviceExist(rspChannel)))
155 {
156 log<level::DEBUG>("Get channel cipher suites - Device does not exist");
157 return ipmi::responseInvalidFieldRequest();
158 }
159
Tom Joseph7cbe2282018-03-21 21:17:33 +0530160 // List index(00h-3Fh), 0h selects the first set of 16, 1h selects the next
161 // set of 16 and so on.
Tom Joseph7cbe2282018-03-21 21:17:33 +0530162
163 // Calculate the number of record data bytes to be returned.
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000164 auto start =
165 std::min(static_cast<size_t>(listIndex) * respSize, records.size());
166 auto end = std::min((static_cast<size_t>(listIndex) * respSize) + respSize,
167 records.size());
Tom Joseph7cbe2282018-03-21 21:17:33 +0530168 auto size = end - start;
169
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000170 std::vector<uint8_t> rspRecords;
171 std::copy_n(records.data() + start, size, std::back_inserter(rspRecords));
Tom Joseph7cbe2282018-03-21 21:17:33 +0530172
Ayushi Smriti5c3b72c2019-08-30 13:47:31 +0000173 return ipmi::responseSuccess(rspChannel, rspRecords);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530174}
Tom Joseph13227682018-08-10 01:05:21 +0530175
176template <typename... ArgTypes>
177static int executeCmd(const char* path, ArgTypes&&... tArgs)
178{
179 boost::process::child execProg(path, const_cast<char*>(tArgs)...);
180 execProg.wait();
181 return execProg.exit_code();
182}
183
184/** @brief Enable the network IPMI service on the specified ethernet interface.
185 *
186 * @param[in] intf - ethernet interface on which to enable IPMI
187 */
188void enableNetworkIPMI(const std::string& intf)
189{
190 // Check if there is a iptable filter to drop IPMI packets for the
191 // interface.
192 auto retCode =
193 executeCmd("/usr/sbin/iptables", "-C", "INPUT", "-p", "udp", "-i",
194 intf.c_str(), "--dport", "623", "-j", "DROP");
195
196 // If the iptable filter exists, delete the filter.
197 if (!retCode)
198 {
199 auto response =
200 executeCmd("/usr/sbin/iptables", "-D", "INPUT", "-p", "udp", "-i",
201 intf.c_str(), "--dport", "623", "-j", "DROP");
202
203 if (response)
204 {
205 log<level::ERR>("Dropping the iptables filter failed",
206 entry("INTF=%s", intf.c_str()),
207 entry("RETURN_CODE:%d", response));
208 }
209 }
210}
211
212/** @brief Disable the network IPMI service on the specified ethernet interface.
213 *
214 * @param[in] intf - ethernet interface on which to disable IPMI
215 */
216void disableNetworkIPMI(const std::string& intf)
217{
218 // Check if there is a iptable filter to drop IPMI packets for the
219 // interface.
220 auto retCode =
221 executeCmd("/usr/sbin/iptables", "-C", "INPUT", "-p", "udp", "-i",
222 intf.c_str(), "--dport", "623", "-j", "DROP");
223
224 // If the iptable filter does not exist, add filter to drop network IPMI
225 // packets
226 if (retCode)
227 {
228 auto response =
229 executeCmd("/usr/sbin/iptables", "-I", "INPUT", "-p", "udp", "-i",
230 intf.c_str(), "--dport", "623", "-j", "DROP");
231
232 if (response)
233 {
234 log<level::ERR>("Inserting iptables filter failed",
235 entry("INTF=%s", intf.c_str()),
236 entry("RETURN_CODE:%d", response));
237 }
238 }
239}