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 { getsession::SequenceNumbers64 auto get(bool inbound = true) const 65 { 66 return inbound ? in : out; 67 } 68 setsession::SequenceNumbers69 void set(uint32_t seqNumber, bool inbound = true) 70 { 71 inbound ? (in = seqNumber) : (out = seqNumber); 72 } 73 incrementsession::SequenceNumbers74 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_t< 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 */ Session(sdbusplus::bus_t & bus,const char * path,SessionID inRemoteConsoleSessID,SessionID BMCSessionID,char priv)118 Session(sdbusplus::bus_t& bus, const char* path, 119 SessionID inRemoteConsoleSessID, SessionID BMCSessionID, 120 char priv) : SessionIface(bus, path) 121 { 122 reqMaxPrivLevel = static_cast<session::Privilege>(priv); 123 bmcSessionID = BMCSessionID; 124 remoteConsoleSessionID = inRemoteConsoleSessID; 125 } 126 getBMCSessionID() const127 auto getBMCSessionID() const 128 { 129 return bmcSessionID; 130 } 131 getRCSessionID() const132 auto getRCSessionID() const 133 { 134 return remoteConsoleSessionID; 135 } 136 getAuthAlgo() const137 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 setAuthAlgo(std::unique_ptr<cipher::rakp_auth::Interface> && inAuthAlgo)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 */ getIntegrityAlgo() const159 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 */ setIntegrityAlgo(std::unique_ptr<cipher::integrity::Interface> && integrityAlgo)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 */ isIntegrityAlgoEnabled()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 */ getCryptAlgo() const197 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 */ setCryptAlgo(std::unique_ptr<cipher::crypt::Interface> && cryptAlgo)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 */ isCryptAlgoEnabled()225 auto isCryptAlgoEnabled() 226 { 227 return cryptAlgoInterface ? true : false; 228 } 229 updateLastTransactionTime()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 */ isSessionActive(const std::chrono::microseconds & activeGrace,const std::chrono::microseconds & setupGrace)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>( 251 currentTime - 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