1 #include "session_cmds.hpp" 2 3 #include "endian.hpp" 4 #include "main.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 const 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 = std::get<session::Manager&>(singletonPool) 38 .getSession(handler.sessionID); 39 40 if (reqPrivilegeLevel == 0) // Just return present privilege level 41 { 42 response->newPrivLevel = session->currentPrivilege(); 43 return outPayload; 44 } 45 if (reqPrivilegeLevel > (static_cast<uint8_t>(session->reqMaxPrivLevel) & 46 session::reqMaxPrivMask)) 47 { 48 // Requested level exceeds Channel and/or User Privilege Limit 49 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV; 50 return outPayload; 51 } 52 // Use the minimum privilege of user or channel 53 uint8_t minPriv = 0; 54 if (session->sessionChannelAccess.privLimit < 55 session->sessionUserPrivAccess.privilege) 56 { 57 minPriv = session->sessionChannelAccess.privLimit; 58 } 59 else 60 { 61 minPriv = session->sessionUserPrivAccess.privilege; 62 } 63 if (reqPrivilegeLevel > minPriv) 64 { 65 // Requested level exceeds Channel and/or User Privilege Limit 66 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV; 67 } 68 else 69 { 70 // update current privilege of the session. 71 session->currentPrivilege(static_cast<uint8_t>(reqPrivilegeLevel)); 72 response->newPrivLevel = reqPrivilegeLevel; 73 } 74 75 return outPayload; 76 } 77 78 /** 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 **/ 91 uint8_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 119 uint8_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 169 uint8_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 215 std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload, 216 const message::Handler& handler) 217 { 218 // 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 227 auto request = 228 reinterpret_cast<const CloseSessionRequest*>(inPayload.data()); 229 230 std::vector<uint8_t> outPayload(sizeof(CloseSessionResponse)); 231 auto response = reinterpret_cast<CloseSessionResponse*>(outPayload.data()); 232 uint32_t reqSessionId = request->sessionID; 233 uint8_t ipmiNetworkInstance = 0; 234 uint8_t currentSessionPriv = 0; 235 uint8_t reqSessionHandle = session::invalidSessionHandle; 236 237 if (inPayload.size() == sizeof(CloseSessionRequest)) 238 { 239 reqSessionHandle = request->sessionHandle; 240 } 241 242 if (reqSessionId == session::sessionZero && 243 reqSessionHandle == session::invalidSessionHandle) 244 { 245 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); 288 std::get<session::Manager&>(singletonPool) 289 .scheduleSessionCleaner(100us); 290 } 291 else 292 { 293 response->completionCode = closeOtherNetInstanceSession( 294 reqSessionId, reqSessionHandle, currentSessionPriv); 295 } 296 297 return outPayload; 298 } 299 300 } // namespace command 301