1 #include "session_cmds.hpp" 2 3 #include "endian.hpp" 4 #include "sessions_manager.hpp" 5 6 #include <ipmid/api.h> 7 8 #include <chrono> 9 #include <ipmid/sessionhelper.hpp> 10 #include <ipmid/utils.hpp> 11 #include <phosphor-logging/log.hpp> 12 13 using namespace std::chrono_literals; 14 15 namespace command 16 { 17 using namespace phosphor::logging; 18 19 std::vector<uint8_t> 20 setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload, 21 std::shared_ptr<message::Handler>& handler) 22 { 23 auto request = 24 reinterpret_cast<const SetSessionPrivLevelReq*>(inPayload.data()); 25 if (inPayload.size() != sizeof(*request)) 26 { 27 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 28 return errorPayload; 29 } 30 if (request->reserved != 0) 31 { 32 std::vector<uint8_t> errorPayload{IPMI_CC_INVALID_FIELD_REQUEST}; 33 return errorPayload; 34 } 35 36 std::vector<uint8_t> outPayload(sizeof(SetSessionPrivLevelResp)); 37 auto response = 38 reinterpret_cast<SetSessionPrivLevelResp*>(outPayload.data()); 39 response->completionCode = IPMI_CC_OK; 40 uint8_t reqPrivilegeLevel = request->reqPrivLevel; 41 42 auto session = session::Manager::get().getSession(handler->sessionID); 43 44 if (reqPrivilegeLevel == 0) // Just return present privilege level 45 { 46 response->newPrivLevel = session->currentPrivilege(); 47 return outPayload; 48 } 49 if (reqPrivilegeLevel == 50 static_cast<uint8_t>(session::Privilege::CALLBACK) || 51 reqPrivilegeLevel > static_cast<uint8_t>(session::Privilege::OEM)) 52 { 53 response->completionCode = IPMI_CC_INVALID_FIELD_REQUEST; 54 return outPayload; 55 } 56 57 if (reqPrivilegeLevel > (static_cast<uint8_t>(session->reqMaxPrivLevel) & 58 session::reqMaxPrivMask)) 59 { 60 // Requested level exceeds Channel and/or User Privilege Limit 61 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV; 62 return outPayload; 63 } 64 // Use the minimum privilege of user or channel 65 uint8_t minPriv = 0; 66 if (session->sessionChannelAccess.privLimit < 67 session->sessionUserPrivAccess.privilege) 68 { 69 minPriv = session->sessionChannelAccess.privLimit; 70 } 71 else 72 { 73 minPriv = session->sessionUserPrivAccess.privilege; 74 } 75 if (reqPrivilegeLevel > minPriv) 76 { 77 // Requested level exceeds Channel and/or User Privilege Limit 78 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV; 79 } 80 else 81 { 82 // update current privilege of the session. 83 session->currentPrivilege(static_cast<uint8_t>(reqPrivilegeLevel)); 84 response->newPrivLevel = reqPrivilegeLevel; 85 } 86 87 return outPayload; 88 } 89 90 /** 91 * @brief set the session state as teardown 92 * 93 * This function is to set the session state to tear down in progress if the 94 * state is active. 95 * 96 * @param[in] busp - Dbus obj 97 * @param[in] service - service name 98 * @param[in] obj - object path 99 * 100 * @return success completion code if it sets the session state to 101 * tearDownInProgress else return the corresponding error completion code. 102 **/ 103 uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp, 104 const std::string& service, const std::string& obj) 105 { 106 try 107 { 108 uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty( 109 *busp, service, obj, session::sessionIntf, "State")); 110 111 if (sessionState == static_cast<uint8_t>(session::State::active)) 112 { 113 ipmi::setDbusProperty( 114 *busp, service, obj, session::sessionIntf, "State", 115 static_cast<uint8_t>(session::State::tearDownInProgress)); 116 return ipmi::ccSuccess; 117 } 118 } 119 catch (const std::exception& e) 120 { 121 log<level::ERR>("Failed in getting session state property", 122 entry("service=%s", service.c_str()), 123 entry("object path=%s", obj.c_str()), 124 entry("interface=%s", session::sessionIntf)); 125 return ipmi::ccUnspecifiedError; 126 } 127 128 return ipmi::ccInvalidFieldRequest; 129 } 130 131 uint8_t closeOtherNetInstanceSession(const uint32_t reqSessionId, 132 const uint8_t reqSessionHandle, 133 const uint8_t currentSessionPriv) 134 { 135 auto busp = getSdBus(); 136 137 try 138 { 139 ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects( 140 *busp, session::sessionManagerRootPath, session::sessionIntf); 141 142 for (auto& objectTreeItr : objectTree) 143 { 144 const std::string obj = objectTreeItr.first; 145 146 if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle)) 147 { 148 auto& serviceMap = objectTreeItr.second; 149 150 if (serviceMap.size() != 1) 151 { 152 return ipmi::ccUnspecifiedError; 153 } 154 155 auto itr = serviceMap.begin(); 156 const std::string service = itr->first; 157 uint8_t closeSessionPriv = 158 std::get<uint8_t>(ipmi::getDbusProperty( 159 *busp, service, obj, session::sessionIntf, 160 "CurrentPrivilege")); 161 162 if (currentSessionPriv < closeSessionPriv) 163 { 164 return ipmi::ccInsufficientPrivilege; 165 } 166 return setSessionState(busp, service, obj); 167 } 168 } 169 } 170 catch (const sdbusplus::exception::exception& e) 171 { 172 log<level::ERR>("Failed to fetch object from dbus", 173 entry("INTERFACE=%s", session::sessionIntf), 174 entry("ERRMSG=%s", e.what())); 175 return ipmi::ccUnspecifiedError; 176 } 177 178 return ipmi::ccInvalidFieldRequest; 179 } 180 181 uint8_t closeMyNetInstanceSession(uint32_t reqSessionId, 182 uint8_t reqSessionHandle, 183 const uint8_t currentSessionPriv) 184 { 185 bool status = false; 186 187 try 188 { 189 if (reqSessionId == session::sessionZero) 190 { 191 reqSessionId = session::Manager::get().getSessionIDbyHandle( 192 reqSessionHandle & session::multiIntfaceSessionHandleMask); 193 if (!reqSessionId) 194 { 195 return session::ccInvalidSessionHandle; 196 } 197 } 198 } 199 catch (const std::exception& e) 200 { 201 log<level::ERR>("Failed to get session manager instance or sessionID " 202 "by sessionHandle", 203 entry("ERRMSG=%s", e.what())); 204 return session::ccInvalidSessionHandle; 205 } 206 207 try 208 { 209 auto closeSessionInstance = 210 session::Manager::get().getSession(reqSessionId); 211 uint8_t closeSessionPriv = closeSessionInstance->currentPrivilege(); 212 213 if (currentSessionPriv < closeSessionPriv) 214 { 215 return ipmi::ccInsufficientPrivilege; 216 } 217 } 218 catch (const std::exception& e) 219 { 220 log<level::ERR>("Failed to get session manager instance or sessionID", 221 entry("ERRMSG=%s", e.what())); 222 return session::ccInvalidSessionId; 223 } 224 225 try 226 { 227 status = session::Manager::get().stopSession(reqSessionId); 228 229 if (!status) 230 { 231 return session::ccInvalidSessionId; 232 } 233 } 234 catch (const std::exception& e) 235 { 236 log<level::ERR>( 237 "Failed to get session manager instance or stop session", 238 entry("ERRMSG=%s", e.what())); 239 return ipmi::ccUnspecifiedError; 240 } 241 242 return ipmi::ccSuccess; 243 } 244 245 std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload, 246 std::shared_ptr<message::Handler>& handler) 247 { 248 // minimum inPayload size is reqSessionId (uint32_t) 249 // maximum inPayload size is struct CloseSessionRequest 250 if (inPayload.size() != sizeof(uint32_t) && 251 inPayload.size() != sizeof(CloseSessionRequest)) 252 { 253 std::vector<uint8_t> errorPayload{IPMI_CC_REQ_DATA_LEN_INVALID}; 254 return errorPayload; 255 } 256 257 auto request = 258 reinterpret_cast<const CloseSessionRequest*>(inPayload.data()); 259 260 std::vector<uint8_t> outPayload(sizeof(CloseSessionResponse)); 261 auto response = reinterpret_cast<CloseSessionResponse*>(outPayload.data()); 262 uint32_t reqSessionId = request->sessionID; 263 uint8_t ipmiNetworkInstance = 0; 264 uint8_t currentSessionPriv = 0; 265 uint8_t reqSessionHandle = session::invalidSessionHandle; 266 267 if (inPayload.size() == sizeof(CloseSessionRequest)) 268 { 269 reqSessionHandle = request->sessionHandle; 270 } 271 272 if (reqSessionId == session::sessionZero && 273 reqSessionHandle == session::invalidSessionHandle) 274 { 275 response->completionCode = session::ccInvalidSessionHandle; 276 return outPayload; 277 } 278 279 if (inPayload.size() == sizeof(reqSessionId) && 280 reqSessionId == session::sessionZero) 281 { 282 response->completionCode = session::ccInvalidSessionId; 283 return outPayload; 284 } 285 286 if (reqSessionId != session::sessionZero && 287 inPayload.size() != sizeof(reqSessionId)) 288 { 289 response->completionCode = ipmi::ccInvalidFieldRequest; 290 return outPayload; 291 } 292 293 try 294 { 295 ipmiNetworkInstance = session::Manager::get().getNetworkInstance(); 296 auto currentSession = 297 session::Manager::get().getSession(handler->sessionID); 298 currentSessionPriv = currentSession->currentPrivilege(); 299 } 300 catch (const sdbusplus::exception::exception& e) 301 { 302 log<level::ERR>("Failed to fetch object from dbus", 303 entry("INTERFACE=%s", session::sessionIntf), 304 entry("ERRMSG=%s", e.what())); 305 response->completionCode = ipmi::ccUnspecifiedError; 306 return outPayload; 307 } 308 309 if (reqSessionId >> myNetInstanceSessionIdShiftMask == 310 ipmiNetworkInstance || 311 (reqSessionId == session::sessionZero && 312 (reqSessionHandle >> myNetInstanceSessionHandleShiftMask == 313 ipmiNetworkInstance))) 314 { 315 response->completionCode = closeMyNetInstanceSession( 316 reqSessionId, reqSessionHandle, currentSessionPriv); 317 session::Manager::get().scheduleSessionCleaner(100us); 318 } 319 else 320 { 321 response->completionCode = closeOtherNetInstanceSession( 322 reqSessionId, reqSessionHandle, currentSessionPriv); 323 } 324 325 return outPayload; 326 } 327 328 } // namespace command 329