1 #pragma once 2 3 #include "auth_algo.hpp" 4 #include "crypt_algo.hpp" 5 #include "endian.hpp" 6 #include "integrity_algo.hpp" 7 #include "prng.hpp" 8 #include "socket_channel.hpp" 9 10 #include <chrono> 11 #include <exception> 12 #include <ipmid/api.hpp> 13 #include <ipmid/sessiondef.hpp> 14 #include <list> 15 #include <memory> 16 #include <sdbusplus/bus.hpp> 17 #include <sdbusplus/server/object.hpp> 18 #include <string> 19 #include <unordered_map> 20 #include <user_channel/channel_layer.hpp> 21 #include <user_channel/user_layer.hpp> 22 #include <vector> 23 #include <xyz/openbmc_project/Ipmi/SessionInfo/server.hpp> 24 25 namespace session 26 { 27 28 using namespace std::chrono_literals; 29 using SessionID = uint32_t; 30 31 enum class Privilege : uint8_t 32 { 33 HIGHEST_MATCHING, 34 CALLBACK, 35 USER, 36 OPERATOR, 37 ADMIN, 38 OEM, 39 }; 40 41 // Mask to get only the privilege from requested maximum privlege (RAKP message 42 // 1) 43 constexpr uint8_t reqMaxPrivMask = 0xF; 44 45 /** 46 * @struct SequenceNumbers Session Sequence Numbers 47 * 48 * IPMI v2.0 RMCP+ Session Sequence Numbers are used for rejecting packets that 49 * may have been duplicated by the network or intentionally replayed. There are 50 * two sets of Session SequenceNumbers for a given session.One set of inbound 51 * and outbound sequence numbers is used for authenticated (signed) packets, 52 * and the other set is used for unauthenticated packets. 53 * 54 * The individual Session Sequence Numbers is are initialized to zero whenever 55 * a session is created and incremented by one at the start of outbound 56 * processing for a given packet (i.e. the first transmitted packet has a ‘1’ 57 * as the sequence number, not 0). Session Sequence numbers are incremented for 58 * every packet that is transmitted by a given sender, regardless of whether 59 * the payload for the packet is a ‘retry’ or not. 60 */ 61 struct SequenceNumbers 62 { 63 auto get(bool inbound = true) const 64 { 65 return inbound ? in : out; 66 } 67 68 void set(uint32_t seqNumber, bool inbound = true) 69 { 70 inbound ? (in = seqNumber) : (out = seqNumber); 71 } 72 73 auto increment() 74 { 75 return ++out; 76 } 77 78 private: 79 uint32_t in = 0; 80 uint32_t out = 0; 81 }; 82 /** 83 * @class Session 84 * 85 * Encapsulates the data related to an IPMI Session 86 * 87 * Authenticated IPMI communication to the BMC is accomplished by establishing 88 * a session. Once established, a session is identified by a Session ID. The 89 * Session ID may be thought of as a handle that identifies a connection between 90 * a given remote user and the BMC. The specification supports having multiple 91 * active sessions established with the BMC. It is recommended that a BMC 92 * implementation support at least four simultaneous sessions 93 */ 94 95 using SessionIface = sdbusplus::server::object::object< 96 sdbusplus::xyz::openbmc_project::Ipmi::server::SessionInfo>; 97 98 class Session : public SessionIface 99 { 100 public: 101 Session() = default; 102 ~Session() = default; 103 Session(const Session&) = delete; 104 Session& operator=(const Session&) = delete; 105 Session(Session&&) = default; 106 Session& operator=(Session&&) = default; 107 108 /** 109 * @brief Session Constructor 110 * 111 * This is issued by the Session Manager when a session is started for 112 * the Open SessionRequest command 113 * 114 * @param[in] inRemoteConsoleSessID - Remote Console Session ID 115 * @param[in] priv - Privilege Level requested in the Command 116 */ 117 Session(sdbusplus::bus::bus& bus, const char* path, 118 SessionID inRemoteConsoleSessID, SessionID BMCSessionID, 119 char priv) : 120 SessionIface(bus, path) 121 { 122 reqMaxPrivLevel = static_cast<session::Privilege>(priv); 123 bmcSessionID = BMCSessionID; 124 remoteConsoleSessionID = inRemoteConsoleSessID; 125 } 126 127 auto getBMCSessionID() const 128 { 129 return bmcSessionID; 130 } 131 132 auto getRCSessionID() const 133 { 134 return remoteConsoleSessionID; 135 } 136 137 auto getAuthAlgo() const 138 { 139 if (authAlgoInterface) 140 { 141 return authAlgoInterface.get(); 142 } 143 else 144 { 145 throw std::runtime_error("Authentication Algorithm Empty"); 146 } 147 } 148 149 void setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface>&& inAuthAlgo) 150 { 151 authAlgoInterface = std::move(inAuthAlgo); 152 } 153 154 /** 155 * @brief Get Session's Integrity Algorithm 156 * 157 * @return pointer to the integrity algorithm 158 */ 159 auto getIntegrityAlgo() const 160 { 161 if (integrityAlgoInterface) 162 { 163 return integrityAlgoInterface.get(); 164 } 165 else 166 { 167 throw std::runtime_error("Integrity Algorithm Empty"); 168 } 169 } 170 171 /** 172 * @brief Set Session's Integrity Algorithm 173 * 174 * @param[in] integrityAlgo - unique pointer to integrity algorithm 175 * instance 176 */ 177 void setIntegrityAlgo( 178 std::unique_ptr<cipher::integrity::Interface>&& integrityAlgo) 179 { 180 integrityAlgoInterface = std::move(integrityAlgo); 181 } 182 183 /** @brief Check if integrity algorithm is enabled for this session. 184 * 185 * @return true if integrity algorithm is enabled else false. 186 */ 187 auto isIntegrityAlgoEnabled() 188 { 189 return integrityAlgoInterface ? true : false; 190 } 191 192 /** 193 * @brief Get Session's Confidentiality Algorithm 194 * 195 * @return pointer to the confidentiality algorithm 196 */ 197 auto getCryptAlgo() const 198 { 199 if (cryptAlgoInterface) 200 { 201 return cryptAlgoInterface.get(); 202 } 203 else 204 { 205 throw std::runtime_error("Confidentiality Algorithm Empty"); 206 } 207 } 208 209 /** 210 * @brief Set Session's Confidentiality Algorithm 211 * 212 * @param[in] confAlgo - unique pointer to confidentiality algorithm 213 * instance 214 */ 215 void setCryptAlgo(std::unique_ptr<cipher::crypt::Interface>&& cryptAlgo) 216 { 217 cryptAlgoInterface = std::move(cryptAlgo); 218 } 219 220 /** @brief Check if confidentiality algorithm is enabled for this 221 * session. 222 * 223 * @return true if confidentiality algorithm is enabled else false. 224 */ 225 auto isCryptAlgoEnabled() 226 { 227 return cryptAlgoInterface ? true : false; 228 } 229 230 void updateLastTransactionTime() 231 { 232 lastTime = std::chrono::steady_clock::now(); 233 } 234 235 /** 236 * @brief Session Active Status 237 * 238 * Session Active status is decided upon the Session State and the last 239 * transaction time is compared against the session inactivity timeout. 240 * 241 * @param[in] activeGrace - microseconds of idle time for active sessions 242 * @param[in] setupGrace - microseconds of idle time for sessions in setup 243 * 244 */ 245 bool isSessionActive(const std::chrono::microseconds& activeGrace, 246 const std::chrono::microseconds& setupGrace) 247 { 248 auto currentTime = std::chrono::steady_clock::now(); 249 auto elapsedMicros = 250 std::chrono::duration_cast<std::chrono::microseconds>(currentTime - 251 lastTime); 252 253 State state = static_cast<session::State>(this->state()); 254 255 switch (state) 256 { 257 case State::active: 258 if (elapsedMicros < activeGrace) 259 { 260 return true; 261 } 262 break; 263 case State::setupInProgress: 264 if (elapsedMicros < setupGrace) 265 { 266 return true; 267 } 268 break; 269 case State::tearDownInProgress: 270 break; 271 default: 272 break; 273 } 274 return false; 275 } 276 277 /** 278 * @brief Session's Requested Maximum Privilege Level 279 */ 280 Privilege reqMaxPrivLevel; 281 282 /** 283 * @brief session's user & channel access details 284 */ 285 ipmi::PrivAccess sessionUserPrivAccess{}; 286 ipmi::ChannelAccess sessionChannelAccess{}; 287 288 SequenceNumbers sequenceNums; // Session Sequence Numbers 289 std::string userName{}; // User Name 290 291 /** @brief Socket channel for communicating with the remote client.*/ 292 std::shared_ptr<udpsocket::Channel> channelPtr; 293 294 private: 295 SessionID bmcSessionID = 0; // BMC Session ID 296 SessionID remoteConsoleSessionID = 0; // Remote Console Session ID 297 298 // Authentication Algorithm Interface for the Session 299 std::unique_ptr<cipher::rakp_auth::Interface> authAlgoInterface; 300 301 // Integrity Algorithm Interface for the Session 302 std::unique_ptr<cipher::integrity::Interface> integrityAlgoInterface = 303 nullptr; 304 305 // Confidentiality Algorithm Interface for the Session 306 std::unique_ptr<cipher::crypt::Interface> cryptAlgoInterface = nullptr; 307 308 // Last Transaction Time 309 decltype(std::chrono::steady_clock::now()) lastTime; 310 }; 311 312 } // namespace session 313