blob: 0f49a2d5d8a860cd397a599feaee7066020db459 [file] [log] [blame]
#include "sessions_manager.hpp"
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <memory>
#include "session.hpp"
namespace session
{
Manager::Manager()
{
/*
* Session ID is 0000_0000h for messages that are sent outside the session.
* The session setup commands are sent on this session, so when the session
* manager comes up, is creates the Session ID 0000_0000h. It is active
* through the lifetime of the Session Manager.
*/
sessionsMap.emplace(0, std::make_shared<Session>());
// Seeding the pseudo-random generator
std::srand(std::time(0));
}
std::weak_ptr<Session> Manager::startSession(SessionID remoteConsoleSessID,
Privilege priv, cipher::rakp_auth::Algorithms authAlgo,
cipher::integrity::Algorithms intAlgo,
cipher::crypt::Algorithms cryptAlgo)
{
std::shared_ptr<Session> session = nullptr;
SessionID sessionID = 0;
cleanStaleEntries();
auto activeSessions = sessionsMap.size() - MAX_SESSIONLESS_COUNT;
if (activeSessions < MAX_SESSION_COUNT)
{
do
{
session = std::make_shared<Session>(remoteConsoleSessID, priv);
/*
* Every IPMI Session has two ID's attached to it Remote Console
* Session ID and BMC Session ID. The remote console ID is passed
* along with the Open Session request command. The BMC session ID
* is the key for the session map and is generated using std::rand.
* There is a rare chance for collision of BMC session ID, so the
* following check validates that. In the case of collision the
* created session is reseted and a new session is created for
* validating collision.
*/
auto iterator = sessionsMap.find(session->getBMCSessionID());
if (iterator != sessionsMap.end())
{
//Detected BMC Session ID collisions
session.reset();
continue;
}
else
{
break;
}
}
while (1);
// Set the Authentication Algorithm
switch (authAlgo)
{
case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1:
{
session->setAuthAlgo(
std::make_unique<cipher::rakp_auth::AlgoSHA1>(intAlgo,
cryptAlgo));
break;
}
case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA256:
{
session->setAuthAlgo(
std::make_unique<cipher::rakp_auth::AlgoSHA256>(
intAlgo, cryptAlgo));
break;
}
default:
{
throw std::runtime_error("Invalid Authentication Algorithm");
}
}
sessionID = session->getBMCSessionID();
sessionsMap.emplace(sessionID, std::move(session));
}
else
{
std::cerr << "E> No free sessions left: Active: " << activeSessions <<
" Allowed: " <<
MAX_SESSION_COUNT << "\n";
for (const auto& iterator : sessionsMap)
{
std::cerr << "E> Active Session: 0x" << std::hex
<< std::setfill('0') << std::setw(8)
<< (iterator.second)->getBMCSessionID() << "\n";
}
throw std::runtime_error("No free sessions left");
}
return getSession(sessionID);
}
bool Manager::stopSession(SessionID bmcSessionID)
{
auto iter = sessionsMap.find(bmcSessionID);
if (iter != sessionsMap.end())
{
iter->second->state = State::TEAR_DOWN_IN_PROGRESS;
return true;
}
else
{
return false;
}
}
std::weak_ptr<Session> Manager::getSession(SessionID sessionID,
RetrieveOption option)
{
switch (option)
{
case RetrieveOption::BMC_SESSION_ID:
{
auto iter = sessionsMap.find(sessionID);
if (iter != sessionsMap.end())
{
return iter->second;
}
break;
}
case RetrieveOption::RC_SESSION_ID:
{
auto iter = std::find_if(sessionsMap.begin(),
sessionsMap.end(),
[sessionID](const std::pair<const uint32_t,
std::shared_ptr<Session>>& in)
-> bool
{
return sessionID == in.second->getRCSessionID();
});
if (iter != sessionsMap.end())
{
return iter->second;
}
break;
}
default:
throw std::runtime_error("Invalid retrieval option");
}
throw std::runtime_error("Session ID not found");
}
void Manager::cleanStaleEntries()
{
for(auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
{
auto session = iter->second;
if ((session->getBMCSessionID() != SESSION_ZERO) &&
!(session->isSessionActive()))
{
iter = sessionsMap.erase(iter);
}
else
{
++iter;
}
}
}
} // namespace session