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 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA256: 78 { 79 session->setAuthAlgo( 80 std::make_unique<cipher::rakp_auth::AlgoSHA256>( 81 intAlgo, cryptAlgo)); 82 break; 83 } 84 default: 85 { 86 throw std::runtime_error("Invalid Authentication Algorithm"); 87 } 88 } 89 sessionID = session->getBMCSessionID(); 90 sessionsMap.emplace(sessionID, std::move(session)); 91 } 92 else 93 { 94 std::cerr << "E> No free sessions left: Active: " << activeSessions << 95 " Allowed: " << 96 MAX_SESSION_COUNT << "\n"; 97 98 for (const auto& iterator : sessionsMap) 99 { 100 std::cerr << "E> Active Session: 0x" << std::hex 101 << std::setfill('0') << std::setw(8) 102 << (iterator.second)->getBMCSessionID() << "\n"; 103 } 104 throw std::runtime_error("No free sessions left"); 105 } 106 107 return getSession(sessionID); 108 } 109 110 bool Manager::stopSession(SessionID bmcSessionID) 111 { 112 auto iter = sessionsMap.find(bmcSessionID); 113 if (iter != sessionsMap.end()) 114 { 115 iter->second->state = State::TEAR_DOWN_IN_PROGRESS; 116 return true; 117 } 118 else 119 { 120 return false; 121 } 122 } 123 124 std::weak_ptr<Session> Manager::getSession(SessionID sessionID, 125 RetrieveOption option) 126 { 127 switch (option) 128 { 129 case RetrieveOption::BMC_SESSION_ID: 130 { 131 auto iter = sessionsMap.find(sessionID); 132 if (iter != sessionsMap.end()) 133 { 134 return iter->second; 135 } 136 break; 137 } 138 case RetrieveOption::RC_SESSION_ID: 139 { 140 auto iter = std::find_if(sessionsMap.begin(), 141 sessionsMap.end(), 142 [sessionID](const std::pair<const uint32_t, 143 std::shared_ptr<Session>>& in) 144 -> bool 145 { 146 return sessionID == in.second->getRCSessionID(); 147 }); 148 149 if (iter != sessionsMap.end()) 150 { 151 return iter->second; 152 } 153 break; 154 } 155 default: 156 throw std::runtime_error("Invalid retrieval option"); 157 } 158 159 throw std::runtime_error("Session ID not found"); 160 } 161 162 void Manager::cleanStaleEntries() 163 { 164 for(auto iter = sessionsMap.begin(); iter != sessionsMap.end();) 165 { 166 auto session = iter->second; 167 if ((session->getBMCSessionID() != SESSION_ZERO) && 168 !(session->isSessionActive())) 169 { 170 iter = sessionsMap.erase(iter); 171 } 172 else 173 { 174 ++iter; 175 } 176 } 177 } 178 179 } // namespace session 180