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