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