blob: 98016c996d2d83798e1ae311b7332ff5b92705c9 [file] [log] [blame]
Tom Joseph9662c3a2016-12-06 17:52:16 +05301#include "session_cmds.hpp"
2
Tom Joseph9662c3a2016-12-06 17:52:16 +05303#include "endian.hpp"
4#include "main.hpp"
Vernon Mauery9e801a22018-10-12 13:20:49 -07005
William A. Kennington III4f09eae2019-02-12 17:10:35 -08006#include <ipmid/api.h>
Tom Joseph9662c3a2016-12-06 17:52:16 +05307
Vernon Maueryecc8efa2021-06-12 12:52:23 -07008#include <chrono>
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +00009#include <ipmid/sessionhelper.hpp>
10#include <ipmid/utils.hpp>
11#include <phosphor-logging/log.hpp>
12
Vernon Maueryecc8efa2021-06-12 12:52:23 -070013using namespace std::chrono_literals;
14
Tom Joseph9662c3a2016-12-06 17:52:16 +053015namespace command
16{
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +000017using namespace phosphor::logging;
Tom Joseph9662c3a2016-12-06 17:52:16 +053018
Vernon Mauery9e801a22018-10-12 13:20:49 -070019std::vector<uint8_t>
20 setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload,
21 const message::Handler& handler)
Tom Joseph9662c3a2016-12-06 17:52:16 +053022{
Vernon Mauery9e801a22018-10-12 13:20:49 -070023 auto request =
24 reinterpret_cast<const SetSessionPrivLevelReq*>(inPayload.data());
Zhikui Ren2b1edef2020-07-24 14:32:13 -070025 if (inPayload.size() != sizeof(*request))
26 {
27 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
28 return errorPayload;
29 }
30
31 std::vector<uint8_t> outPayload(sizeof(SetSessionPrivLevelResp));
Vernon Mauery9e801a22018-10-12 13:20:49 -070032 auto response =
33 reinterpret_cast<SetSessionPrivLevelResp*>(outPayload.data());
Tom Joseph9662c3a2016-12-06 17:52:16 +053034 response->completionCode = IPMI_CC_OK;
35 uint8_t reqPrivilegeLevel = request->reqPrivLevel;
36
Vernon Maueryae1fda42018-10-15 12:55:34 -070037 auto session = std::get<session::Manager&>(singletonPool)
38 .getSession(handler.sessionID);
Tom Joseph9662c3a2016-12-06 17:52:16 +053039
40 if (reqPrivilegeLevel == 0) // Just return present privilege level
41 {
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053042 response->newPrivLevel = session->currentPrivilege();
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053043 return outPayload;
Tom Joseph9662c3a2016-12-06 17:52:16 +053044 }
Tom Joseph4021b1f2019-02-12 10:10:12 +053045 if (reqPrivilegeLevel > (static_cast<uint8_t>(session->reqMaxPrivLevel) &
46 session::reqMaxPrivMask))
Tom Joseph9662c3a2016-12-06 17:52:16 +053047 {
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053048 // Requested level exceeds Channel and/or User Privilege Limit
49 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV;
50 return outPayload;
51 }
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053052 // Use the minimum privilege of user or channel
53 uint8_t minPriv = 0;
Richard Marian Thomaiyar992e53c2019-03-03 13:30:46 +053054 if (session->sessionChannelAccess.privLimit <
55 session->sessionUserPrivAccess.privilege)
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053056 {
Richard Marian Thomaiyar992e53c2019-03-03 13:30:46 +053057 minPriv = session->sessionChannelAccess.privLimit;
Tom Joseph9662c3a2016-12-06 17:52:16 +053058 }
59 else
60 {
Richard Marian Thomaiyar992e53c2019-03-03 13:30:46 +053061 minPriv = session->sessionUserPrivAccess.privilege;
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053062 }
63 if (reqPrivilegeLevel > minPriv)
64 {
Tom Joseph9662c3a2016-12-06 17:52:16 +053065 // Requested level exceeds Channel and/or User Privilege Limit
66 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV;
67 }
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053068 else
69 {
70 // update current privilege of the session.
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053071 session->currentPrivilege(static_cast<uint8_t>(reqPrivilegeLevel));
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053072 response->newPrivLevel = reqPrivilegeLevel;
73 }
74
Tom Joseph9662c3a2016-12-06 17:52:16 +053075 return outPayload;
76}
77
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +000078/**
79 * @brief set the session state as teardown
80 *
81 * This function is to set the session state to tear down in progress if the
82 * state is active.
83 *
84 * @param[in] busp - Dbus obj
85 * @param[in] service - service name
86 * @param[in] obj - object path
87 *
88 * @return success completion code if it sets the session state to
89 * tearDownInProgress else return the corresponding error completion code.
90 **/
91uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp,
92 const std::string& service, const std::string& obj)
93{
94 try
95 {
96 uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty(
97 *busp, service, obj, session::sessionIntf, "State"));
98
99 if (sessionState == static_cast<uint8_t>(session::State::active))
100 {
101 ipmi::setDbusProperty(
102 *busp, service, obj, session::sessionIntf, "State",
103 static_cast<uint8_t>(session::State::tearDownInProgress));
104 return ipmi::ccSuccess;
105 }
106 }
107 catch (std::exception& e)
108 {
109 log<level::ERR>("Failed in getting session state property",
110 entry("service=%s", service.c_str()),
111 entry("object path=%s", obj.c_str()),
112 entry("interface=%s", session::sessionIntf));
113 return ipmi::ccUnspecifiedError;
114 }
115
116 return ipmi::ccInvalidFieldRequest;
117}
118
119uint8_t closeOtherNetInstanceSession(const uint32_t reqSessionId,
120 const uint8_t reqSessionHandle,
121 const uint8_t currentSessionPriv)
122{
123 auto busp = getSdBus();
124
125 try
126 {
127 ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects(
128 *busp, session::sessionManagerRootPath, session::sessionIntf);
129
130 for (auto& objectTreeItr : objectTree)
131 {
132 const std::string obj = objectTreeItr.first;
133
134 if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle))
135 {
136 auto& serviceMap = objectTreeItr.second;
137
138 if (serviceMap.size() != 1)
139 {
140 return ipmi::ccUnspecifiedError;
141 }
142
143 auto itr = serviceMap.begin();
144 const std::string service = itr->first;
145 uint8_t closeSessionPriv =
146 std::get<uint8_t>(ipmi::getDbusProperty(
147 *busp, service, obj, session::sessionIntf,
148 "CurrentPrivilege"));
149
150 if (currentSessionPriv < closeSessionPriv)
151 {
152 return ipmi::ccInsufficientPrivilege;
153 }
154 return setSessionState(busp, service, obj);
155 }
156 }
157 }
158 catch (sdbusplus::exception::SdBusError& e)
159 {
160 log<level::ERR>("Failed to fetch object from dbus",
161 entry("INTERFACE=%s", session::sessionIntf),
162 entry("ERRMSG=%s", e.what()));
163 return ipmi::ccUnspecifiedError;
164 }
165
166 return ipmi::ccInvalidFieldRequest;
167}
168
169uint8_t closeMyNetInstanceSession(uint32_t reqSessionId,
170 uint8_t reqSessionHandle,
171 const uint8_t currentSessionPriv)
172{
173 bool status = false;
174
175 try
176 {
177 if (reqSessionId == session::sessionZero)
178 {
179 reqSessionId = std::get<session::Manager&>(singletonPool)
180 .getSessionIDbyHandle(
181 reqSessionHandle &
182 session::multiIntfaceSessionHandleMask);
183 if (!reqSessionId)
184 {
185 return session::ccInvalidSessionHandle;
186 }
187 }
188
189 auto closeSessionInstance =
190 std::get<session::Manager&>(singletonPool).getSession(reqSessionId);
191 uint8_t closeSessionPriv = closeSessionInstance->currentPrivilege();
192
193 if (currentSessionPriv < closeSessionPriv)
194 {
195 return ipmi::ccInsufficientPrivilege;
196 }
197 status = std::get<session::Manager&>(singletonPool)
198 .stopSession(reqSessionId);
199
200 if (!status)
201 {
202 return session::ccInvalidSessionId;
203 }
204 }
205 catch (std::exception& e)
206 {
207 log<level::ERR>("Failed to get session manager instance",
208 entry("ERRMSG=%s", e.what()));
209 return ipmi::ccUnspecifiedError;
210 }
211
212 return ipmi::ccSuccess;
213}
214
Tom Joseph18a45e92017-04-11 11:30:44 +0530215std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload,
Tom Joseph9662c3a2016-12-06 17:52:16 +0530216 const message::Handler& handler)
217{
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700218 // minimum inPayload size is reqSessionId (uint32_t)
219 // maximum inPayload size is struct CloseSessionRequest
220 if (inPayload.size() != sizeof(uint32_t) &&
221 inPayload.size() != sizeof(CloseSessionRequest))
222 {
223 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
224 return errorPayload;
225 }
226
Vernon Mauery9e801a22018-10-12 13:20:49 -0700227 auto request =
228 reinterpret_cast<const CloseSessionRequest*>(inPayload.data());
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700229
230 std::vector<uint8_t> outPayload(sizeof(CloseSessionResponse));
Tom Joseph9662c3a2016-12-06 17:52:16 +0530231 auto response = reinterpret_cast<CloseSessionResponse*>(outPayload.data());
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000232 uint32_t reqSessionId = request->sessionID;
233 uint8_t ipmiNetworkInstance = 0;
234 uint8_t currentSessionPriv = 0;
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700235 uint8_t reqSessionHandle = session::invalidSessionHandle;
236
237 if (inPayload.size() == sizeof(CloseSessionRequest))
238 {
239 reqSessionHandle = request->sessionHandle;
240 }
Tom Joseph9662c3a2016-12-06 17:52:16 +0530241
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000242 if (reqSessionId == session::sessionZero &&
243 reqSessionHandle == session::invalidSessionHandle)
Tom Joseph9662c3a2016-12-06 17:52:16 +0530244 {
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000245 response->completionCode = session::ccInvalidSessionHandle;
246 return outPayload;
247 }
248
249 if (inPayload.size() == sizeof(reqSessionId) &&
250 reqSessionId == session::sessionZero)
251 {
252 response->completionCode = session::ccInvalidSessionId;
253 return outPayload;
254 }
255
256 if (reqSessionId != session::sessionZero &&
257 inPayload.size() != sizeof(reqSessionId))
258 {
259 response->completionCode = ipmi::ccInvalidFieldRequest;
260 return outPayload;
261 }
262
263 try
264 {
265 ipmiNetworkInstance =
266 std::get<session::Manager&>(singletonPool).getNetworkInstance();
267 auto currentSession = std::get<session::Manager&>(singletonPool)
268 .getSession(handler.sessionID);
269 currentSessionPriv = currentSession->currentPrivilege();
270 }
271 catch (sdbusplus::exception::SdBusError& e)
272 {
273 log<level::ERR>("Failed to fetch object from dbus",
274 entry("INTERFACE=%s", session::sessionIntf),
275 entry("ERRMSG=%s", e.what()));
276 response->completionCode = ipmi::ccUnspecifiedError;
277 return outPayload;
278 }
279
280 if (reqSessionId >> myNetInstanceSessionIdShiftMask ==
281 ipmiNetworkInstance ||
282 (reqSessionId == session::sessionZero &&
283 (reqSessionHandle >> myNetInstanceSessionHandleShiftMask ==
284 ipmiNetworkInstance)))
285 {
286 response->completionCode = closeMyNetInstanceSession(
287 reqSessionId, reqSessionHandle, currentSessionPriv);
Vernon Maueryecc8efa2021-06-12 12:52:23 -0700288 std::get<session::Manager&>(singletonPool)
289 .scheduleSessionCleaner(100us);
Tom Joseph9662c3a2016-12-06 17:52:16 +0530290 }
291 else
292 {
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000293 response->completionCode = closeOtherNetInstanceSession(
294 reqSessionId, reqSessionHandle, currentSessionPriv);
Tom Joseph9662c3a2016-12-06 17:52:16 +0530295 }
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000296
Tom Joseph9662c3a2016-12-06 17:52:16 +0530297 return outPayload;
298}
299
300} // namespace command