blob: 945d8d99ea636719f3dd0ed5f7a2b16da450c20f [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
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +00008#include <ipmid/sessionhelper.hpp>
9#include <ipmid/utils.hpp>
10#include <phosphor-logging/log.hpp>
11
Tom Joseph9662c3a2016-12-06 17:52:16 +053012namespace command
13{
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +000014using namespace phosphor::logging;
Tom Joseph9662c3a2016-12-06 17:52:16 +053015
Vernon Mauery9e801a22018-10-12 13:20:49 -070016std::vector<uint8_t>
17 setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload,
18 const message::Handler& handler)
Tom Joseph9662c3a2016-12-06 17:52:16 +053019{
Vernon Mauery9e801a22018-10-12 13:20:49 -070020 auto request =
21 reinterpret_cast<const SetSessionPrivLevelReq*>(inPayload.data());
Zhikui Ren2b1edef2020-07-24 14:32:13 -070022 if (inPayload.size() != sizeof(*request))
23 {
24 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
25 return errorPayload;
26 }
27
28 std::vector<uint8_t> outPayload(sizeof(SetSessionPrivLevelResp));
Vernon Mauery9e801a22018-10-12 13:20:49 -070029 auto response =
30 reinterpret_cast<SetSessionPrivLevelResp*>(outPayload.data());
Tom Joseph9662c3a2016-12-06 17:52:16 +053031 response->completionCode = IPMI_CC_OK;
32 uint8_t reqPrivilegeLevel = request->reqPrivLevel;
33
Vernon Maueryae1fda42018-10-15 12:55:34 -070034 auto session = std::get<session::Manager&>(singletonPool)
35 .getSession(handler.sessionID);
Tom Joseph9662c3a2016-12-06 17:52:16 +053036
37 if (reqPrivilegeLevel == 0) // Just return present privilege level
38 {
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053039 response->newPrivLevel = session->currentPrivilege();
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053040 return outPayload;
Tom Joseph9662c3a2016-12-06 17:52:16 +053041 }
Tom Joseph4021b1f2019-02-12 10:10:12 +053042 if (reqPrivilegeLevel > (static_cast<uint8_t>(session->reqMaxPrivLevel) &
43 session::reqMaxPrivMask))
Tom Joseph9662c3a2016-12-06 17:52:16 +053044 {
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053045 // Requested level exceeds Channel and/or User Privilege Limit
46 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV;
47 return outPayload;
48 }
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053049 // Use the minimum privilege of user or channel
50 uint8_t minPriv = 0;
Richard Marian Thomaiyar992e53c2019-03-03 13:30:46 +053051 if (session->sessionChannelAccess.privLimit <
52 session->sessionUserPrivAccess.privilege)
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053053 {
Richard Marian Thomaiyar992e53c2019-03-03 13:30:46 +053054 minPriv = session->sessionChannelAccess.privLimit;
Tom Joseph9662c3a2016-12-06 17:52:16 +053055 }
56 else
57 {
Richard Marian Thomaiyar992e53c2019-03-03 13:30:46 +053058 minPriv = session->sessionUserPrivAccess.privilege;
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053059 }
60 if (reqPrivilegeLevel > minPriv)
61 {
Tom Joseph9662c3a2016-12-06 17:52:16 +053062 // Requested level exceeds Channel and/or User Privilege Limit
63 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV;
64 }
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053065 else
66 {
67 // update current privilege of the session.
Suryakanth Sekarf8a34fc2019-06-12 20:59:18 +053068 session->currentPrivilege(static_cast<uint8_t>(reqPrivilegeLevel));
Richard Marian Thomaiyar127748a2018-09-06 07:08:51 +053069 response->newPrivLevel = reqPrivilegeLevel;
70 }
71
Tom Joseph9662c3a2016-12-06 17:52:16 +053072 return outPayload;
73}
74
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +000075/**
76 * @brief set the session state as teardown
77 *
78 * This function is to set the session state to tear down in progress if the
79 * state is active.
80 *
81 * @param[in] busp - Dbus obj
82 * @param[in] service - service name
83 * @param[in] obj - object path
84 *
85 * @return success completion code if it sets the session state to
86 * tearDownInProgress else return the corresponding error completion code.
87 **/
88uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp,
89 const std::string& service, const std::string& obj)
90{
91 try
92 {
93 uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty(
94 *busp, service, obj, session::sessionIntf, "State"));
95
96 if (sessionState == static_cast<uint8_t>(session::State::active))
97 {
98 ipmi::setDbusProperty(
99 *busp, service, obj, session::sessionIntf, "State",
100 static_cast<uint8_t>(session::State::tearDownInProgress));
101 return ipmi::ccSuccess;
102 }
103 }
104 catch (std::exception& e)
105 {
106 log<level::ERR>("Failed in getting session state property",
107 entry("service=%s", service.c_str()),
108 entry("object path=%s", obj.c_str()),
109 entry("interface=%s", session::sessionIntf));
110 return ipmi::ccUnspecifiedError;
111 }
112
113 return ipmi::ccInvalidFieldRequest;
114}
115
116uint8_t closeOtherNetInstanceSession(const uint32_t reqSessionId,
117 const uint8_t reqSessionHandle,
118 const uint8_t currentSessionPriv)
119{
120 auto busp = getSdBus();
121
122 try
123 {
124 ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects(
125 *busp, session::sessionManagerRootPath, session::sessionIntf);
126
127 for (auto& objectTreeItr : objectTree)
128 {
129 const std::string obj = objectTreeItr.first;
130
131 if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle))
132 {
133 auto& serviceMap = objectTreeItr.second;
134
135 if (serviceMap.size() != 1)
136 {
137 return ipmi::ccUnspecifiedError;
138 }
139
140 auto itr = serviceMap.begin();
141 const std::string service = itr->first;
142 uint8_t closeSessionPriv =
143 std::get<uint8_t>(ipmi::getDbusProperty(
144 *busp, service, obj, session::sessionIntf,
145 "CurrentPrivilege"));
146
147 if (currentSessionPriv < closeSessionPriv)
148 {
149 return ipmi::ccInsufficientPrivilege;
150 }
151 return setSessionState(busp, service, obj);
152 }
153 }
154 }
155 catch (sdbusplus::exception::SdBusError& e)
156 {
157 log<level::ERR>("Failed to fetch object from dbus",
158 entry("INTERFACE=%s", session::sessionIntf),
159 entry("ERRMSG=%s", e.what()));
160 return ipmi::ccUnspecifiedError;
161 }
162
163 return ipmi::ccInvalidFieldRequest;
164}
165
166uint8_t closeMyNetInstanceSession(uint32_t reqSessionId,
167 uint8_t reqSessionHandle,
168 const uint8_t currentSessionPriv)
169{
170 bool status = false;
171
172 try
173 {
174 if (reqSessionId == session::sessionZero)
175 {
176 reqSessionId = std::get<session::Manager&>(singletonPool)
177 .getSessionIDbyHandle(
178 reqSessionHandle &
179 session::multiIntfaceSessionHandleMask);
180 if (!reqSessionId)
181 {
182 return session::ccInvalidSessionHandle;
183 }
184 }
185
186 auto closeSessionInstance =
187 std::get<session::Manager&>(singletonPool).getSession(reqSessionId);
188 uint8_t closeSessionPriv = closeSessionInstance->currentPrivilege();
189
190 if (currentSessionPriv < closeSessionPriv)
191 {
192 return ipmi::ccInsufficientPrivilege;
193 }
194 status = std::get<session::Manager&>(singletonPool)
195 .stopSession(reqSessionId);
196
197 if (!status)
198 {
199 return session::ccInvalidSessionId;
200 }
201 }
202 catch (std::exception& e)
203 {
204 log<level::ERR>("Failed to get session manager instance",
205 entry("ERRMSG=%s", e.what()));
206 return ipmi::ccUnspecifiedError;
207 }
208
209 return ipmi::ccSuccess;
210}
211
Tom Joseph18a45e92017-04-11 11:30:44 +0530212std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload,
Tom Joseph9662c3a2016-12-06 17:52:16 +0530213 const message::Handler& handler)
214{
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700215 // minimum inPayload size is reqSessionId (uint32_t)
216 // maximum inPayload size is struct CloseSessionRequest
217 if (inPayload.size() != sizeof(uint32_t) &&
218 inPayload.size() != sizeof(CloseSessionRequest))
219 {
220 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID};
221 return errorPayload;
222 }
223
Vernon Mauery9e801a22018-10-12 13:20:49 -0700224 auto request =
225 reinterpret_cast<const CloseSessionRequest*>(inPayload.data());
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700226
227 std::vector<uint8_t> outPayload(sizeof(CloseSessionResponse));
Tom Joseph9662c3a2016-12-06 17:52:16 +0530228 auto response = reinterpret_cast<CloseSessionResponse*>(outPayload.data());
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000229 uint32_t reqSessionId = request->sessionID;
230 uint8_t ipmiNetworkInstance = 0;
231 uint8_t currentSessionPriv = 0;
Zhikui Ren2b1edef2020-07-24 14:32:13 -0700232 uint8_t reqSessionHandle = session::invalidSessionHandle;
233
234 if (inPayload.size() == sizeof(CloseSessionRequest))
235 {
236 reqSessionHandle = request->sessionHandle;
237 }
Tom Joseph9662c3a2016-12-06 17:52:16 +0530238
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000239 if (reqSessionId == session::sessionZero &&
240 reqSessionHandle == session::invalidSessionHandle)
Tom Joseph9662c3a2016-12-06 17:52:16 +0530241 {
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000242 response->completionCode = session::ccInvalidSessionHandle;
243 return outPayload;
244 }
245
246 if (inPayload.size() == sizeof(reqSessionId) &&
247 reqSessionId == session::sessionZero)
248 {
249 response->completionCode = session::ccInvalidSessionId;
250 return outPayload;
251 }
252
253 if (reqSessionId != session::sessionZero &&
254 inPayload.size() != sizeof(reqSessionId))
255 {
256 response->completionCode = ipmi::ccInvalidFieldRequest;
257 return outPayload;
258 }
259
260 try
261 {
262 ipmiNetworkInstance =
263 std::get<session::Manager&>(singletonPool).getNetworkInstance();
264 auto currentSession = std::get<session::Manager&>(singletonPool)
265 .getSession(handler.sessionID);
266 currentSessionPriv = currentSession->currentPrivilege();
267 }
268 catch (sdbusplus::exception::SdBusError& e)
269 {
270 log<level::ERR>("Failed to fetch object from dbus",
271 entry("INTERFACE=%s", session::sessionIntf),
272 entry("ERRMSG=%s", e.what()));
273 response->completionCode = ipmi::ccUnspecifiedError;
274 return outPayload;
275 }
276
277 if (reqSessionId >> myNetInstanceSessionIdShiftMask ==
278 ipmiNetworkInstance ||
279 (reqSessionId == session::sessionZero &&
280 (reqSessionHandle >> myNetInstanceSessionHandleShiftMask ==
281 ipmiNetworkInstance)))
282 {
283 response->completionCode = closeMyNetInstanceSession(
284 reqSessionId, reqSessionHandle, currentSessionPriv);
Tom Joseph9662c3a2016-12-06 17:52:16 +0530285 }
286 else
287 {
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000288 response->completionCode = closeOtherNetInstanceSession(
289 reqSessionId, reqSessionHandle, currentSessionPriv);
Tom Joseph9662c3a2016-12-06 17:52:16 +0530290 }
Rajashekar Gade Reddydafe3642019-07-12 17:35:06 +0000291
Tom Joseph9662c3a2016-12-06 17:52:16 +0530292 return outPayload;
293}
294
295} // namespace command