blob: 29e3340542d4cd3d0f38c11941d6fb7f3b13e73d [file] [log] [blame]
Tom Josephf0ca5132016-08-09 08:16:12 -05001#pragma once
2
3#include <chrono>
4#include <exception>
5#include <list>
6#include <memory>
7#include <string>
8#include <vector>
9
10#include "auth_algo.hpp"
Tom Joseph638d0662017-01-10 16:02:07 +053011#include "integrity_algo.hpp"
Tom Josephf0ca5132016-08-09 08:16:12 -050012#include "endian.hpp"
13#include "socket_channel.hpp"
14
15namespace session
16{
17
18using namespace std::chrono_literals;
19using SessionID = uint32_t;
20
21enum class Privilege : uint8_t
22{
23 HIGHEST_MATCHING,
24 CALLBACK,
25 USER,
26 OPERATOR,
27 ADMIN,
28 OEM,
29};
30
31enum class State
32{
33 INACTIVE, // Session is not in use
34 SETUP_IN_PROGRESS, // Session Setup Sequence is progressing
35 ACTIVE, // Session is active
36 TEAR_DOWN_IN_PROGRESS,// When Closing Session
37};
38
39// Seconds of inactivity allowed during session setup stage
40constexpr auto SESSION_SETUP_TIMEOUT = 5s;
41// Seconds of inactivity allowed when session is active
42constexpr auto SESSION_INACTIVITY_TIMEOUT = 60s;
43
44/*
45 * @struct SequenceNumbers Session Sequence Numbers
46 *
47 * IPMI v2.0 RMCP+ Session Sequence Numbers are used for rejecting packets that
48 * may have been duplicated by the network or intentionally replayed. There are
49 * two sets of Session SequenceNumbers for a given session.One set of inbound
50 * and outbound sequence numbers is used for authenticated (signed) packets,
51 * and the other set is used for unauthenticated packets.
52 *
53 * The individual Session Sequence Numbers is are initialized to zero whenever
54 * a session is created and incremented by one at the start of outbound
55 * processing for a given packet (i.e. the first transmitted packet has a ‘1’
56 * as the sequence number, not 0). Session Sequence numbers are incremented for
57 * every packet that is transmitted by a given sender, regardless of whether
58 * the payload for the packet is a ‘retry’ or not.
59 */
60struct SequenceNumbers
61{
62 auto get(bool inbound = true) const
63 {
64 return inbound ? in : out;
65 }
66
67 void set(uint32_t seqNumber, bool inbound = true)
68 {
69 inbound ? (in = seqNumber) : (out = seqNumber);
70 }
71
72 auto increment()
73 {
74 return ++out;
75 }
76
77 private:
78 uint32_t in;
79 uint32_t out;
80};
81/*
82 * @class Session
83 *
84 * Encapsulates the data related to an IPMI Session
85 *
86 * Authenticated IPMI communication to the BMC is accomplished by establishing
87 * a session. Once established, a session is identified by a Session ID. The
88 * Session ID may be thought of as a handle that identifies a connection between
89 * a given remote user and the BMC. The specification supports having multiple
90 * active sessions established with the BMC. It is recommended that a BMC
91 * implementation support at least four simultaneous sessions
92 */
93class Session
94{
95 public:
96
97 Session() = default;
98 ~Session() = default;
99 Session(const Session&) = delete;
100 Session& operator=(const Session&) = delete;
101 Session(Session&&) = default;
102 Session& operator=(Session&&) = default;
103
104 /*
105 * @brief Session Constructor
106 *
107 * This is issued by the Session Manager when a session is started for
108 * the Open SessionRequest command
109 *
110 * @param[in] inRemoteConsoleSessID - Remote Console Session ID
111 * @param[in] priv - Privilege Level requested in the Command
112 */
113 Session(SessionID inRemoteConsoleSessID, Privilege priv):
114 curPrivLevel(priv),
115 bmcSessionID(std::rand()),
116 remoteConsoleSessionID(inRemoteConsoleSessID) {}
117
118 auto getBMCSessionID() const
119 {
120 return bmcSessionID;
121 }
122
123 auto getRCSessionID() const
124 {
125 return remoteConsoleSessionID;
126 }
127
128 auto getAuthAlgo() const
129 {
130 if(authAlgoInterface)
131 {
132 return authAlgoInterface.get();
133 }
134 else
135 {
136 throw std::runtime_error("Authentication Algorithm Empty");
137 }
138 }
139
140 void setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface>&&
141 inAuthAlgo)
142 {
143 authAlgoInterface = std::move(inAuthAlgo);
144 }
145
Tom Joseph638d0662017-01-10 16:02:07 +0530146 /*
147 * @brief Get Session's Integrity Algorithm
148 *
149 * @return pointer to the integrity algorithm
150 */
151 auto getIntegrityAlgo() const
152 {
153 if(integrityAlgoInterface)
154 {
155 return integrityAlgoInterface.get();
156 }
157 else
158 {
159 throw std::runtime_error("Integrity Algorithm Empty");
160 }
161 }
162
163 /*
164 * @brief Set Session's Integrity Algorithm
165 *
166 * @param[in] integrityAlgo - unique pointer to integrity algorithm
167 * instance
168 */
169 void setIntegrityAlgo(
170 std::unique_ptr<cipher::integrity::Interface>&& integrityAlgo)
171 {
172 integrityAlgoInterface = std::move(integrityAlgo);
173 }
174
Tom Josephf0ca5132016-08-09 08:16:12 -0500175 void updateLastTransactionTime()
176 {
177 lastTime = std::chrono::steady_clock::now();
178 }
179
180 /*
181 * @brief Session Active Status
182 *
183 * Session Active status is decided upon the Session State and the last
184 * transaction time is compared against the session inactivity timeout.
185 *
186 */
187 bool isSessionActive();
188
189 /*
190 * @brief Session's Current Privilege Level
191 */
192 Privilege curPrivLevel;
193
194 /*
195 * @brief Session's Maximum Privilege Level
196 */
197 Privilege maxPrivLevel = Privilege::CALLBACK;
198
199 SequenceNumbers sequenceNums; // Session Sequence Numbers
200 State state = State::INACTIVE; // Session State
201 std::vector<char> userName; // User Name
202
203 private:
204
205 SessionID bmcSessionID = 0; //BMC Session ID
206 SessionID remoteConsoleSessionID = 0; //Remote Console Session ID
207
208 // Authentication Algorithm Interface for the Session
209 std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface;
210
Tom Joseph638d0662017-01-10 16:02:07 +0530211 // Integrity Algorithm Interface for the Session
212 std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface =
213 nullptr;
214
Tom Josephf0ca5132016-08-09 08:16:12 -0500215 // Last Transaction Time
216 decltype(std::chrono::steady_clock::now()) lastTime;
217};
218
219} // namespace session