1 #include "open_session.hpp"
2 
3 #include "comm_module.hpp"
4 #include "endian.hpp"
5 #include "sessions_manager.hpp"
6 
7 #include <phosphor-logging/log.hpp>
8 
9 using namespace phosphor::logging;
10 
11 namespace command
12 {
13 
14 std::vector<uint8_t>
15     openSession(const std::vector<uint8_t>& inPayload,
16                 std::shared_ptr<message::Handler>& /* handler */)
17 {
18     auto request =
19         reinterpret_cast<const OpenSessionRequest*>(inPayload.data());
20     if (inPayload.size() != sizeof(*request))
21     {
22         std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
23         return errorPayload;
24     }
25 
26     std::vector<uint8_t> outPayload(sizeof(OpenSessionResponse));
27     auto response = reinterpret_cast<OpenSessionResponse*>(outPayload.data());
28 
29     // Per the IPMI Spec, messageTag and remoteConsoleSessionID are always
30     // returned
31     response->messageTag = request->messageTag;
32     response->remoteConsoleSessionID = request->remoteConsoleSessionID;
33 
34     // Check for valid Authentication Algorithms
35     if (!cipher::rakp_auth::Interface::isAlgorithmSupported(
36             static_cast<cipher::rakp_auth::Algorithms>(request->authAlgo)))
37     {
38         response->status_code =
39             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_AUTH_ALGO);
40         return outPayload;
41     }
42 
43     // Check for valid Integrity Algorithms
44     if (!cipher::integrity::Interface::isAlgorithmSupported(
45             static_cast<cipher::integrity::Algorithms>(request->intAlgo)))
46     {
47         response->status_code =
48             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_INTEGRITY_ALGO);
49         return outPayload;
50     }
51 
52     session::Privilege priv;
53 
54     // 0h in the requested maximum privilege role field indicates highest level
55     // matching proposed algorithms. The maximum privilege level the session
56     // can take is set to Administrator level. In the RAKP12 command sequence
57     // the session maximum privilege role is set again based on the user's
58     // permitted privilege level.
59     if (!request->maxPrivLevel)
60     {
61         priv = session::Privilege::ADMIN;
62     }
63     else
64     {
65         priv = static_cast<session::Privilege>(request->maxPrivLevel);
66     }
67 
68     // Check for valid Confidentiality Algorithms
69     if (!cipher::crypt::Interface::isAlgorithmSupported(
70             static_cast<cipher::crypt::Algorithms>(request->confAlgo)))
71     {
72         response->status_code =
73             static_cast<uint8_t>(RAKP_ReturnCode::INVALID_CONF_ALGO);
74         return outPayload;
75     }
76 
77     std::shared_ptr<session::Session> session;
78     try
79     {
80         // Start an IPMI session
81         session = session::Manager::get().startSession(
82             endian::from_ipmi<>(request->remoteConsoleSessionID), priv,
83             static_cast<cipher::rakp_auth::Algorithms>(request->authAlgo),
84             static_cast<cipher::integrity::Algorithms>(request->intAlgo),
85             static_cast<cipher::crypt::Algorithms>(request->confAlgo));
86     }
87     catch (const std::exception& e)
88     {
89         response->status_code =
90             static_cast<uint8_t>(RAKP_ReturnCode::INSUFFICIENT_RESOURCE);
91         log<level::ERR>("openSession : Problem opening a session",
92                         entry("EXCEPTION=%s", e.what()));
93         return outPayload;
94     }
95 
96     response->status_code = static_cast<uint8_t>(RAKP_ReturnCode::NO_ERROR);
97     response->maxPrivLevel = static_cast<uint8_t>(session->reqMaxPrivLevel);
98     response->managedSystemSessionID =
99         endian::to_ipmi<>(session->getBMCSessionID());
100 
101     response->authPayload = request->authPayload;
102     response->authPayloadLen = request->authPayloadLen;
103     response->authAlgo = request->authAlgo;
104 
105     response->intPayload = request->intPayload;
106     response->intPayloadLen = request->intPayloadLen;
107     response->intAlgo = request->intAlgo;
108 
109     response->confPayload = request->confPayload;
110     response->confPayloadLen = request->confPayloadLen;
111     response->confAlgo = request->confAlgo;
112 
113     session->updateLastTransactionTime();
114 
115     // Session state is Setup in progress
116     session->state(static_cast<uint8_t>(session::State::setupInProgress));
117     return outPayload;
118 }
119 
120 } // namespace command
121