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