1 #include "sessions_manager.hpp" 2 3 #include "main.hpp" 4 #include "session.hpp" 5 6 #include <algorithm> 7 #include <cstdlib> 8 #include <iomanip> 9 #include <memory> 10 #include <phosphor-logging/log.hpp> 11 #include <sdbusplus/asio/connection.hpp> 12 #include <user_channel/channel_layer.hpp> 13 14 using namespace phosphor::logging; 15 16 namespace session 17 { 18 19 static std::array<uint8_t, session::maxNetworkInstanceSupported> 20 ipmiNetworkChannelNumList = {0}; 21 22 void Manager::setNetworkInstance(void) 23 { 24 25 uint8_t index = 0, ch = 1; 26 // Constructing net-ipmid instances list based on channel info 27 // valid channel start from 1 to 15 and assuming max 4 LAN channel 28 // supported 29 30 while (ch < ipmi::maxIpmiChannels && 31 index < session::maxNetworkInstanceSupported) 32 { 33 ipmi::ChannelInfo chInfo; 34 ipmi::getChannelInfo(ch, chInfo); 35 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) == 36 ipmi::EChannelMediumType::lan8032) 37 { 38 39 if (getInterfaceIndex() == ch) 40 { 41 ipmiNetworkInstance = index; 42 } 43 44 ipmiNetworkChannelNumList[index] = ch; 45 index++; 46 } 47 ch++; 48 } 49 } 50 51 uint8_t Manager::getNetworkInstance(void) 52 { 53 return ipmiNetworkInstance; 54 } 55 56 Manager::Manager() 57 { 58 } 59 60 void Manager::managerInit(const std::string& channel) 61 { 62 63 /* 64 * Session ID is 0000_0000h for messages that are sent outside the session. 65 * The session setup commands are sent on this session, so when the session 66 * manager comes up, is creates the Session ID 0000_0000h. It is active 67 * through the lifetime of the Session Manager. 68 */ 69 70 objManager = std::make_unique<sdbusplus::server::manager::manager>( 71 *getSdBus(), session::sessionManagerRootPath); 72 73 auto objPath = 74 std::string(session::sessionManagerRootPath) + "/" + channel + "/0"; 75 76 chName = channel; 77 setNetworkInstance(); 78 sessionsMap.emplace( 79 0, std::make_shared<Session>(*getSdBus(), objPath.c_str(), 0, 0, 0)); 80 } 81 82 std::shared_ptr<Session> 83 Manager::startSession(SessionID remoteConsoleSessID, Privilege priv, 84 cipher::rakp_auth::Algorithms authAlgo, 85 cipher::integrity::Algorithms intAlgo, 86 cipher::crypt::Algorithms cryptAlgo) 87 { 88 std::shared_ptr<Session> session = nullptr; 89 SessionID bmcSessionID = 0; 90 cleanStaleEntries(); 91 uint8_t sessionHandle = 0; 92 93 auto activeSessions = sessionsMap.size() - session::maxSessionlessCount; 94 95 if (activeSessions < session::maxSessionCountPerChannel) 96 { 97 do 98 { 99 bmcSessionID = (crypto::prng::rand()); 100 bmcSessionID &= session::multiIntfaceSessionIDMask; 101 // In sessionID , BIT 31 BIT30 are used for netipmid instance 102 bmcSessionID |= ipmiNetworkInstance << 30; 103 /* 104 * Every IPMI Session has two ID's attached to it Remote Console 105 * Session ID and BMC Session ID. The remote console ID is passed 106 * along with the Open Session request command. The BMC session ID 107 * is the key for the session map and is generated using std::rand. 108 * There is a rare chance for collision of BMC session ID, so the 109 * following check validates that. In the case of collision the 110 * created session is reset and a new session is created for 111 * validating collision. 112 */ 113 auto iterator = sessionsMap.find(bmcSessionID); 114 if (iterator != sessionsMap.end()) 115 { 116 // Detected BMC Session ID collisions 117 continue; 118 } 119 else 120 { 121 break; 122 } 123 } while (1); 124 125 sessionHandle = storeSessionHandle(bmcSessionID); 126 127 if (!sessionHandle) 128 { 129 throw std::runtime_error( 130 "Invalid sessionHandle - No sessionID slot "); 131 } 132 sessionHandle &= session::multiIntfaceSessionHandleMask; 133 // In sessionID , BIT 31 BIT30 are used for netipmid instance 134 sessionHandle |= ipmiNetworkInstance << 6; 135 std::stringstream sstream; 136 sstream << std::hex << bmcSessionID; 137 std::stringstream shstream; 138 shstream << std::hex << (int)sessionHandle; 139 auto objPath = std::string(session::sessionManagerRootPath) + "/" + 140 chName + "/" + sstream.str() + "_" + shstream.str(); 141 session = std::make_shared<Session>(*getSdBus(), objPath.c_str(), 142 remoteConsoleSessID, bmcSessionID, 143 static_cast<uint8_t>(priv)); 144 145 // Set the Authentication Algorithm 146 switch (authAlgo) 147 { 148 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1: 149 { 150 session->setAuthAlgo( 151 std::make_unique<cipher::rakp_auth::AlgoSHA1>(intAlgo, 152 cryptAlgo)); 153 break; 154 } 155 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA256: 156 { 157 session->setAuthAlgo( 158 std::make_unique<cipher::rakp_auth::AlgoSHA256>(intAlgo, 159 cryptAlgo)); 160 break; 161 } 162 default: 163 { 164 throw std::runtime_error("Invalid Authentication Algorithm"); 165 } 166 } 167 168 sessionsMap.emplace(bmcSessionID, session); 169 session->sessionHandle(sessionHandle); 170 171 return session; 172 } 173 174 log<level::INFO>("No free RMCP+ sessions left"); 175 176 throw std::runtime_error("No free sessions left"); 177 } 178 179 bool Manager::stopSession(SessionID bmcSessionID) 180 { 181 auto iter = sessionsMap.find(bmcSessionID); 182 if (iter != sessionsMap.end()) 183 { 184 iter->second->state( 185 static_cast<uint8_t>(session::State::tearDownInProgress)); 186 return true; 187 } 188 else 189 { 190 return false; 191 } 192 } 193 194 std::shared_ptr<Session> Manager::getSession(SessionID sessionID, 195 RetrieveOption option) 196 { 197 switch (option) 198 { 199 case RetrieveOption::BMC_SESSION_ID: 200 { 201 auto iter = sessionsMap.find(sessionID); 202 if (iter != sessionsMap.end()) 203 { 204 return iter->second; 205 } 206 break; 207 } 208 case RetrieveOption::RC_SESSION_ID: 209 { 210 auto iter = std::find_if( 211 sessionsMap.begin(), sessionsMap.end(), 212 [sessionID]( 213 const std::pair<const uint32_t, std::shared_ptr<Session>>& 214 in) -> bool { 215 return sessionID == in.second->getRCSessionID(); 216 }); 217 218 if (iter != sessionsMap.end()) 219 { 220 return iter->second; 221 } 222 break; 223 } 224 default: 225 throw std::runtime_error("Invalid retrieval option"); 226 } 227 228 throw std::runtime_error("Session ID not found"); 229 } 230 231 void Manager::cleanStaleEntries() 232 { 233 for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();) 234 { 235 236 auto session = iter->second; 237 if ((session->getBMCSessionID() != session::sessionZero) && 238 !(session->isSessionActive(session->state()))) 239 { 240 sessionHandleMap[getSessionHandle(session->getBMCSessionID())] = 0; 241 iter = sessionsMap.erase(iter); 242 } 243 else 244 { 245 ++iter; 246 } 247 } 248 } 249 250 uint8_t Manager::storeSessionHandle(SessionID bmcSessionID) 251 { 252 // Handler index 0 is reserved for invalid session. 253 // index starts with 1, for direct usage. Index 0 reserved 254 for (uint8_t i = 1; i <= session::maxSessionCountPerChannel; i++) 255 { 256 if (sessionHandleMap[i] == 0) 257 { 258 sessionHandleMap[i] = bmcSessionID; 259 return i; 260 } 261 } 262 return 0; 263 } 264 265 uint32_t Manager::getSessionIDbyHandle(uint8_t sessionHandle) const 266 { 267 if (sessionHandle <= session::maxSessionCountPerChannel) 268 { 269 return sessionHandleMap[sessionHandle]; 270 } 271 return 0; 272 } 273 274 uint8_t Manager::getSessionHandle(SessionID bmcSessionID) const 275 { 276 277 // Handler index 0 is reserved for invalid session. 278 // index starts with 1, for direct usage. Index 0 reserved 279 280 for (uint8_t i = 1; i <= session::maxSessionCountPerChannel; i++) 281 { 282 if (sessionHandleMap[i] == bmcSessionID) 283 { 284 return (i); 285 } 286 } 287 return 0; 288 } 289 uint8_t Manager::getActiveSessionCount() const 290 { 291 292 return (std::count_if( 293 sessionsMap.begin(), sessionsMap.end(), 294 [](const std::pair<const uint32_t, std::shared_ptr<Session>>& in) 295 -> bool { 296 return in.second->state() == 297 static_cast<uint8_t>(session::State::active); 298 })); 299 } 300 } // namespace session 301