blob: 4d4bf19c8ea45b9065a217c7ad478d47905149dc [file] [log] [blame]
Tom Josephf0ca5132016-08-09 08:16:12 -05001#pragma once
2
Vernon Mauery9e801a22018-10-12 13:20:49 -07003#include "auth_algo.hpp"
4#include "crypt_algo.hpp"
5#include "endian.hpp"
6#include "integrity_algo.hpp"
Vernon Mauery8977d122018-10-24 14:02:16 -07007#include "prng.hpp"
Vernon Mauery9e801a22018-10-12 13:20:49 -07008#include "socket_channel.hpp"
9
Tom Josephf0ca5132016-08-09 08:16:12 -050010#include <chrono>
11#include <exception>
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053012#include <ipmid/api.hpp>
13#include <ipmid/sessiondef.hpp>
Tom Josephf0ca5132016-08-09 08:16:12 -050014#include <list>
15#include <memory>
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053016#include <sdbusplus/bus.hpp>
17#include <sdbusplus/server/object.hpp>
Tom Josephf0ca5132016-08-09 08:16:12 -050018#include <string>
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053019#include <unordered_map>
Richard Marian Thomaiyar992e53c2019-03-03 13:30:46 +053020#include <user_channel/channel_layer.hpp>
21#include <user_channel/user_layer.hpp>
Tom Josephf0ca5132016-08-09 08:16:12 -050022#include <vector>
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053023#include <xyz/openbmc_project/Ipmi/SessionInfo/server.hpp>
Tom Josephf0ca5132016-08-09 08:16:12 -050024
Tom Josephf0ca5132016-08-09 08:16:12 -050025namespace session
26{
27
28using namespace std::chrono_literals;
29using SessionID = uint32_t;
30
31enum class Privilege : uint8_t
32{
33 HIGHEST_MATCHING,
34 CALLBACK,
35 USER,
36 OPERATOR,
37 ADMIN,
38 OEM,
39};
40
Tom Josephf0ca5132016-08-09 08:16:12 -050041// Seconds of inactivity allowed during session setup stage
42constexpr auto SESSION_SETUP_TIMEOUT = 5s;
43// Seconds of inactivity allowed when session is active
44constexpr auto SESSION_INACTIVITY_TIMEOUT = 60s;
45
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053046// Mask to get only the privilege from requested maximum privlege (RAKP message
47// 1)
48constexpr uint8_t reqMaxPrivMask = 0xF;
49
Tom Joseph3563f8f2017-05-08 15:42:54 +053050/**
Tom Josephf0ca5132016-08-09 08:16:12 -050051 * @struct SequenceNumbers Session Sequence Numbers
52 *
53 * IPMI v2.0 RMCP+ Session Sequence Numbers are used for rejecting packets that
54 * may have been duplicated by the network or intentionally replayed. There are
55 * two sets of Session SequenceNumbers for a given session.One set of inbound
56 * and outbound sequence numbers is used for authenticated (signed) packets,
57 * and the other set is used for unauthenticated packets.
58 *
59 * The individual Session Sequence Numbers is are initialized to zero whenever
60 * a session is created and incremented by one at the start of outbound
61 * processing for a given packet (i.e. the first transmitted packet has a ‘1’
62 * as the sequence number, not 0). Session Sequence numbers are incremented for
63 * every packet that is transmitted by a given sender, regardless of whether
64 * the payload for the packet is a ‘retry’ or not.
65 */
66struct SequenceNumbers
67{
Vernon Mauery9e801a22018-10-12 13:20:49 -070068 auto get(bool inbound = true) const
69 {
70 return inbound ? in : out;
71 }
Tom Josephf0ca5132016-08-09 08:16:12 -050072
Vernon Mauery9e801a22018-10-12 13:20:49 -070073 void set(uint32_t seqNumber, bool inbound = true)
74 {
75 inbound ? (in = seqNumber) : (out = seqNumber);
76 }
Tom Josephf0ca5132016-08-09 08:16:12 -050077
Vernon Mauery9e801a22018-10-12 13:20:49 -070078 auto increment()
79 {
80 return ++out;
81 }
Tom Josephf0ca5132016-08-09 08:16:12 -050082
Vernon Mauery9e801a22018-10-12 13:20:49 -070083 private:
84 uint32_t in = 0;
85 uint32_t out = 0;
Tom Josephf0ca5132016-08-09 08:16:12 -050086};
Tom Joseph3563f8f2017-05-08 15:42:54 +053087/**
Tom Josephf0ca5132016-08-09 08:16:12 -050088 * @class Session
89 *
90 * Encapsulates the data related to an IPMI Session
91 *
92 * Authenticated IPMI communication to the BMC is accomplished by establishing
93 * a session. Once established, a session is identified by a Session ID. The
94 * Session ID may be thought of as a handle that identifies a connection between
95 * a given remote user and the BMC. The specification supports having multiple
96 * active sessions established with the BMC. It is recommended that a BMC
97 * implementation support at least four simultaneous sessions
98 */
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053099
100using SessionIface = sdbusplus::server::object::object<
101 sdbusplus::xyz::openbmc_project::Ipmi::server::SessionInfo>;
102
103class Session : public SessionIface
Tom Josephf0ca5132016-08-09 08:16:12 -0500104{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700105 public:
106 Session() = default;
107 ~Session() = default;
108 Session(const Session&) = delete;
109 Session& operator=(const Session&) = delete;
110 Session(Session&&) = default;
111 Session& operator=(Session&&) = default;
Tom Josephf0ca5132016-08-09 08:16:12 -0500112
Vernon Mauery9e801a22018-10-12 13:20:49 -0700113 /**
114 * @brief Session Constructor
115 *
116 * This is issued by the Session Manager when a session is started for
117 * the Open SessionRequest command
118 *
119 * @param[in] inRemoteConsoleSessID - Remote Console Session ID
120 * @param[in] priv - Privilege Level requested in the Command
121 */
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530122 Session(sdbusplus::bus::bus& bus, const char* path,
123 SessionID inRemoteConsoleSessID, SessionID BMCSessionID,
124 char priv) :
125 SessionIface(bus, path)
Vernon Mauery9e801a22018-10-12 13:20:49 -0700126 {
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530127 reqMaxPrivLevel = static_cast<session::Privilege>(priv);
128 bmcSessionID = BMCSessionID;
129 remoteConsoleSessionID = inRemoteConsoleSessID;
Vernon Mauery9e801a22018-10-12 13:20:49 -0700130 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500131
Vernon Mauery9e801a22018-10-12 13:20:49 -0700132 auto getBMCSessionID() const
133 {
134 return bmcSessionID;
135 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500136
Vernon Mauery9e801a22018-10-12 13:20:49 -0700137 auto getRCSessionID() const
138 {
139 return remoteConsoleSessionID;
140 }
141
142 auto getAuthAlgo() const
143 {
144 if (authAlgoInterface)
Tom Josephf0ca5132016-08-09 08:16:12 -0500145 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700146 return authAlgoInterface.get();
Tom Josephf0ca5132016-08-09 08:16:12 -0500147 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700148 else
Tom Josephf0ca5132016-08-09 08:16:12 -0500149 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700150 throw std::runtime_error("Authentication Algorithm Empty");
Tom Josephf0ca5132016-08-09 08:16:12 -0500151 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700152 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500153
Vernon Mauery9e801a22018-10-12 13:20:49 -0700154 void setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface>&& inAuthAlgo)
155 {
156 authAlgoInterface = std::move(inAuthAlgo);
157 }
158
159 /**
160 * @brief Get Session's Integrity Algorithm
161 *
162 * @return pointer to the integrity algorithm
163 */
164 auto getIntegrityAlgo() const
165 {
166 if (integrityAlgoInterface)
Tom Josephf0ca5132016-08-09 08:16:12 -0500167 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700168 return integrityAlgoInterface.get();
Tom Josephf0ca5132016-08-09 08:16:12 -0500169 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700170 else
Tom Josephf0ca5132016-08-09 08:16:12 -0500171 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700172 throw std::runtime_error("Integrity Algorithm Empty");
Tom Josephf0ca5132016-08-09 08:16:12 -0500173 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700174 }
Tom Josephf0ca5132016-08-09 08:16:12 -0500175
Vernon Mauery9e801a22018-10-12 13:20:49 -0700176 /**
177 * @brief Set Session's Integrity Algorithm
178 *
179 * @param[in] integrityAlgo - unique pointer to integrity algorithm
180 * instance
181 */
182 void setIntegrityAlgo(
183 std::unique_ptr<cipher::integrity::Interface>&& integrityAlgo)
184 {
185 integrityAlgoInterface = std::move(integrityAlgo);
186 }
187
188 /** @brief Check if integrity algorithm is enabled for this session.
189 *
190 * @return true if integrity algorithm is enabled else false.
191 */
192 auto isIntegrityAlgoEnabled()
193 {
194 return integrityAlgoInterface ? true : false;
195 }
196
197 /**
198 * @brief Get Session's Confidentiality Algorithm
199 *
200 * @return pointer to the confidentiality algorithm
201 */
202 auto getCryptAlgo() const
203 {
204 if (cryptAlgoInterface)
Tom Joseph638d0662017-01-10 16:02:07 +0530205 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700206 return cryptAlgoInterface.get();
Tom Joseph638d0662017-01-10 16:02:07 +0530207 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700208 else
Tom Joseph638d0662017-01-10 16:02:07 +0530209 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700210 throw std::runtime_error("Confidentiality Algorithm Empty");
Tom Joseph638d0662017-01-10 16:02:07 +0530211 }
Vernon Mauery9e801a22018-10-12 13:20:49 -0700212 }
Tom Joseph638d0662017-01-10 16:02:07 +0530213
Vernon Mauery9e801a22018-10-12 13:20:49 -0700214 /**
215 * @brief Set Session's Confidentiality Algorithm
216 *
217 * @param[in] confAlgo - unique pointer to confidentiality algorithm
218 * instance
219 */
220 void setCryptAlgo(std::unique_ptr<cipher::crypt::Interface>&& cryptAlgo)
221 {
222 cryptAlgoInterface = std::move(cryptAlgo);
223 }
Tom Josephd8c78612017-03-31 10:17:30 +0530224
Vernon Mauery9e801a22018-10-12 13:20:49 -0700225 /** @brief Check if confidentiality algorithm is enabled for this
226 * session.
227 *
228 * @return true if confidentiality algorithm is enabled else false.
229 */
230 auto isCryptAlgoEnabled()
231 {
232 return cryptAlgoInterface ? true : false;
233 }
Tom Joseph491dbd02017-01-24 18:20:41 +0530234
Vernon Mauery9e801a22018-10-12 13:20:49 -0700235 void updateLastTransactionTime()
236 {
237 lastTime = std::chrono::steady_clock::now();
238 }
Tom Joseph491dbd02017-01-24 18:20:41 +0530239
Vernon Mauery9e801a22018-10-12 13:20:49 -0700240 /**
241 * @brief Session Active Status
242 *
243 * Session Active status is decided upon the Session State and the last
244 * transaction time is compared against the session inactivity timeout.
245 *
246 */
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530247 bool isSessionActive(uint8_t sessionState)
Vernon Mauery07e5b282018-10-24 13:11:23 -0700248 {
249 auto currentTime = std::chrono::steady_clock::now();
250 auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(
251 currentTime - lastTime);
252
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530253 State state = static_cast<session::State>(sessionState);
254
Vernon Mauery07e5b282018-10-24 13:11:23 -0700255 switch (state)
256 {
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530257 case State::setupInProgress:
Vernon Mauery07e5b282018-10-24 13:11:23 -0700258 if (elapsedSeconds < SESSION_SETUP_TIMEOUT)
259 {
260 return true;
261 }
262 break;
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530263 case State::active:
Vernon Mauery07e5b282018-10-24 13:11:23 -0700264 if (elapsedSeconds < SESSION_INACTIVITY_TIMEOUT)
265 {
266 return true;
267 }
268 break;
269 default:
270 return false;
271 }
272 return false;
273 }
Tom Joseph895df942017-03-31 10:19:40 +0530274
Vernon Mauery9e801a22018-10-12 13:20:49 -0700275 /**
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +0530276 * @brief Session's Requested Maximum Privilege Level
Vernon Mauery9e801a22018-10-12 13:20:49 -0700277 */
Tom Joseph4021b1f2019-02-12 10:10:12 +0530278 Privilege reqMaxPrivLevel;
Tom Josephf0ca5132016-08-09 08:16:12 -0500279
Richard Marian Thomaiyar992e53c2019-03-03 13:30:46 +0530280 /**
281 * @brief session's user & channel access details
282 */
283 ipmi::PrivAccess sessionUserPrivAccess{};
284 ipmi::ChannelAccess sessionChannelAccess{};
285
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +0530286 SequenceNumbers sequenceNums; // Session Sequence Numbers
287 std::string userName{}; // User Name
Tom Josephf0ca5132016-08-09 08:16:12 -0500288
Vernon Mauery9e801a22018-10-12 13:20:49 -0700289 /** @brief Socket channel for communicating with the remote client.*/
290 std::shared_ptr<udpsocket::Channel> channelPtr;
Tom Josephf0ca5132016-08-09 08:16:12 -0500291
Vernon Mauery9e801a22018-10-12 13:20:49 -0700292 private:
293 SessionID bmcSessionID = 0; // BMC Session ID
294 SessionID remoteConsoleSessionID = 0; // Remote Console Session ID
Tom Josephf0ca5132016-08-09 08:16:12 -0500295
Vernon Mauery9e801a22018-10-12 13:20:49 -0700296 // Authentication Algorithm Interface for the Session
297 std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface;
Tom Josephcc27e122017-03-31 10:21:04 +0530298
Vernon Mauery9e801a22018-10-12 13:20:49 -0700299 // Integrity Algorithm Interface for the Session
300 std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface =
301 nullptr;
Tom Josephf0ca5132016-08-09 08:16:12 -0500302
Vernon Mauery9e801a22018-10-12 13:20:49 -0700303 // Confidentiality Algorithm Interface for the Session
304 std::unique_ptr<cipher::crypt::Interface> cryptAlgoInterface = nullptr;
Tom Josephf0ca5132016-08-09 08:16:12 -0500305
Vernon Mauery9e801a22018-10-12 13:20:49 -0700306 // Last Transaction Time
307 decltype(std::chrono::steady_clock::now()) lastTime;
Tom Josephf0ca5132016-08-09 08:16:12 -0500308};
309
310} // namespace session