1 #include "session_cmds.hpp"
2 
3 #include "endian.hpp"
4 #include "main.hpp"
5 
6 #include <host-ipmid/ipmid-api.h>
7 
8 #include <user_channel/channel_layer.hpp>
9 #include <user_channel/user_layer.hpp>
10 
11 namespace command
12 {
13 
14 std::vector<uint8_t>
15     setSessionPrivilegeLevel(const std::vector<uint8_t>& inPayload,
16                              const message::Handler& handler)
17 {
18 
19     std::vector<uint8_t> outPayload(sizeof(SetSessionPrivLevelResp));
20     auto request =
21         reinterpret_cast<const SetSessionPrivLevelReq*>(inPayload.data());
22     auto response =
23         reinterpret_cast<SetSessionPrivLevelResp*>(outPayload.data());
24     response->completionCode = IPMI_CC_OK;
25     uint8_t reqPrivilegeLevel = request->reqPrivLevel;
26 
27     auto session = std::get<session::Manager&>(singletonPool)
28                        .getSession(handler.sessionID);
29 
30     if (reqPrivilegeLevel == 0) // Just return present privilege level
31     {
32         response->newPrivLevel = static_cast<uint8_t>(session->curPrivLevel);
33         return outPayload;
34     }
35     if (reqPrivilegeLevel >
36         (session->reqMaxPrivLevel & session::reqMaxPrivMask))
37     {
38         // Requested level exceeds Channel and/or User Privilege Limit
39         response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV;
40         return outPayload;
41     }
42 
43     uint8_t userId = ipmi::ipmiUserGetUserId(session->userName);
44     if (userId == ipmi::invalidUserId)
45     {
46         response->completionCode = IPMI_CC_UNSPECIFIED_ERROR;
47         return outPayload;
48     }
49     ipmi::PrivAccess userAccess{};
50     ipmi::ChannelAccess chAccess{};
51     if ((ipmi::ipmiUserGetPrivilegeAccess(userId, session->chNum, userAccess) !=
52          IPMI_CC_OK) ||
53         (ipmi::getChannelAccessData(session->chNum, chAccess) != IPMI_CC_OK))
54     {
55         response->completionCode = IPMI_CC_INVALID_PRIV_LEVEL;
56         return outPayload;
57     }
58     // Use the minimum privilege of user or channel
59     uint8_t minPriv = 0;
60     if (chAccess.privLimit < userAccess.privilege)
61     {
62         minPriv = chAccess.privLimit;
63     }
64     else
65     {
66         minPriv = userAccess.privilege;
67     }
68     if (reqPrivilegeLevel > minPriv)
69     {
70         // Requested level exceeds Channel and/or User Privilege Limit
71         response->completionCode = IPMI_CC_EXCEEDS_USER_PRIV;
72     }
73     else
74     {
75         // update current privilege of the session.
76         session->curPrivLevel =
77             static_cast<session::Privilege>(reqPrivilegeLevel);
78         response->newPrivLevel = reqPrivilegeLevel;
79     }
80 
81     return outPayload;
82 }
83 
84 std::vector<uint8_t> closeSession(const std::vector<uint8_t>& inPayload,
85                                   const message::Handler& handler)
86 {
87     std::vector<uint8_t> outPayload(sizeof(CloseSessionResponse));
88     auto request =
89         reinterpret_cast<const CloseSessionRequest*>(inPayload.data());
90     auto response = reinterpret_cast<CloseSessionResponse*>(outPayload.data());
91     response->completionCode = IPMI_CC_OK;
92 
93     auto bmcSessionID = endian::from_ipmi(request->sessionID);
94 
95     // Session 0 is needed to handle session setup, so session zero is never
96     // closed
97     if (bmcSessionID == session::SESSION_ZERO)
98     {
99         response->completionCode = IPMI_CC_INVALID_SESSIONID;
100     }
101     else
102     {
103         auto status = std::get<session::Manager&>(singletonPool)
104                           .stopSession(bmcSessionID);
105         if (!status)
106         {
107             response->completionCode = IPMI_CC_INVALID_SESSIONID;
108         }
109     }
110     return outPayload;
111 }
112 
113 } // namespace command
114