user_layer: Add get/set user payload access.
IPMI Spec reference: Section 24.6, 24.7.
Support is added to get/set user access details for the
unreserved, supported payload types defined by Spec.
SOL is the only unreserved, supported payload currently.
If support is needed for unreserved std/oem payload
types in future, they can be enabled with minor source code
changes to this implementation.
All payload types are packed in a JSON object
"payload_enabled" in ipmi_user.json file.
Tested-by:
1. For user 8 in channel 3, Enable SOL payload.
// Command - (channel 3 is of LAN channel type)
ipmitool -I lanplus...raw 0x06 0x4C 3 0x8 0x02 0 0 0
// Verify it with Get User Payload Access Command
ipmitool -I lanplus...raw 0x06 0x4D 3 8
02 00 00 00 // Response
2. Disable SOL payload.
// Command
ipmitool -I lanplus...raw 0x06 0x4C 3 0x48 0x02 0 0x00 0
// Verify it with Get User Payload Access Command
ipmitool -I lanplus...raw 0x06 0x4D 3 8
00 00 00 00 // Response
3. Enable unsupported payload stdPayload7.
// Command
ipmitool -I lanplus...raw 0x06 0x4C 3 0x8 0x80 0 0 0
Error: Invalid data field in request // Response
Change-Id: Idc57b04a747e55666407d928d8b2169223501e5b
Signed-off-by: Saravanan Palanisamy <saravanan.palanisamy@linux.intel.com>
diff --git a/user_channel/user_mgmt.cpp b/user_channel/user_mgmt.cpp
index 9b40f6c..f877981 100644
--- a/user_channel/user_mgmt.cpp
+++ b/user_channel/user_mgmt.cpp
@@ -16,6 +16,7 @@
#include "user_mgmt.hpp"
#include "apphandler.hpp"
+#include "channel_layer.hpp"
#include <security/pam_appl.h>
#include <sys/stat.h>
@@ -833,6 +834,60 @@
return IPMI_CC_OK;
}
+ipmi_ret_t UserAccess::setUserPayloadAccess(const uint8_t chNum,
+ const uint8_t operation,
+ const uint8_t userId,
+ const PayloadAccess& payloadAccess)
+{
+ constexpr uint8_t enable = 0x0;
+ constexpr uint8_t disable = 0x1;
+
+ if (!isValidChannel(chNum))
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ if (!isValidUserId(userId))
+ {
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+ if (operation != enable && operation != disable)
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ // Check operation & payloadAccess if required.
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ userLock{*userMutex};
+ UserInfo* userInfo = getUserInfo(userId);
+
+ if (operation == enable)
+ {
+ userInfo->payloadAccess[chNum].stdPayloadEnables1 |=
+ payloadAccess.stdPayloadEnables1;
+
+ userInfo->payloadAccess[chNum].oemPayloadEnables1 |=
+ payloadAccess.oemPayloadEnables1;
+ }
+ else
+ {
+ userInfo->payloadAccess[chNum].stdPayloadEnables1 &=
+ ~(payloadAccess.stdPayloadEnables1);
+
+ userInfo->payloadAccess[chNum].oemPayloadEnables1 &=
+ ~(payloadAccess.oemPayloadEnables1);
+ }
+
+ try
+ {
+ writeUserData();
+ }
+ catch (const std::exception& e)
+ {
+ log<level::ERR>("Write user data failed");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ return IPMI_CC_OK;
+}
+
ipmi_ret_t UserAccess::setUserPrivilegeAccess(const uint8_t userId,
const uint8_t chNum,
const UserPrivAccess& privAccess,
@@ -1040,6 +1095,98 @@
static constexpr const char* jsonUserEnabled = "user_enabled";
static constexpr const char* jsonUserInSys = "user_in_system";
static constexpr const char* jsonFixedUser = "fixed_user_name";
+static constexpr const char* payloadEnabledStr = "payload_enabled";
+static constexpr const char* stdPayloadStr = "std_payload";
+static constexpr const char* oemPayloadStr = "OEM_payload";
+
+/** @brief to construct a JSON object from the given payload access details.
+ *
+ * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array. (input)
+ * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array. (input)
+ *
+ * @details Sample output JSON object format :
+ * "payload_enabled":{
+ * "OEM_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "OEM_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "OEM_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "OEM_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "OEM_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "OEM_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "OEM_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "OEM_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "std_payload0":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "std_payload1":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "std_payload2":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "std_payload3":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "std_payload4":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "std_payload5":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "std_payload6":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * "std_payload7":[false,...<repeat 'ipmiMaxChannels - 1' times>],
+ * }
+ */
+static const Json constructJsonPayloadEnables(
+ const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
+ stdPayload,
+ const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
+ oemPayload)
+{
+ Json jsonPayloadEnabled;
+
+ for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
+ {
+ std::ostringstream stdPayloadStream;
+ std::ostringstream oemPayloadStream;
+
+ stdPayloadStream << stdPayloadStr << payloadNum;
+ oemPayloadStream << oemPayloadStr << payloadNum;
+
+ jsonPayloadEnabled.push_back(Json::object_t::value_type(
+ stdPayloadStream.str(), stdPayload[payloadNum]));
+
+ jsonPayloadEnabled.push_back(Json::object_t::value_type(
+ oemPayloadStream.str(), oemPayload[payloadNum]));
+ }
+ return jsonPayloadEnabled;
+}
+
+void UserAccess::readPayloadAccessFromUserInfo(
+ const UserInfo& userInfo,
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& stdPayload,
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>& oemPayload)
+{
+ for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
+ {
+ for (auto chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
+ {
+ stdPayload[payloadNum][chIndex] =
+ userInfo.payloadAccess[chIndex].stdPayloadEnables1[payloadNum];
+
+ oemPayload[payloadNum][chIndex] =
+ userInfo.payloadAccess[chIndex].oemPayloadEnables1[payloadNum];
+ }
+ }
+}
+
+void UserAccess::updatePayloadAccessInUserInfo(
+ const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
+ stdPayload,
+ const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
+ oemPayload,
+ UserInfo& userInfo)
+{
+ for (size_t chIndex = 0; chIndex < ipmiMaxChannels; ++chIndex)
+ {
+ // Ensure that reserved/unsupported payloads are marked to zero.
+ userInfo.payloadAccess[chIndex].stdPayloadEnables1.reset();
+ userInfo.payloadAccess[chIndex].oemPayloadEnables1.reset();
+ userInfo.payloadAccess[chIndex].stdPayloadEnables2Reserved.reset();
+ userInfo.payloadAccess[chIndex].oemPayloadEnables2Reserved.reset();
+ // Update SOL status as it is the only supported payload currently.
+ userInfo.payloadAccess[chIndex]
+ .stdPayloadEnables1[static_cast<uint8_t>(ipmi::PayloadType::SOL)] =
+ stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)][chIndex];
+ }
+}
void UserAccess::readUserData()
{
@@ -1063,6 +1210,15 @@
throw std::runtime_error(
"Corrupted IPMI user data file - invalid user count");
}
+
+ // Construct a JSON object with default payload access values.
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> stdPayload =
+ {};
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte> oemPayload =
+ {};
+ static const Json jsonPayloadEnabledDefault =
+ constructJsonPayloadEnables(stdPayload, oemPayload);
+
// user index 0 is reserved, starts with 1
for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
{
@@ -1086,6 +1242,36 @@
userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
std::vector<bool> accessCallback =
userInfo[jsonAccCallbk].get<std::vector<bool>>();
+
+ // Payload Enables Processing.
+ auto jsonPayloadEnabled =
+ userInfo.value<Json>(payloadEnabledStr, jsonPayloadEnabledDefault);
+
+ for (auto payloadNum = 0; payloadNum < payloadsPerByte; payloadNum++)
+ {
+ std::ostringstream stdPayloadStream;
+ std::ostringstream oemPayloadStream;
+
+ stdPayloadStream << stdPayloadStr << payloadNum;
+ oemPayloadStream << oemPayloadStr << payloadNum;
+
+ stdPayload[payloadNum] =
+ jsonPayloadEnabled[stdPayloadStream.str()]
+ .get<std::array<bool, ipmiMaxChannels>>();
+ oemPayload[payloadNum] =
+ jsonPayloadEnabled[oemPayloadStream.str()]
+ .get<std::array<bool, ipmiMaxChannels>>();
+
+ if (stdPayload[payloadNum].size() != ipmiMaxChannels ||
+ oemPayload[payloadNum].size() != ipmiMaxChannels)
+ {
+ log<level::ERR>("Error in reading IPMI user data file - "
+ "payload properties corrupted");
+ throw std::runtime_error(
+ "Corrupted IPMI user data file - payload properties");
+ }
+ }
+
if (privilege.size() != ipmiMaxChannels ||
ipmiEnabled.size() != ipmiMaxChannels ||
linkAuthEnabled.size() != ipmiMaxChannels ||
@@ -1108,6 +1294,8 @@
usersTbl.user[usrIndex].userPrivAccess[chIndex].accessCallback =
accessCallback[chIndex];
}
+ updatePayloadAccessInUserInfo(stdPayload, oemPayload,
+ usersTbl.user[usrIndex]);
usersTbl.user[usrIndex].userEnabled =
userInfo[jsonUserEnabled].get<bool>();
usersTbl.user[usrIndex].userInSystem =
@@ -1140,6 +1328,12 @@
std::vector<bool> ipmiEnabled(ipmiMaxChannels);
std::vector<bool> linkAuthEnabled(ipmiMaxChannels);
std::vector<bool> accessCallback(ipmiMaxChannels);
+
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
+ stdPayload;
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
+ oemPayload;
+
for (size_t chIndex = 0; chIndex < ipmiMaxChannels; chIndex++)
{
privilege[chIndex] =
@@ -1159,6 +1353,13 @@
jsonUserInfo[jsonUserEnabled] = usersTbl.user[usrIndex].userEnabled;
jsonUserInfo[jsonUserInSys] = usersTbl.user[usrIndex].userInSystem;
jsonUserInfo[jsonFixedUser] = usersTbl.user[usrIndex].fixedUserName;
+
+ readPayloadAccessFromUserInfo(usersTbl.user[usrIndex], stdPayload,
+ oemPayload);
+ Json jsonPayloadEnabledInfo =
+ constructJsonPayloadEnables(stdPayload, oemPayload);
+ jsonUserInfo[payloadEnabledStr] = jsonPayloadEnabledInfo;
+
jsonUsersTbl.push_back(jsonUserInfo);
}