1 #include "session_cmds.hpp" 2 3 #include "endian.hpp" 4 #include "main.hpp" 5 6 #include <ipmid/api.h> 7 8 #include <ipmid/sessionhelper.hpp> 9 #include <ipmid/utils.hpp> 10 #include <phosphor-logging/log.hpp> 11 12 namespace command 13 { 14 using namespace phosphor::logging; 15 16 std::vector<uint8_t> 17 setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload, 18 const message::Handler& handler) 19 { 20 auto request = 21 reinterpret_cast<const SetSessionPrivLevelReq*>(inPayload.data()); 22 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)); 29 auto response = 30 reinterpret_cast<SetSessionPrivLevelResp*>(outPayload.data()); 31 response->completionCode = IPMI_CC_OK; 32 uint8_t reqPrivilegeLevel = request->reqPrivLevel; 33 34 auto session = std::get<session::Manager&>(singletonPool) 35 .getSession(handler.sessionID); 36 37 if (reqPrivilegeLevel == 0) // Just return present privilege level 38 { 39 response->newPrivLevel = session->currentPrivilege(); 40 return outPayload; 41 } 42 if (reqPrivilegeLevel > (static_cast<uint8_t>(session->reqMaxPrivLevel) & 43 session::reqMaxPrivMask)) 44 { 45 // Requested level exceeds Channel and/or User Privilege Limit 46 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV; 47 return outPayload; 48 } 49 // Use the minimum privilege of user or channel 50 uint8_t minPriv = 0; 51 if (session->sessionChannelAccess.privLimit < 52 session->sessionUserPrivAccess.privilege) 53 { 54 minPriv = session->sessionChannelAccess.privLimit; 55 } 56 else 57 { 58 minPriv = session->sessionUserPrivAccess.privilege; 59 } 60 if (reqPrivilegeLevel > minPriv) 61 { 62 // Requested level exceeds Channel and/or User Privilege Limit 63 response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV; 64 } 65 else 66 { 67 // update current privilege of the session. 68 session->currentPrivilege(static_cast<uint8_t>(reqPrivilegeLevel)); 69 response->newPrivLevel = reqPrivilegeLevel; 70 } 71 72 return outPayload; 73 } 74 75 /** 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 **/ 88 uint8_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 116 uint8_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 166 uint8_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 212 std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload, 213 const message::Handler& handler) 214 { 215 // 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 224 auto request = 225 reinterpret_cast<const CloseSessionRequest*>(inPayload.data()); 226 227 std::vector<uint8_t> outPayload(sizeof(CloseSessionResponse)); 228 auto response = reinterpret_cast<CloseSessionResponse*>(outPayload.data()); 229 uint32_t reqSessionId = request->sessionID; 230 uint8_t ipmiNetworkInstance = 0; 231 uint8_t currentSessionPriv = 0; 232 uint8_t reqSessionHandle = session::invalidSessionHandle; 233 234 if (inPayload.size() == sizeof(CloseSessionRequest)) 235 { 236 reqSessionHandle = request->sessionHandle; 237 } 238 239 if (reqSessionId == session::sessionZero && 240 reqSessionHandle == session::invalidSessionHandle) 241 { 242 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); 285 } 286 else 287 { 288 response->completionCode = closeOtherNetInstanceSession( 289 reqSessionId, reqSessionHandle, currentSessionPriv); 290 } 291 292 return outPayload; 293 } 294 295 } // namespace command 296