blob: 1a70b49b76ac35dacfe3c4bb0b43f6de8535bce3 [file] [log] [blame]
Tom Joseph3e61aa02016-08-08 08:42:39 -05001#include "sessions_manager.hpp"
2
Vernon Mauery9e801a22018-10-12 13:20:49 -07003#include "session.hpp"
4
Tom Joseph3e61aa02016-08-08 08:42:39 -05005#include <algorithm>
6#include <cstdlib>
7#include <iomanip>
8#include <iostream>
9#include <memory>
10
Tom Joseph3e61aa02016-08-08 08:42:39 -050011namespace 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>());
Tom Joseph3e61aa02016-08-08 08:42:39 -050023}
24
Vernon Maueryae1fda42018-10-15 12:55:34 -070025std::shared_ptr<Session>
Vernon Mauery9e801a22018-10-12 13:20:49 -070026 Manager::startSession(SessionID remoteConsoleSessID, Privilege priv,
27 cipher::rakp_auth::Algorithms authAlgo,
28 cipher::integrity::Algorithms intAlgo,
29 cipher::crypt::Algorithms cryptAlgo)
Tom Joseph3e61aa02016-08-08 08:42:39 -050030{
31 std::shared_ptr<Session> session = nullptr;
32 SessionID sessionID = 0;
33 cleanStaleEntries();
34 auto activeSessions = sessionsMap.size() - MAX_SESSIONLESS_COUNT;
35
36 if (activeSessions < MAX_SESSION_COUNT)
37 {
38 do
39 {
40 session = std::make_shared<Session>(remoteConsoleSessID, priv);
41
42 /*
43 * Every IPMI Session has two ID's attached to it Remote Console
44 * Session ID and BMC Session ID. The remote console ID is passed
45 * along with the Open Session request command. The BMC session ID
46 * is the key for the session map and is generated using std::rand.
47 * There is a rare chance for collision of BMC session ID, so the
48 * following check validates that. In the case of collision the
Gunnar Mills62ec6222018-04-08 16:28:23 -050049 * created session is reset and a new session is created for
Tom Joseph3e61aa02016-08-08 08:42:39 -050050 * validating collision.
51 */
52 auto iterator = sessionsMap.find(session->getBMCSessionID());
53 if (iterator != sessionsMap.end())
54 {
Vernon Mauery9e801a22018-10-12 13:20:49 -070055 // Detected BMC Session ID collisions
Tom Joseph3e61aa02016-08-08 08:42:39 -050056 session.reset();
57 continue;
58 }
59 else
60 {
61 break;
62 }
Vernon Mauery9e801a22018-10-12 13:20:49 -070063 } while (1);
Tom Joseph3e61aa02016-08-08 08:42:39 -050064
Vernon Mauery9b307be2017-11-22 09:28:16 -080065 // Set the Authentication Algorithm
Tom Joseph3e61aa02016-08-08 08:42:39 -050066 switch (authAlgo)
67 {
68 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA1:
69 {
70 session->setAuthAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -070071 std::make_unique<cipher::rakp_auth::AlgoSHA1>(intAlgo,
72 cryptAlgo));
Tom Joseph3e61aa02016-08-08 08:42:39 -050073 break;
74 }
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080075 case cipher::rakp_auth::Algorithms::RAKP_HMAC_SHA256:
76 {
77 session->setAuthAlgo(
Vernon Mauery9e801a22018-10-12 13:20:49 -070078 std::make_unique<cipher::rakp_auth::AlgoSHA256>(intAlgo,
79 cryptAlgo));
Vernon Mauery7e9e2ef2017-11-29 08:36:29 -080080 break;
81 }
Tom Joseph3e61aa02016-08-08 08:42:39 -050082 default:
83 {
84 throw std::runtime_error("Invalid Authentication Algorithm");
85 }
86 }
87 sessionID = session->getBMCSessionID();
Vernon Mauery4cb73592018-10-26 10:15:03 -070088 sessionsMap.emplace(sessionID, session);
89 return session;
Tom Joseph3e61aa02016-08-08 08:42:39 -050090 }
Vernon Mauery4cb73592018-10-26 10:15:03 -070091
92 std::cerr << "E> No free sessions left: Active: " << activeSessions
93 << " Allowed: " << MAX_SESSION_COUNT << "\n";
94
95 for (const auto& iterator : sessionsMap)
Tom Joseph3e61aa02016-08-08 08:42:39 -050096 {
Vernon Mauery4cb73592018-10-26 10:15:03 -070097 std::cerr << "E> Active Session: 0x" << std::hex << std::setfill('0')
98 << std::setw(8) << (iterator.second)->getBMCSessionID()
99 << "\n";
Tom Joseph3e61aa02016-08-08 08:42:39 -0500100 }
Vernon Mauery4cb73592018-10-26 10:15:03 -0700101 throw std::runtime_error("No free sessions left");
Tom Joseph3e61aa02016-08-08 08:42:39 -0500102}
103
Tom Joseph9662c3a2016-12-06 17:52:16 +0530104bool Manager::stopSession(SessionID bmcSessionID)
Tom Joseph3e61aa02016-08-08 08:42:39 -0500105{
Tom Joseph9662c3a2016-12-06 17:52:16 +0530106 auto iter = sessionsMap.find(bmcSessionID);
107 if (iter != sessionsMap.end())
Tom Joseph3e61aa02016-08-08 08:42:39 -0500108 {
Tom Joseph9662c3a2016-12-06 17:52:16 +0530109 iter->second->state = State::TEAR_DOWN_IN_PROGRESS;
110 return true;
111 }
112 else
113 {
114 return false;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500115 }
116}
117
Vernon Maueryae1fda42018-10-15 12:55:34 -0700118std::shared_ptr<Session> Manager::getSession(SessionID sessionID,
119 RetrieveOption option)
Tom Joseph3e61aa02016-08-08 08:42:39 -0500120{
121 switch (option)
122 {
123 case RetrieveOption::BMC_SESSION_ID:
124 {
125 auto iter = sessionsMap.find(sessionID);
126 if (iter != sessionsMap.end())
127 {
128 return iter->second;
129 }
Tom Joseph6516cef2017-07-31 18:48:34 +0530130 break;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500131 }
132 case RetrieveOption::RC_SESSION_ID:
133 {
Vernon Mauery9e801a22018-10-12 13:20:49 -0700134 auto iter = std::find_if(
135 sessionsMap.begin(), sessionsMap.end(),
136 [sessionID](
137 const std::pair<const uint32_t, std::shared_ptr<Session>>&
138 in) -> bool {
139 return sessionID == in.second->getRCSessionID();
140 });
Tom Joseph3e61aa02016-08-08 08:42:39 -0500141
142 if (iter != sessionsMap.end())
143 {
144 return iter->second;
145 }
Tom Joseph6516cef2017-07-31 18:48:34 +0530146 break;
Tom Joseph3e61aa02016-08-08 08:42:39 -0500147 }
148 default:
149 throw std::runtime_error("Invalid retrieval option");
150 }
151
152 throw std::runtime_error("Session ID not found");
153}
154
155void Manager::cleanStaleEntries()
156{
Vernon Mauery9e801a22018-10-12 13:20:49 -0700157 for (auto iter = sessionsMap.begin(); iter != sessionsMap.end();)
Tom Joseph3e61aa02016-08-08 08:42:39 -0500158 {
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