blob: 8d7b121af6dbcf754674c372423ffd230dd1d375 [file] [log] [blame]
Tom Joseph3e61aa02016-08-08 08:42:39 -05001#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
11namespace session
12{
13
14Manager::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
27std::weak_ptr<Session> Manager::startSession(SessionID remoteConsoleSessID,
Tom Josephdd1be1a2017-01-10 16:10:29 +053028 Privilege priv, cipher::rakp_auth::Algorithms authAlgo,
Tom Josephba11f792017-01-24 18:21:45 +053029 cipher::integrity::Algorithms intAlgo,
30 cipher::crypt::Algorithms cryptAlgo)
Tom Joseph3e61aa02016-08-08 08:42:39 -050031{
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
Gunnar Mills62ec6222018-04-08 16:28:23 -050050 * created session is reset and a new session is created for
Tom Joseph3e61aa02016-08-08 08:42:39 -050051 * 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
Vernon Mauery9b307be2017-11-22 09:28:16 -080067 // Set the Authentication Algorithm
Tom Joseph3e61aa02016-08-08 08:42:39 -050068 switch (authAlgo)
69 {
70 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1:
71 {
72 session->setAuthAlgo(
Tom Josephba11f792017-01-24 18:21:45 +053073 std::make_unique<cipher::rakp_auth::AlgoSHA1>(intAlgo,
74 cryptAlgo));
Tom Joseph3e61aa02016-08-08 08:42:39 -050075 break;
76 }
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080077 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 }
Tom Joseph3e61aa02016-08-08 08:42:39 -050084 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
Tom Joseph9662c3a2016-12-06 17:52:16 +0530110bool Manager::stopSession(SessionID bmcSessionID)
Tom Joseph3e61aa02016-08-08 08:42:39 -0500111{
Tom Joseph9662c3a2016-12-06 17:52:16 +0530112 auto iter = sessionsMap.find(bmcSessionID);
113 if (iter != sessionsMap.end())
Tom Joseph3e61aa02016-08-08 08:42:39 -0500114 {
Tom Joseph9662c3a2016-12-06 17:52:16 +0530115 iter->second->state = State::TEAR_DOWN_IN_PROGRESS;
116 return true;
117 }
118 else
119 {
120 return false;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500121 }
122}
123
124std::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 }
Tom Joseph6516cef2017-07-31 18:48:34 +0530136 break;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500137 }
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 }
Tom Joseph6516cef2017-07-31 18:48:34 +0530153 break;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500154 }
155 default:
156 throw std::runtime_error("Invalid retrieval option");
157 }
158
159 throw std::runtime_error("Session ID not found");
160}
161
162void 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