1 #include "sessions_manager.hpp" 2 3 #include <algorithm> 4 #include <cstdlib> 5 #include <iomanip> 6 #include <iostream> 7 #include <memory> 8 9 #include "session.hpp" 10 11 namespace session 12 { 13 14 Manager::Manager() 15 { 16 /* 17 * Session ID is 0000_0000h for messages that are sent outside the session. 18 * The session setup commands are sent on this session, so when the session 19 * manager comes up, is creates the Session ID 0000_0000h. It is active 20 * through the lifetime of the Session Manager. 21 */ 22 sessionsMap.emplace(0, std::make_shared<Session>()); 23 // Seeding the pseudo-random generator 24 std::srand(std::time(0)); 25 } 26 27 std::weak_ptr<Session> Manager::startSession(SessionID remoteConsoleSessID, 28 Privilege priv, cipher::rakp_auth::Algorithms authAlgo, 29 cipher::integrity::Algorithms intAlgo, 30 cipher::crypt::Algorithms cryptAlgo) 31 { 32 std::shared_ptr<Session> session = nullptr; 33 SessionID sessionID = 0; 34 cleanStaleEntries(); 35 auto activeSessions = sessionsMap.size() - MAX_SESSIONLESS_COUNT; 36 37 if (activeSessions < MAX_SESSION_COUNT) 38 { 39 do 40 { 41 session = std::make_shared<Session>(remoteConsoleSessID, priv); 42 43 /* 44 * Every IPMI Session has two ID's attached to it Remote Console 45 * Session ID and BMC Session ID. The remote console ID is passed 46 * along with the Open Session request command. The BMC session ID 47 * is the key for the session map and is generated using std::rand. 48 * There is a rare chance for collision of BMC session ID, so the 49 * following check validates that. In the case of collision the 50 * created session is reseted and a new session is created for 51 * validating collision. 52 */ 53 auto iterator = sessionsMap.find(session->getBMCSessionID()); 54 if (iterator != sessionsMap.end()) 55 { 56 //Detected BMC Session ID collisions 57 session.reset(); 58 continue; 59 } 60 else 61 { 62 break; 63 } 64 } 65 while (1); 66 67 // Set the Authentication Algorithm 68 switch (authAlgo) 69 { 70 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1: 71 { 72 session->setAuthAlgo( 73 std::make_unique<cipher::rakp_auth::AlgoSHA1>(intAlgo, 74 cryptAlgo)); 75 break; 76 } 77 default: 78 { 79 throw std::runtime_error("Invalid Authentication Algorithm"); 80 } 81 } 82 sessionID = session->getBMCSessionID(); 83 sessionsMap.emplace(sessionID, std::move(session)); 84 } 85 else 86 { 87 std::cerr << "E> No free sessions left: Active: " << activeSessions << 88 " Allowed: " << 89 MAX_SESSION_COUNT << "\n"; 90 91 for (const auto& iterator : sessionsMap) 92 { 93 std::cerr << "E> Active Session: 0x" << std::hex 94 << std::setfill('0') << std::setw(8) 95 << (iterator.second)->getBMCSessionID() << "\n"; 96 } 97 throw std::runtime_error("No free sessions left"); 98 } 99 100 return getSession(sessionID); 101 } 102 103 bool Manager::stopSession(SessionID bmcSessionID) 104 { 105 auto iter = sessionsMap.find(bmcSessionID); 106 if (iter != sessionsMap.end()) 107 { 108 iter->second->state = State::TEAR_DOWN_IN_PROGRESS; 109 return true; 110 } 111 else 112 { 113 return false; 114 } 115 } 116 117 std::weak_ptr<Session> Manager::getSession(SessionID sessionID, 118 RetrieveOption option) 119 { 120 switch (option) 121 { 122 case RetrieveOption::BMC_SESSION_ID: 123 { 124 auto iter = sessionsMap.find(sessionID); 125 if (iter != sessionsMap.end()) 126 { 127 return iter->second; 128 } 129 break; 130 } 131 case RetrieveOption::RC_SESSION_ID: 132 { 133 auto iter = std::find_if(sessionsMap.begin(), 134 sessionsMap.end(), 135 [sessionID](const std::pair<const uint32_t, 136 std::shared_ptr<Session>>& in) 137 -> bool 138 { 139 return sessionID == in.second->getRCSessionID(); 140 }); 141 142 if (iter != sessionsMap.end()) 143 { 144 return iter->second; 145 } 146 break; 147 } 148 default: 149 throw std::runtime_error("Invalid retrieval option"); 150 } 151 152 throw std::runtime_error("Session ID not found"); 153 } 154 155 void Manager::cleanStaleEntries() 156 { 157 for(auto iter = sessionsMap.begin(); iter != sessionsMap.end();) 158 { 159 auto session = iter->second; 160 if ((session->getBMCSessionID() != SESSION_ZERO) && 161 !(session->isSessionActive())) 162 { 163 iter = sessionsMap.erase(iter); 164 } 165 else 166 { 167 ++iter; 168 } 169 } 170 } 171 172 } // namespace session 173