summaryrefslogtreecommitdiffstats
path: root/user_channel
diff options
context:
space:
mode:
Diffstat (limited to 'user_channel')
-rw-r--r--user_channel/Makefile.am9
-rw-r--r--user_channel/channel_layer.cpp20
-rw-r--r--user_channel/channel_layer.hpp35
-rw-r--r--user_channel/channel_mgmt.cpp142
-rw-r--r--user_channel/channel_mgmt.hpp24
-rw-r--r--user_channel/channelcommands.cpp591
-rw-r--r--user_channel/channelcommands.hpp35
-rw-r--r--user_channel/passwd_mgr.cpp7
-rw-r--r--user_channel/user_layer.cpp59
-rw-r--r--user_channel/user_layer.hpp62
-rw-r--r--user_channel/user_mgmt.cpp495
-rw-r--r--user_channel/user_mgmt.hpp86
-rw-r--r--user_channel/usercommands.cpp207
13 files changed, 1164 insertions, 608 deletions
diff --git a/user_channel/Makefile.am b/user_channel/Makefile.am
index 3860a39..747c4c8 100644
--- a/user_channel/Makefile.am
+++ b/user_channel/Makefile.am
@@ -12,7 +12,12 @@ COMMON_CXX = \
-DBOOST_ASIO_DISABLE_THREADS \
-DBOOST_ALL_NO_LIB
-lib_LTLIBRARIES = libuserlayer.la libchannellayer.la
+
+lib_LTLIBRARIES =
+
+if FEATURE_LIBUSERLAYER
+
+lib_LTLIBRARIES += libuserlayer.la
libuserlayer_la_SOURCES = \
user_layer.cpp \
user_mgmt.cpp \
@@ -29,7 +34,9 @@ libuserlayer_la_LDFLAGS = \
libuserlayer_la_CXXFLAGS = \
-I$(top_srcdir) \
$(COMMON_CXX)
+endif
+lib_LTLIBRARIES += libchannellayer.la
libchannellayer_la_SOURCES = \
channel_mgmt.cpp \
channel_layer.cpp
diff --git a/user_channel/channel_layer.cpp b/user_channel/channel_layer.cpp
index 34a596d..c6866c2 100644
--- a/user_channel/channel_layer.cpp
+++ b/user_channel/channel_layer.cpp
@@ -58,11 +58,6 @@ bool isValidChannel(const uint8_t chNum)
return getChannelConfigObject().isValidChannel(chNum);
}
-uint8_t convertCurrentChannelNum(const uint8_t chNum)
-{
- return getChannelConfigObject().convertToChannelIndexNumber(chNum);
-}
-
bool isValidAuthType(const uint8_t chNum, const EAuthType& authType)
{
return getChannelConfigObject().isValidAuthType(chNum, authType);
@@ -142,4 +137,19 @@ std::string getChannelName(const uint8_t chNum)
return getChannelConfigObject().getChannelName(chNum);
}
+uint8_t getChannelByName(const std::string& chName)
+{
+ return getChannelConfigObject().getChannelByName(chName);
+}
+
+bool isValidPayloadType(const PayloadType payloadType)
+{
+ return (
+ payloadType == PayloadType::IPMI || payloadType == PayloadType::SOL ||
+ payloadType == PayloadType::OPEN_SESSION_REQUEST ||
+ payloadType == PayloadType::OPEN_SESSION_RESPONSE ||
+ payloadType == PayloadType::RAKP1 ||
+ payloadType == PayloadType::RAKP2 ||
+ payloadType == PayloadType::RAKP3 || payloadType == PayloadType::RAKP4);
+}
} // namespace ipmi
diff --git a/user_channel/channel_layer.hpp b/user_channel/channel_layer.hpp
index 1a8d64c..4eb51b7 100644
--- a/user_channel/channel_layer.hpp
+++ b/user_channel/channel_layer.hpp
@@ -16,7 +16,6 @@
#pragma once
#include <ipmid/api.h>
-#include <ipmid/message.hpp>
#include <string>
namespace ipmi
@@ -24,6 +23,7 @@ namespace ipmi
static constexpr uint8_t maxIpmiChannels = 16;
static constexpr uint8_t currentChNum = 0xE;
+static constexpr uint8_t invalidChannel = 0xff;
/**
* @enum IPMI return codes specific to channel (refer spec se 22.22 response
@@ -280,30 +280,21 @@ ipmi_ret_t getChannelAccessData(const uint8_t chNum,
/** @brief provides function to convert current channel number (0xE)
*
* @param[in] chNum - channel number as requested in commands.
- * @param[in] ipmi::context - ipmi context ptr, which has more details
+ * @param[in] devChannel - channel number as provided by device (not 0xE)
*
* @return same channel number or proper channel number for current channel
* number (0xE).
*/
-inline uint8_t convertCurrentChannelNum(const uint8_t chNum,
- ipmi::Context::ptr ctx)
+static inline uint8_t convertCurrentChannelNum(const uint8_t chNum,
+ const uint8_t devChannel)
{
if (chNum == currentChNum)
{
- return ctx->channel;
+ return devChannel;
}
return chNum;
}
-/** @brief provides function to convert current channel number (0xE)
- *
- * @param[in] chNum - channel number as requested in commands.
- *
- * @return same channel number or proper channel number for current channel
- * number (0xE).
- */
-uint8_t convertCurrentChannelNum(const uint8_t chNum);
-
/** @brief to set channel access data
*
* @param[in] chNum - channel number
@@ -367,4 +358,20 @@ ipmi_ret_t getChannelEnabledAuthType(const uint8_t chNum, const uint8_t priv,
*/
std::string getChannelName(const uint8_t chNum);
+/** @brief Retrieves the LAN channel number from the IPMI channel name
+ *
+ * @param[in] chName - IPMI channel name (i.e. eth0)
+ *
+ * @return the LAN channel number
+ */
+uint8_t getChannelByName(const std::string& chName);
+
+/** @brief determines whether payload type is valid
+ *
+ * @param[in] payload type - Payload Type
+ *
+ * @return true if valid, false otherwise
+ */
+bool isValidPayloadType(const PayloadType payloadType);
+
} // namespace ipmi
diff --git a/user_channel/channel_mgmt.cpp b/user_channel/channel_mgmt.cpp
index 3fb19b2..759de43 100644
--- a/user_channel/channel_mgmt.cpp
+++ b/user_channel/channel_mgmt.cpp
@@ -34,7 +34,6 @@
namespace ipmi
{
-namespace variant_ns = sdbusplus::message::variant_ns;
using namespace phosphor::logging;
static constexpr const char* channelAccessDefaultFilename =
@@ -143,7 +142,7 @@ std::string ChannelConfig::getChannelName(const uint8_t chNum)
if (!isValidChannel(chNum))
{
log<level::ERR>("Invalid channel number.",
- entry("ChannelID:%d", chNum));
+ entry("CHANNEL_ID=%d", chNum));
throw std::invalid_argument("Invalid channel number");
}
@@ -161,7 +160,7 @@ int ChannelConfig::convertToChannelNumberFromChannelName(
}
}
log<level::ERR>("Invalid channel name.",
- entry("Channel:%s", chName.c_str()));
+ entry("CHANNEL=%s", chName.c_str()));
throw std::invalid_argument("Invalid channel name");
return -1;
@@ -169,15 +168,15 @@ int ChannelConfig::convertToChannelNumberFromChannelName(
std::string ChannelConfig::getChannelNameFromPath(const std::string& path)
{
- std::size_t pos = path.find(networkIntfObjectBasePath);
- if (pos == std::string::npos)
+
+ constexpr size_t length = strlen(networkIntfObjectBasePath);
+ if (((length + 1) >= path.size()) ||
+ path.compare(0, length, networkIntfObjectBasePath))
{
- log<level::ERR>("Invalid interface path.",
- entry("PATH:%s", path.c_str()));
- throw std::invalid_argument("Invalid interface path");
+ log<level::ERR>("Invalid object path.", entry("PATH=%s", path.c_str()));
+ throw std::invalid_argument("Invalid object path");
}
- std::string chName =
- path.substr(pos + strlen(networkIntfObjectBasePath) + 1);
+ std::string chName(path, length + 1);
return chName;
}
@@ -192,7 +191,7 @@ void ChannelConfig::processChAccessPropChange(
}
catch (const std::invalid_argument& e)
{
- log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
+ log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
return;
}
@@ -204,7 +203,7 @@ void ChannelConfig::processChAccessPropChange(
if (prop.first == privilegePropertyString)
{
propName = privilegePropertyString;
- intfPrivStr = variant_ns::get<std::string>(prop.second);
+ intfPrivStr = std::get<std::string>(prop.second);
break;
}
}
@@ -218,7 +217,7 @@ void ChannelConfig::processChAccessPropChange(
if (intfPrivStr.empty())
{
log<level::ERR>("Invalid privilege string.",
- entry("INTF:%s", chName.c_str()));
+ entry("INTF=%s", chName.c_str()));
return;
}
@@ -231,7 +230,7 @@ void ChannelConfig::processChAccessPropChange(
}
catch (const std::invalid_argument& e)
{
- log<level::ERR>("Exception: ", entry("MSG: %s", e.what()));
+ log<level::ERR>("Exception: ", entry("MSG=%s", e.what()));
return;
}
@@ -614,7 +613,7 @@ ipmi_ret_t ChannelConfig::setChannelAccessPersistData(
{
log<level::DEBUG>(
"Network interface does not exist",
- entry("INTERFACE:%s", channelData[chNum].chName.c_str()));
+ entry("INTERFACE=%s", channelData[chNum].chName.c_str()));
return IPMI_CC_UNSPECIFIED_ERROR;
}
}
@@ -787,45 +786,13 @@ EChannelProtocolType
return static_cast<EChannelProtocolType>(it->second);
}
-uint8_t ChannelConfig::convertToChannelIndexNumber(const uint8_t chNum)
-{
-
- // TODO: There is limitation in current design. we cannot detect exact
- // LAN interface(eth0 or eth1) so Implementation may be updated
- // when there is any design update to figure out all the interfaces
- // independently based on the message.
-
- static uint8_t curChannel = 0xFF;
-
- if (curChannel == 0xFF)
- {
- auto it = interfaceMap.find(getInterfaceIndex());
- if (it == interfaceMap.end())
- {
- log<level::ERR>("Invalid Interface type ",
- entry("InterfaceIndex: %d", getInterfaceIndex()));
- throw std::invalid_argument("Invalid interface type.");
- }
-
- for (auto& channel : channelData)
- {
- std::string& interfaceName = it->second;
- if (channel.chName == interfaceName)
- {
- curChannel = channel.chID;
- break;
- }
- }
- }
- return ((chNum == currentChNum) ? curChannel : chNum);
-}
-
Json ChannelConfig::readJsonFile(const std::string& configFile)
{
std::ifstream jsonFile(configFile);
if (!jsonFile.good())
{
- log<level::ERR>("JSON file not found");
+ log<level::INFO>("JSON file not found",
+ entry("FILE_NAME=%s", configFile.c_str()));
return nullptr;
}
@@ -837,7 +804,7 @@ Json ChannelConfig::readJsonFile(const std::string& configFile)
catch (Json::parse_error& e)
{
log<level::DEBUG>("Corrupted channel config.",
- entry("MSG: %s", e.what()));
+ entry("MSG=%s", e.what()));
throw std::runtime_error("Corrupted channel config file");
}
@@ -847,17 +814,33 @@ Json ChannelConfig::readJsonFile(const std::string& configFile)
int ChannelConfig::writeJsonFile(const std::string& configFile,
const Json& jsonData)
{
- std::ofstream jsonFile(configFile);
- if (!jsonFile.good())
+ const std::string tmpFile = configFile + "_tmp";
+ int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ {
+ log<level::ERR>("Error in creating json file",
+ entry("FILE_NAME = %s", tmpFile.c_str()));
+ return -EIO;
+ }
+ const auto& writeData = jsonData.dump();
+ if (write(fd, writeData.c_str(), writeData.size()) !=
+ static_cast<ssize_t>(writeData.size()))
{
- log<level::ERR>("JSON file not found");
+ close(fd);
+ log<level::ERR>("Error in writing configuration file",
+ entry("FILE_NAME = %s", tmpFile.c_str()));
return -EIO;
}
+ close(fd);
- // Write JSON to file
- jsonFile << jsonData;
+ if (std::rename(tmpFile.c_str(), configFile.c_str()) != 0)
+ {
+ log<level::ERR>("Error in renaming temporary data file",
+ entry("FILE_NAME = %s", tmpFile.c_str()));
+ return -EIO;
+ }
- jsonFile.flush();
return 0;
}
@@ -900,7 +883,7 @@ int ChannelConfig::loadChannelConfig()
{
log<level::WARNING>(
"Channel not configured so loading default.",
- entry("CHANNEL_NUM:%d", chNum));
+ entry("CHANNEL_NUM=%d", chNum));
// If user didn't want to configure specific channel (say
// reserved channel), then load that index with default values.
setDefaultChannelConfig(chNum, defaultChannelName);
@@ -938,12 +921,12 @@ int ChannelConfig::loadChannelConfig()
catch (const Json::exception& e)
{
log<level::DEBUG>("Json Exception caught.",
- entry("MSG:%s", e.what()));
+ entry("MSG=%s", e.what()));
return -EBADMSG;
}
catch (const std::invalid_argument& e)
{
- log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
+ log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
return -EBADMSG;
}
}
@@ -997,7 +980,7 @@ int ChannelConfig::readChannelVolatileData()
{
log<level::ERR>(
"Invalid/corrupted volatile channel access file",
- entry("FILE: %s", channelVolatileDataFilename));
+ entry("FILE=%s", channelVolatileDataFilename));
throw std::runtime_error(
"Corrupted volatile channel access file");
}
@@ -1005,12 +988,12 @@ int ChannelConfig::readChannelVolatileData()
}
catch (const Json::exception& e)
{
- log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
+ log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
throw std::runtime_error("Corrupted volatile channel access file");
}
catch (const std::invalid_argument& e)
{
- log<level::ERR>("Corrupted config.", entry("MSG:%s", e.what()));
+ log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
throw std::runtime_error("Corrupted volatile channel access file");
}
@@ -1065,19 +1048,19 @@ int ChannelConfig::readChannelPersistData()
else
{
log<level::ERR>("Invalid/corrupted nv channel access file",
- entry("FILE:%s", channelNvDataFilename));
+ entry("FILE=%s", channelNvDataFilename));
throw std::runtime_error("Corrupted nv channel access file");
}
}
}
catch (const Json::exception& e)
{
- log<level::DEBUG>("Json Exception caught.", entry("MSG:%s", e.what()));
+ log<level::DEBUG>("Json Exception caught.", entry("MSG=%s", e.what()));
throw std::runtime_error("Corrupted nv channel access file");
}
catch (const std::invalid_argument& e)
{
- log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
+ log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
throw std::runtime_error("Corrupted nv channel access file");
}
@@ -1120,7 +1103,7 @@ int ChannelConfig::writeChannelVolatileData()
}
catch (const std::invalid_argument& e)
{
- log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
+ log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
return -EINVAL;
}
@@ -1171,7 +1154,7 @@ int ChannelConfig::writeChannelPersistData()
}
catch (const std::invalid_argument& e)
{
- log<level::ERR>("Corrupted config.", entry("MSG: %s", e.what()));
+ log<level::ERR>("Corrupted config.", entry("MSG=%s", e.what()));
return -EINVAL;
}
@@ -1245,10 +1228,10 @@ int ChannelConfig::setDbusProperty(const std::string& service,
catch (const sdbusplus::exception::SdBusError& e)
{
log<level::DEBUG>("set-property failed",
- entry("SERVICE:%s", service.c_str()),
- entry("OBJPATH:%s", objPath.c_str()),
- entry("INTERFACE:%s", interface.c_str()),
- entry("PROP:%s", property.c_str()));
+ entry("SERVICE=%s", service.c_str()),
+ entry("OBJPATH=%s", objPath.c_str()),
+ entry("INTERFACE=%s", interface.c_str()),
+ entry("PROP=%s", property.c_str()));
return -EIO;
}
@@ -1275,10 +1258,10 @@ int ChannelConfig::getDbusProperty(const std::string& service,
catch (const sdbusplus::exception::SdBusError& e)
{
log<level::DEBUG>("get-property failed",
- entry("SERVICE:%s", service.c_str()),
- entry("OBJPATH:%s", objPath.c_str()),
- entry("INTERFACE:%s", interface.c_str()),
- entry("PROP:%s", property.c_str()));
+ entry("SERVICE=%s", service.c_str()),
+ entry("OBJPATH=%s", objPath.c_str()),
+ entry("INTERFACE=%s", interface.c_str()),
+ entry("PROP=%s", property.c_str()));
return -EIO;
}
return 0;
@@ -1305,13 +1288,13 @@ int ChannelConfig::syncNetworkChannelConfig()
privilegePropertyString, variant))
{
log<level::DEBUG>("Network interface does not exist",
- entry("INTERFACE:%s",
+ entry("INTERFACE=%s",
channelData[chNum].chName.c_str()));
continue;
}
- intfPrivStr = variant_ns::get<std::string>(variant);
+ intfPrivStr = std::get<std::string>(variant);
}
- catch (const variant_ns::bad_variant_access& e)
+ catch (const std::bad_variant_access& e)
{
log<level::DEBUG>(
"exception: Network interface does not exist");
@@ -1358,6 +1341,9 @@ int ChannelConfig::syncNetworkChannelConfig()
void ChannelConfig::initChannelPersistData()
{
+ boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
+ channelLock{*channelMutex};
+
/* Always read the channel config */
if (loadChannelConfig() != 0)
{
diff --git a/user_channel/channel_mgmt.hpp b/user_channel/channel_mgmt.hpp
index 35bb494..80bd6d9 100644
--- a/user_channel/channel_mgmt.hpp
+++ b/user_channel/channel_mgmt.hpp
@@ -23,14 +23,14 @@
#include <ctime>
#include <nlohmann/json.hpp>
#include <sdbusplus/bus.hpp>
+#include <variant>
namespace ipmi
{
using Json = nlohmann::json;
-using DbusVariant =
- sdbusplus::message::variant<std::vector<std::string>, std::string, bool>;
+using DbusVariant = std::variant<std::vector<std::string>, std::string, bool>;
using DbusChObjProperties = std::vector<std::pair<std::string, DbusVariant>>;
@@ -105,6 +105,18 @@ class ChannelConfig
*/
std::string getChannelName(const uint8_t chNum);
+ /** @brief function to get channel number from channel name
+ *
+ * @param[in] chName - channel name
+ *
+ * @return network channel interface number
+ */
+
+ uint8_t getChannelByName(const std::string& chName)
+ {
+ return convertToChannelNumberFromChannelName(chName);
+ }
+
/** @brief determines supported session type of a channel
*
* @param[in] chNum - channel number
@@ -212,14 +224,6 @@ class ChannelConfig
*/
CommandPrivilege convertToPrivLimitIndex(const std::string& value);
- /** @brief function to convert channel number to channel index
- *
- * @param[in] chNum - channel number
- *
- * @return channel index
- */
- uint8_t convertToChannelIndexNumber(const uint8_t chNum);
-
/** @brief function to write persistent channel configuration to config file
*
* @return 0 for success, -errno for failure.
diff --git a/user_channel/channelcommands.cpp b/user_channel/channelcommands.cpp
index d1b275e..adf19d5 100644
--- a/user_channel/channelcommands.cpp
+++ b/user_channel/channelcommands.cpp
@@ -14,11 +14,10 @@
// limitations under the License.
*/
-#include "channelcommands.hpp"
-
#include "apphandler.hpp"
#include "channel_layer.hpp"
+#include <ipmid/api.hpp>
#include <phosphor-logging/log.hpp>
#include <regex>
@@ -27,241 +26,99 @@ using namespace phosphor::logging;
namespace ipmi
{
-/** @struct SetChannelAccessReq
- *
- * Structure for set channel access request command (refer spec sec 22.22)
- */
-struct SetChannelAccessReq
-{
-#if BYTE_ORDER == LITTLE_ENDIAN
- uint8_t chNum : 4;
- uint8_t reserved_1 : 4;
- uint8_t accessMode : 3;
- uint8_t usrAuthDisabled : 1;
- uint8_t msgAuthDisabled : 1;
- uint8_t alertDisabled : 1;
- uint8_t accessSetMode : 2;
- uint8_t privLimit : 4;
- uint8_t reserved_2 : 2;
- uint8_t privSetMode : 2;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- uint8_t reserved_1 : 4;
- uint8_t chNum : 4;
- uint8_t accessSetMode : 2;
- uint8_t alertDisabled : 1;
- uint8_t msgAuthDisabled : 1;
- uint8_t usrAuthDisabled : 1;
- uint8_t accessMode : 3;
- uint8_t privSetMode : 2;
- uint8_t reserved_2 : 2;
- uint8_t privLimit : 4;
-#endif
-
-} __attribute__((packed));
-
-/** @struct GetChannelAccessReq
- *
- * Structure for get channel access request command (refer spec sec 22.23)
- */
-struct GetChannelAccessReq
-{
-#if BYTE_ORDER == LITTLE_ENDIAN
- uint8_t chNum : 4;
- uint8_t reserved_1 : 4;
- uint8_t reserved_2 : 6;
- uint8_t accessSetMode : 2;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- uint8_t reserved_1 : 4;
- uint8_t chNum : 4;
- uint8_t accessSetMode : 2;
- uint8_t reserved_2 : 6;
-#endif
-} __attribute__((packed));
-
-/** @struct GetChannelAccessResp
+static constexpr const uint8_t ccActionNotSupportedForChannel = 0x82;
+
+/** @brief implements the set channel access command
+ * @ param ctx - context pointer
+ * @ param channel - channel number
+ * @ param reserved - skip 4 bits
+ * @ param accessMode - access mode for IPMI messaging
+ * @ param usrAuth - user level authentication (enable/disable)
+ * @ param msgAuth - per message authentication (enable/disable)
+ * @ param alertDisabled - PEF alerting (enable/disable)
+ * @ param chanAccess - channel access
+ * @ param channelPrivLimit - channel privilege limit
+ * @ param reserved - skip 3 bits
+ * @ param channelPrivMode - channel priviledge mode
*
- * Structure for get channel access response command (refer spec sec 22.23)
- */
-struct GetChannelAccessResp
+ * @ returns IPMI completion code
+ **/
+RspType<> ipmiSetChannelAccess(Context::ptr ctx, uint4_t channel,
+ uint4_t reserved1, uint3_t accessMode,
+ bool usrAuth, bool msgAuth, bool alertDisabled,
+ uint2_t chanAccess, uint4_t channelPrivLimit,
+ uint2_t reserved2, uint2_t channelPrivMode)
{
-#if BYTE_ORDER == LITTLE_ENDIAN
- uint8_t accessMode : 3;
- uint8_t usrAuthDisabled : 1;
- uint8_t msgAuthDisabled : 1;
- uint8_t alertDisabled : 1;
- uint8_t reserved_1 : 2;
- uint8_t privLimit : 4;
- uint8_t reserved_2 : 4;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- uint8_t reserved_1 : 2;
- uint8_t alertDisabled : 1;
- uint8_t msgAuthDisabled : 1;
- uint8_t usrAuthDisabled : 1;
- uint8_t accessMode : 3;
- uint8_t reserved_2 : 4;
- uint8_t privLimit : 4;
-#endif
-} __attribute__((packed));
-
-/** @struct GetChannelInfoReq
- *
- * Structure for get channel info request command (refer spec sec 22.24)
- */
-struct GetChannelInfoReq
-{
-#if BYTE_ORDER == LITTLE_ENDIAN
- uint8_t chNum : 4;
- uint8_t reserved_1 : 4;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- uint8_t reserved_1 : 4;
- uint8_t chNum : 4;
-#endif
-} __attribute__((packed));
-
-/** @struct GetChannelInfoResp
- *
- * Structure for get channel info response command (refer spec sec 22.24)
- */
-struct GetChannelInfoResp
-{
-#if BYTE_ORDER == LITTLE_ENDIAN
- uint8_t chNum : 4;
- uint8_t reserved_1 : 4;
- uint8_t mediumType : 7;
- uint8_t reserved_2 : 1;
- uint8_t msgProtType : 5;
- uint8_t reserved_3 : 3;
- uint8_t actSessCount : 6;
- uint8_t sessType : 2;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- uint8_t reserved_1 : 4;
- uint8_t chNum : 4;
- uint8_t reserved_2 : 1;
- uint8_t mediumType : 7;
- uint8_t reserved_3 : 3;
- uint8_t msgProtType : 5;
- uint8_t sessType : 2;
- uint8_t actSessCount : 6;
-#endif
- uint8_t vendorId[3];
- uint8_t auxChInfo[2];
-} __attribute__((packed));
-
-/** @struct GetChannelPayloadSupportReq
- *
- * Structure for get channel payload support command request (refer spec
- * sec 24.8)
- */
-struct GetChannelPayloadSupportReq
-{
-#if BYTE_ORDER == LITTLE_ENDIAN
- uint8_t chNum : 4;
- uint8_t reserved : 4;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- uint8_t reserved : 4;
- uint8_t chNum : 4;
-#endif
-} __attribute__((packed));
-
-/** @struct GetChannelPayloadSupportResp
- *
- * Structure for get channel payload support command response (refer spec
- * sec 24.8)
- */
-struct GetChannelPayloadSupportResp
-{
- uint8_t stdPayloadType[2];
- uint8_t sessSetupPayloadType[2];
- uint8_t OEMPayloadType[2];
- uint8_t reserved[2];
-} __attribute__((packed));
-
-ipmi_ret_t ipmiSetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
- ipmi_request_t request,
- ipmi_response_t response,
- ipmi_data_len_t data_len,
- ipmi_context_t context)
-{
- const SetChannelAccessReq* req = static_cast<SetChannelAccessReq*>(request);
- size_t reqLength = *data_len;
-
- *data_len = 0;
+ const uint8_t chNum =
+ convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
- if (reqLength != sizeof(*req))
- {
- log<level::DEBUG>("Set channel access - Invalid Length");
- return IPMI_CC_REQ_DATA_LEN_INVALID;
- }
-
- uint8_t chNum = convertCurrentChannelNum(req->chNum);
- if (!isValidChannel(chNum) || req->reserved_1 != 0 || req->reserved_2 != 0)
+ if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0)
{
log<level::DEBUG>("Set channel access - Invalid field in request");
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ return responseInvalidFieldRequest();
}
- if (EChannelSessSupported::none == getChannelSessionSupport(chNum))
+ if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
{
log<level::DEBUG>("Set channel access - No support on channel");
- return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
+ return response(ccActionNotSupportedForChannel);
}
ChannelAccess chActData;
ChannelAccess chNVData;
uint8_t setActFlag = 0;
uint8_t setNVFlag = 0;
- ipmi_ret_t compCode = IPMI_CC_OK;
+ Cc compCode;
- switch (req->accessSetMode)
+ // cannot static cast directly from uint2_t to enum; must go via int
+ uint8_t channelAccessAction = static_cast<uint8_t>(chanAccess);
+ switch (static_cast<EChannelActionType>(channelAccessAction))
{
case doNotSet:
- // Do nothing
break;
case nvData:
- chNVData.accessMode = req->accessMode;
- chNVData.userAuthDisabled = req->usrAuthDisabled;
- chNVData.perMsgAuthDisabled = req->msgAuthDisabled;
- chNVData.alertingDisabled = req->alertDisabled;
+ chNVData.accessMode = static_cast<uint8_t>(accessMode);
+ chNVData.userAuthDisabled = usrAuth;
+ chNVData.perMsgAuthDisabled = msgAuth;
+ chNVData.alertingDisabled = alertDisabled;
setNVFlag |= (setAccessMode | setUserAuthEnabled |
setMsgAuthEnabled | setAlertingEnabled);
break;
+
case activeData:
- chActData.accessMode = req->accessMode;
- chActData.userAuthDisabled = req->usrAuthDisabled;
- chActData.perMsgAuthDisabled = req->msgAuthDisabled;
- chActData.alertingDisabled = req->alertDisabled;
+ chActData.accessMode = static_cast<uint8_t>(accessMode);
+ chActData.userAuthDisabled = usrAuth;
+ chActData.perMsgAuthDisabled = msgAuth;
+ chActData.alertingDisabled = alertDisabled;
setActFlag |= (setAccessMode | setUserAuthEnabled |
setMsgAuthEnabled | setAlertingEnabled);
break;
+
case reserved:
default:
log<level::DEBUG>("Set channel access - Invalid access set mode");
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ return responseInvalidFieldRequest();
}
- switch (req->privSetMode)
+ // cannot static cast directly from uint2_t to enum; must go via int
+ uint8_t channelPrivAction = static_cast<uint8_t>(channelPrivMode);
+ switch (static_cast<EChannelActionType>(channelPrivAction))
{
case doNotSet:
- // Do nothing
break;
case nvData:
- chNVData.privLimit = req->privLimit;
+ chNVData.privLimit = static_cast<uint8_t>(channelPrivLimit);
setNVFlag |= setPrivLimit;
break;
case activeData:
- chActData.privLimit = req->privLimit;
+ chActData.privLimit = static_cast<uint8_t>(channelPrivLimit);
+
setActFlag |= setPrivLimit;
break;
case reserved:
default:
log<level::DEBUG>("Set channel access - Invalid access priv mode");
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ return responseInvalidFieldRequest();
}
if (setNVFlag != 0)
@@ -270,7 +127,7 @@ ipmi_ret_t ipmiSetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
if (compCode != IPMI_CC_OK)
{
log<level::DEBUG>("Set channel access - Failed to set access data");
- return compCode;
+ return response(compCode);
}
}
@@ -280,219 +137,250 @@ ipmi_ret_t ipmiSetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
if (compCode != IPMI_CC_OK)
{
log<level::DEBUG>("Set channel access - Failed to set access data");
- return compCode;
+ return response(compCode);
}
}
- return IPMI_CC_OK;
+ return responseSuccess();
}
-ipmi_ret_t ipmiGetChannelAccess(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
- ipmi_request_t request,
- ipmi_response_t response,
- ipmi_data_len_t data_len,
- ipmi_context_t context)
+/** @brief implements the get channel access command
+ * @ param ctx - context pointer
+ * @ param channel - channel number
+ * @ param reserved1 - skip 4 bits
+ * @ param reserved2 - skip 6 bits
+ * @ param accessMode - get access mode
+ *
+ * @returns ipmi completion code plus response data
+ * - accessMode - get access mode
+ * - usrAuthDisabled - user level authentication status
+ * - msgAuthDisabled - message level authentication status
+ * - alertDisabled - alerting status
+ * - reserved - skip 2 bits
+ * - privLimit - channel privilege limit
+ * - reserved - skip 4 bits
+ * */
+ipmi ::RspType<uint3_t, // access mode,
+ bool, // user authentication status,
+ bool, // message authentication status,
+ bool, // alerting status,
+ uint2_t, // reserved,
+
+ uint4_t, // channel privilege,
+ uint4_t // reserved
+ >
+ ipmiGetChannelAccess(Context::ptr ctx, uint4_t channel, uint4_t reserved1,
+ uint6_t reserved2, uint2_t accessSetMode)
{
- const GetChannelAccessReq* req = static_cast<GetChannelAccessReq*>(request);
- size_t reqLength = *data_len;
-
- *data_len = 0;
-
- if (reqLength != sizeof(*req))
- {
- log<level::DEBUG>("Get channel access - Invalid Length");
- return IPMI_CC_REQ_DATA_LEN_INVALID;
- }
+ const uint8_t chNum =
+ convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
- uint8_t chNum = convertCurrentChannelNum(req->chNum);
- if (!isValidChannel(chNum) || req->reserved_1 != 0 || req->reserved_2 != 0)
+ if (!isValidChannel(chNum) || reserved1 != 0 || reserved2 != 0)
{
log<level::DEBUG>("Get channel access - Invalid field in request");
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ return responseInvalidFieldRequest();
}
- if ((req->accessSetMode == doNotSet) || (req->accessSetMode == reserved))
+ if ((accessSetMode == doNotSet) || (accessSetMode == reserved))
{
log<level::DEBUG>("Get channel access - Invalid Access mode");
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ return responseInvalidFieldRequest();
}
- if (EChannelSessSupported::none == getChannelSessionSupport(chNum))
+ if (getChannelSessionSupport(chNum) == EChannelSessSupported::none)
{
log<level::DEBUG>("Get channel access - No support on channel");
- return IPMI_CC_ACTION_NOT_SUPPORTED_FOR_CHANNEL;
+ return response(ccActionNotSupportedForChannel);
}
- GetChannelAccessResp* resp = static_cast<GetChannelAccessResp*>(response);
-
- std::fill(reinterpret_cast<uint8_t*>(resp),
- reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
-
ChannelAccess chAccess;
- ipmi_ret_t compCode = IPMI_CC_OK;
- if (req->accessSetMode == nvData)
+ Cc compCode;
+
+ if (accessSetMode == nvData)
{
compCode = getChannelAccessPersistData(chNum, chAccess);
}
- else if (req->accessSetMode == activeData)
+ else if (accessSetMode == activeData)
{
compCode = getChannelAccessData(chNum, chAccess);
}
if (compCode != IPMI_CC_OK)
{
- return compCode;
+ return response(compCode);
}
- resp->accessMode = chAccess.accessMode;
- resp->usrAuthDisabled = chAccess.userAuthDisabled;
- resp->msgAuthDisabled = chAccess.perMsgAuthDisabled;
- resp->alertDisabled = chAccess.alertingDisabled;
- resp->privLimit = chAccess.privLimit;
+ constexpr uint2_t reservedOut1 = 0;
+ constexpr uint4_t reservedOut2 = 0;
- *data_len = sizeof(*resp);
- return IPMI_CC_OK;
+ return responseSuccess(
+ static_cast<uint3_t>(chAccess.accessMode), chAccess.userAuthDisabled,
+ chAccess.perMsgAuthDisabled, chAccess.alertingDisabled, reservedOut1,
+ static_cast<uint4_t>(chAccess.privLimit), reservedOut2);
}
-ipmi_ret_t ipmiGetChannelInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
- ipmi_request_t request, ipmi_response_t response,
- ipmi_data_len_t data_len, ipmi_context_t context)
+/** @brief implements the get channel info command
+ * @ param ctx - context pointer
+ * @ param channel - channel number
+ * @ param reserved - skip 4 bits
+ *
+ * @returns ipmi completion code plus response data
+ * - chNum - the channel number for this request
+ * - mediumType - see Table 6-3, Channel Medium Type Numbers
+ * - protocolType - Table 6-2, Channel Protocol Type Numbers
+ * - activeSessionCount - number of active sessions
+ * - sessionType - channel support for sessions
+ * - vendorId - vendor for this channel protocol (IPMI - 7154)
+ * - auxChInfo - auxiliary info for channel
+ * */
+RspType<uint4_t, // chNum
+ uint4_t, // reserved
+ uint7_t, // mediumType
+ bool, // reserved
+ uint5_t, // protocolType
+ uint3_t, // reserved
+ uint6_t, // activeSessionCount
+ uint2_t, // sessionType
+ uint24_t, // Vendor IANA
+ uint16_t // aux info
+ >
+ ipmiGetChannelInfo(Context::ptr ctx, uint4_t channel, uint4_t reserved)
{
- const GetChannelInfoReq* req = static_cast<GetChannelInfoReq*>(request);
- size_t reqLength = *data_len;
-
- *data_len = 0;
-
- if (reqLength != sizeof(*req))
- {
- log<level::DEBUG>("Get channel info - Invalid Length");
- return IPMI_CC_REQ_DATA_LEN_INVALID;
- }
-
- uint8_t chNum = convertCurrentChannelNum(req->chNum);
- if (!isValidChannel(chNum) || req->reserved_1 != 0)
+ uint8_t chNum =
+ convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
+ if (!isValidChannel(chNum) || reserved)
{
- log<level::DEBUG>("Get channel info - Invalid field in request");
- return IPMI_CC_INVALID_FIELD_REQUEST;
- }
-
- // Check the existance of device for session-less channels.
- if ((EChannelSessSupported::none != getChannelSessionSupport(chNum)) &&
- (!(doesDeviceExist(chNum))))
- {
- log<level::DEBUG>("Get channel info - Device not exist");
- return IPMI_CC_PARM_OUT_OF_RANGE;
+ log<level::DEBUG>("Get channel access - Invalid field in request");
+ return responseInvalidFieldRequest();
}
- GetChannelInfoResp* resp = static_cast<GetChannelInfoResp*>(response);
-
- std::fill(reinterpret_cast<uint8_t*>(resp),
- reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
-
ChannelInfo chInfo;
- ipmi_ret_t compCode = getChannelInfo(chNum, chInfo);
- if (compCode != IPMI_CC_OK)
+ Cc compCode = getChannelInfo(chNum, chInfo);
+ if (compCode != ccSuccess)
{
- return compCode;
+ log<level::ERR>("Failed to get channel info",
+ entry("CHANNEL=%x", chNum),
+ entry("ERRNO=%x", compCode));
+ return response(compCode);
}
- resp->chNum = chNum;
- resp->mediumType = chInfo.mediumType;
- resp->msgProtType = chInfo.protocolType;
- resp->actSessCount = getChannelActiveSessions(chNum);
- resp->sessType = chInfo.sessionSupported;
-
+ constexpr uint4_t reserved1 = 0;
+ constexpr bool reserved2 = false;
+ constexpr uint3_t reserved3 = 0;
+ uint8_t mediumType = chInfo.mediumType;
+ uint8_t protocolType = chInfo.protocolType;
+ uint2_t sessionType = chInfo.sessionSupported;
+ uint6_t activeSessionCount = getChannelActiveSessions(chNum);
// IPMI Spec: The IPMI Enterprise Number is: 7154 (decimal)
- resp->vendorId[0] = 0xF2;
- resp->vendorId[1] = 0x1B;
- resp->vendorId[2] = 0x00;
-
- // Auxiliary Channel info - byte 1:2
- // TODO: For System Interface(0xF) and OEM channel types, this needs
- // to be changed acoordingly.
- // All other channel types, its reverved
- resp->auxChInfo[0] = 0x00;
- resp->auxChInfo[1] = 0x00;
+ constexpr uint24_t vendorId = 7154;
+ constexpr uint16_t auxChInfo = 0;
- *data_len = sizeof(*resp);
-
- return IPMI_CC_OK;
+ return responseSuccess(chNum, reserved1, mediumType, reserved2,
+ protocolType, reserved3, activeSessionCount,
+ sessionType, vendorId, auxChInfo);
}
-ipmi_ret_t ipmiGetChannelPayloadSupport(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
- ipmi_request_t request,
- ipmi_response_t response,
- ipmi_data_len_t data_len,
- ipmi_context_t context)
+namespace
{
- const auto req = static_cast<GetChannelPayloadSupportReq*>(request);
- size_t reqLength = *data_len;
-
- *data_len = 0;
-
- if (reqLength != sizeof(*req))
- {
- log<level::DEBUG>("Get channel payload - Invalid Length");
- return IPMI_CC_REQ_DATA_LEN_INVALID;
- }
+constexpr uint16_t standardPayloadBit(PayloadType p)
+{
+ return (1 << static_cast<size_t>(p));
+}
- uint8_t chNum = convertCurrentChannelNum(req->chNum);
- if (!isValidChannel(chNum) || req->reserved != 0)
- {
- log<level::DEBUG>("Get channel payload - Invalid field in request");
- return IPMI_CC_INVALID_FIELD_REQUEST;
- }
+constexpr uint16_t sessionPayloadBit(PayloadType p)
+{
+ constexpr size_t sessionShift =
+ static_cast<size_t>(PayloadType::OPEN_SESSION_REQUEST);
+ return ((1 << static_cast<size_t>(p)) >> sessionShift);
+}
+} // namespace
- // Not supported on sessionless channels.
- if (EChannelSessSupported::none == getChannelSessionSupport(chNum))
+/** @brief implements get channel payload support command
+ * @ param ctx - ipmi context pointer
+ * @ param chNum - channel number
+ * @ param reserved - skip 4 bits
+ *
+ * @ returns IPMI completion code plus response data
+ * - stdPayloadType - bitmask of supported standard payload types
+ * - sessSetupPayloadType - bitmask of supported session setup payload types
+ * - OEMPayloadType - bitmask of supported OEM payload types
+ * - reserved - 2 bytes of 0
+ **/
+RspType<uint16_t, // stdPayloadType
+ uint16_t, // sessSetupPayloadType
+ uint16_t, // OEMPayloadType
+ uint16_t // reserved
+ >
+ ipmiGetChannelPayloadSupport(Context::ptr ctx, uint4_t channel,
+ uint4_t reserved)
+{
+ uint8_t chNum =
+ convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
+ if (!isValidChannel(chNum) || reserved)
{
- log<level::DEBUG>("Get channel payload - Sessionless Channel");
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ log<level::DEBUG>("Get channel access - Invalid field in request");
+ return responseInvalidFieldRequest();
}
// Session support is available in active LAN channels.
- if ((EChannelSessSupported::none != getChannelSessionSupport(chNum)) &&
- (!(doesDeviceExist(chNum))))
+ if ((getChannelSessionSupport(chNum) == EChannelSessSupported::none) ||
+ !(doesDeviceExist(chNum)))
{
log<level::DEBUG>("Get channel payload - Device not exist");
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ return responseInvalidFieldRequest();
}
- auto resp = static_cast<GetChannelPayloadSupportResp*>(response);
+ constexpr uint16_t stdPayloadType = standardPayloadBit(PayloadType::IPMI) |
+ standardPayloadBit(PayloadType::SOL);
+ constexpr uint16_t sessSetupPayloadType =
+ sessionPayloadBit(PayloadType::OPEN_SESSION_REQUEST) |
+ sessionPayloadBit(PayloadType::OPEN_SESSION_RESPONSE) |
+ sessionPayloadBit(PayloadType::RAKP1) |
+ sessionPayloadBit(PayloadType::RAKP2) |
+ sessionPayloadBit(PayloadType::RAKP3) |
+ sessionPayloadBit(PayloadType::RAKP4);
+ constexpr uint16_t OEMPayloadType = 0;
+ constexpr uint16_t rspRsvd = 0;
+ return responseSuccess(stdPayloadType, sessSetupPayloadType, OEMPayloadType,
+ rspRsvd);
+}
- std::fill(reinterpret_cast<uint8_t*>(resp),
- reinterpret_cast<uint8_t*>(resp) + sizeof(*resp), 0);
+/** @brief implements the get channel payload version command
+ * @param ctx - IPMI context pointer (for channel)
+ * @param chNum - channel number to get info about
+ * @param reserved - skip 4 bits
+ * @param payloadTypeNum - to get payload type info
- // TODO: Hard coding for now.
- // Mapping PayloadTypes to 'GetChannelPayloadSupportResp' fields:
- // --------------------------------------------------------------
- // Mask all except least 3 significant bits to get a value in the range of
- // 0-7. This value maps to the bit position of given payload type in 'resp'
- // fields.
+ * @returns IPMI completion code plus response data
+ * - formatVersion - BCD encoded format version info
+ */
- static constexpr uint8_t payloadByteMask = 0x07;
- static constexpr uint8_t stdPayloadTypeIPMI =
- 1 << (static_cast<uint8_t>(PayloadType::IPMI) & payloadByteMask);
- static constexpr uint8_t stdPayloadTypeSOL =
- 1 << (static_cast<uint8_t>(PayloadType::SOL) & payloadByteMask);
+RspType<uint8_t> // formatVersion
+ ipmiGetChannelPayloadVersion(Context::ptr ctx, uint4_t chNum,
+ uint4_t reserved, uint8_t payloadTypeNum)
+{
+ uint8_t channel =
+ convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel);
- static constexpr uint8_t sessPayloadTypeOpenReq =
- 1 << (static_cast<uint8_t>(PayloadType::OPEN_SESSION_REQUEST) &
- payloadByteMask);
- static constexpr uint8_t sessPayloadTypeRAKP1 =
- 1 << (static_cast<uint8_t>(PayloadType::RAKP1) & payloadByteMask);
- static constexpr uint8_t sessPayloadTypeRAKP3 =
- 1 << (static_cast<uint8_t>(PayloadType::RAKP3) & payloadByteMask);
+ if (reserved || !isValidChannel(channel) ||
+ (getChannelSessionSupport(channel)) == EChannelSessSupported::none)
+ {
+ return responseInvalidFieldRequest();
+ }
+
+ if (!isValidPayloadType(static_cast<PayloadType>(payloadTypeNum)))
+ {
+ log<level::ERR>("Channel payload version - Payload type unavailable");
- resp->stdPayloadType[0] = stdPayloadTypeIPMI | stdPayloadTypeSOL;
- // RMCP+ Open Session request, RAKP Message1 and RAKP Message3.
- resp->sessSetupPayloadType[0] =
- sessPayloadTypeOpenReq | sessPayloadTypeRAKP1 | sessPayloadTypeRAKP3;
+ constexpr uint8_t payloadTypeNotSupported = 0x80;
+ return response(payloadTypeNotSupported);
+ }
- *data_len = sizeof(*resp);
+ // BCD encoded version representation - 1.0
+ constexpr uint8_t formatVersion = 0x10;
- return IPMI_CC_OK;
+ return responseSuccess(formatVersion);
}
void registerChannelFunctions() __attribute__((constructor));
@@ -500,19 +388,20 @@ void registerChannelFunctions()
{
ipmiChannelInit();
- ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHANNEL_ACCESS, NULL,
- ipmiSetChannelAccess, PRIVILEGE_ADMIN);
+ registerHandler(prioOpenBmcBase, netFnApp, app::cmdSetChannelAccess,
+ Privilege::Admin, ipmiSetChannelAccess);
- ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
- ipmiGetChannelAccess, PRIVILEGE_USER);
+ registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelAccess,
+ Privilege::User, ipmiGetChannelAccess);
- ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_INFO, NULL,
- ipmiGetChannelInfo, PRIVILEGE_USER);
+ registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelInfoCommand,
+ Privilege::User, ipmiGetChannelInfo);
- ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_PAYLOAD_SUPPORT,
- NULL, ipmiGetChannelPayloadSupport, PRIVILEGE_USER);
+ registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadSupport,
+ Privilege::User, ipmiGetChannelPayloadSupport);
- return;
+ registerHandler(prioOpenBmcBase, netFnApp, app::cmdGetChannelPayloadVersion,
+ Privilege::User, ipmiGetChannelPayloadVersion);
}
} // namespace ipmi
diff --git a/user_channel/channelcommands.hpp b/user_channel/channelcommands.hpp
deleted file mode 100644
index abcead6..0000000
--- a/user_channel/channelcommands.hpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-// Copyright (c) 2018 Intel Corporation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-*/
-
-#pragma once
-#include <cstdint>
-
-namespace ipmi
-{
-
-/**
- * @enum IPMI commands for channel command NETFN:APP
- */
-enum ipmi_netfn_channel_cmds
-{
- IPMI_CMD_SET_CHANNEL_ACCESS = 0x40,
- IPMI_CMD_GET_CHANNEL_ACCESS = 0x41,
- IPMI_CMD_GET_CHANNEL_INFO = 0x42,
- IPMI_CMD_GET_CHANNEL_PAYLOAD_SUPPORT = 0x4E,
-};
-
-void registerChannelFunctions();
-} // namespace ipmi
diff --git a/user_channel/passwd_mgr.cpp b/user_channel/passwd_mgr.cpp
index 525b2b7..66bdef0 100644
--- a/user_channel/passwd_mgr.cpp
+++ b/user_channel/passwd_mgr.cpp
@@ -217,9 +217,10 @@ void PasswdMgr::initPasswordMap(void)
char* outPtr = reinterpret_cast<char*>(dataBuf.data());
char* nToken = NULL;
char* linePtr = strtok_r(outPtr, "\n", &nToken);
- size_t userEPos = 0, lineSize = 0;
+ size_t lineSize = 0;
while (linePtr != NULL)
{
+ size_t userEPos = 0;
std::string lineStr(linePtr);
if ((userEPos = lineStr.find(":")) != std::string::npos)
{
@@ -355,11 +356,12 @@ int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
if (inBytesLen != 0)
{
char* outPtr = reinterpret_cast<char*>(dataBuf.data());
- size_t userEPos = 0;
char* nToken = NULL;
char* linePtr = strtok_r(outPtr, "\n", &nToken);
while (linePtr != NULL)
{
+ size_t userEPos = 0;
+
std::string lineStr(linePtr);
if ((userEPos = lineStr.find(":")) != std::string::npos)
{
@@ -441,7 +443,6 @@ int PasswdMgr::updatePasswdSpecialFile(const std::string& userName,
log<level::DEBUG>("Error creating temp file");
return -EIO;
}
- fd = -1; // don't use fd anymore, as the File object owns it
// Set the file mode as of actual ipmi-pass file.
if (fchmod(fileno((temp)()), st.st_mode) < 0)
diff --git a/user_channel/user_layer.cpp b/user_channel/user_layer.cpp
index b241564..b309e86 100644
--- a/user_channel/user_layer.cpp
+++ b/user_channel/user_layer.cpp
@@ -88,6 +88,12 @@ ipmi_ret_t ipmiUserSetUserPassword(const uint8_t userId,
return getUserAccessObject().setUserPassword(userId, userPassword);
}
+ipmi_ret_t ipmiSetSpecialUserPassword(const std::string& userName,
+ const std::string& userPassword)
+{
+ return getUserAccessObject().setSpecialUserPassword(userName, userPassword);
+}
+
ipmi_ret_t ipmiUserGetAllCounts(uint8_t& maxChUsers, uint8_t& enabledUsers,
uint8_t& fixedUsers)
{
@@ -164,4 +170,57 @@ ipmi_ret_t ipmiUserSetPrivilegeAccess(const uint8_t userId, const uint8_t chNum,
userId, chNum, userPrivAccess, otherPrivUpdates);
}
+bool ipmiUserPamAuthenticate(std::string_view userName,
+ std::string_view userPassword)
+{
+ return pamUserCheckAuthenticate(userName, userPassword);
+}
+
+ipmi_ret_t ipmiUserSetUserPayloadAccess(const uint8_t chNum,
+ const uint8_t operation,
+ const uint8_t userId,
+ const PayloadAccess& payloadAccess)
+{
+
+ if (!UserAccess::isValidChannel(chNum))
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ if (!UserAccess::isValidUserId(userId))
+ {
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ return getUserAccessObject().setUserPayloadAccess(chNum, operation, userId,
+ payloadAccess);
+}
+
+ipmi_ret_t ipmiUserGetUserPayloadAccess(const uint8_t chNum,
+ const uint8_t userId,
+ PayloadAccess& payloadAccess)
+{
+
+ if (!UserAccess::isValidChannel(chNum))
+ {
+ return IPMI_CC_INVALID_FIELD_REQUEST;
+ }
+ if (!UserAccess::isValidUserId(userId))
+ {
+ return IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+ UserInfo* userInfo = getUserAccessObject().getUserInfo(userId);
+
+ payloadAccess.stdPayloadEnables1 =
+ userInfo->payloadAccess[chNum].stdPayloadEnables1;
+ payloadAccess.stdPayloadEnables2Reserved =
+ userInfo->payloadAccess[chNum].stdPayloadEnables2Reserved;
+ payloadAccess.oemPayloadEnables1 =
+ userInfo->payloadAccess[chNum].oemPayloadEnables1;
+ payloadAccess.oemPayloadEnables2Reserved =
+ userInfo->payloadAccess[chNum].oemPayloadEnables2Reserved;
+
+ return IPMI_CC_OK;
+}
+
} // namespace ipmi
diff --git a/user_channel/user_layer.hpp b/user_channel/user_layer.hpp
index 5f3567a..450d878 100644
--- a/user_channel/user_layer.hpp
+++ b/user_channel/user_layer.hpp
@@ -16,6 +16,7 @@
#pragma once
#include <ipmid/api.h>
+#include <bitset>
#include <string>
namespace ipmi
@@ -37,6 +38,7 @@ static constexpr uint8_t ipmiMaxUsers = 15;
static constexpr uint8_t ipmiMaxChannels = 16;
static constexpr uint8_t maxIpmi20PasswordSize = 20;
static constexpr uint8_t maxIpmi15PasswordSize = 16;
+static constexpr uint8_t payloadsPerByte = 8;
/** @struct PrivAccess
*
@@ -61,6 +63,19 @@ struct PrivAccess
#endif
} __attribute__((packed));
+/** @struct UserPayloadAccess
+ *
+ * Structure to denote payload access restrictions applicable for a
+ * given user and channel. (refer spec sec 24.6)
+ */
+struct PayloadAccess
+{
+ std::bitset<payloadsPerByte> stdPayloadEnables1;
+ std::bitset<payloadsPerByte> stdPayloadEnables2Reserved;
+ std::bitset<payloadsPerByte> oemPayloadEnables1;
+ std::bitset<payloadsPerByte> oemPayloadEnables2Reserved;
+};
+
/** @brief initializes user management
*
* @return IPMI_CC_OK for success, others for failure.
@@ -138,6 +153,16 @@ ipmi_ret_t ipmiUserSetUserName(const uint8_t userId, const char* userName);
ipmi_ret_t ipmiUserSetUserPassword(const uint8_t userId,
const char* userPassword);
+/** @brief set special user password (non-ipmi accounts)
+ *
+ * @param[in] userName - user name
+ * @param[in] userPassword - New Password
+ *
+ * @return IPMI_CC_OK for success, others for failure.
+ */
+ipmi_ret_t ipmiSetSpecialUserPassword(const std::string& userName,
+ const std::string& userPassword);
+
/** @brief get user name
*
* @param[in] userId - user id
@@ -200,4 +225,41 @@ ipmi_ret_t ipmiUserSetPrivilegeAccess(const uint8_t userId, const uint8_t chNum,
const PrivAccess& privAccess,
const bool& otherPrivUpdate);
+/** @brief check for user pam authentication. This is to determine, whether user
+ * is already locked out for failed login attempt
+ *
+ * @param[in] username - username
+ * @param[in] password - password
+ *
+ * @return status
+ */
+bool ipmiUserPamAuthenticate(std::string_view userName,
+ std::string_view userPassword);
+
+/** @brief sets user payload access data
+ *
+ * @param[in] chNum - channel number
+ * @param[in] operation - ENABLE / DISABLE operation
+ * @param[in] userId - user id
+ * @param[in] payloadAccess - payload access data
+ *
+ * @return IPMI_CC_OK for success, others for failure.
+ */
+ipmi_ret_t ipmiUserSetUserPayloadAccess(const uint8_t chNum,
+ const uint8_t operation,
+ const uint8_t userId,
+ const PayloadAccess& payloadAccess);
+
+/** @brief provides user payload access data
+ *
+ * @param[in] chNum - channel number
+ * @param[in] userId - user id
+ * @param[out] payloadAccess - payload access data
+ *
+ * @return IPMI_CC_OK for success, others for failure.
+ */
+ipmi_ret_t ipmiUserGetUserPayloadAccess(const uint8_t chNum,
+ const uint8_t userId,
+ PayloadAccess& payloadAccess);
+
} // namespace ipmi
diff --git a/user_channel/user_mgmt.cpp b/user_channel/user_mgmt.cpp
index f0cd7ad..102f990 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>
@@ -31,6 +32,7 @@
#include <regex>
#include <sdbusplus/bus/match.hpp>
#include <sdbusplus/server/object.hpp>
+#include <variant>
#include <xyz/openbmc_project/Common/error.hpp>
#include <xyz/openbmc_project/User/Common/error.hpp>
@@ -103,13 +105,10 @@ static std::array<std::string, (PRIVILEGE_OEM + 1)> ipmiPrivIndex = {
"priv-custom" // PRIVILEGE_OEM - 5
};
-namespace variant_ns = sdbusplus::message::variant_ns;
-
using namespace phosphor::logging;
using Json = nlohmann::json;
-using PrivAndGroupType =
- sdbusplus::message::variant<std::string, std::vector<std::string>>;
+using PrivAndGroupType = std::variant<std::string, std::vector<std::string>>;
using NoResource =
sdbusplus::xyz::openbmc_project::User::Common::Error::NoResource;
@@ -198,12 +197,13 @@ UserAccess& getUserAccessObject()
int getUserNameFromPath(const std::string& path, std::string& userName)
{
- static size_t pos = strlen(userObjBasePath) + 1;
- if (path.find(userObjBasePath) == std::string::npos)
+ constexpr size_t length = strlen(userObjBasePath);
+ if (((length + 1) >= path.size()) ||
+ path.compare(0, length, userObjBasePath))
{
return -EINVAL;
}
- userName.assign(path, pos, path.size());
+ userName.assign(path, length + 1, path.size());
return 0;
}
@@ -308,7 +308,7 @@ void userUpdatedSignalHandler(UserAccess& usrAccess,
{
static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection());
std::string signal = msg.get_member();
- std::string userName, update, priv, newUserName;
+ std::string userName, priv, newUserName;
std::vector<std::string> groups;
bool enabled = false;
UserUpdateEvent userEvent = UserUpdateEvent::reservedEvent;
@@ -376,17 +376,17 @@ void userUpdatedSignalHandler(UserAccess& usrAccess,
std::string member = prop.first;
if (member == userPrivProperty)
{
- priv = variant_ns::get<std::string>(prop.second);
+ priv = std::get<std::string>(prop.second);
userEvent = UserUpdateEvent::userPrivUpdated;
}
else if (member == userGrpProperty)
{
- groups = variant_ns::get<std::vector<std::string>>(prop.second);
+ groups = std::get<std::vector<std::string>>(prop.second);
userEvent = UserUpdateEvent::userGrpUpdated;
}
else if (member == userEnabledProperty)
{
- enabled = variant_ns::get<bool>(prop.second);
+ enabled = std::get<bool>(prop.second);
userEvent = UserUpdateEvent::userStateUpdated;
}
// Process based on event type.
@@ -472,43 +472,8 @@ UserAccess::UserAccess() : bus(ipmid_get_sd_bus_connection())
userMutex = std::make_unique<boost::interprocess::named_recursive_mutex>(
boost::interprocess::open_or_create, ipmiUserMutex);
- initUserDataFile();
+ cacheUserDataFile();
getSystemPrivAndGroups();
- sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
- // Register it for single object and single process either netipimd /
- // host-ipmid
- if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
- {
- log<level::DEBUG>("Registering signal handler");
- userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
- bus,
- sdbusplus::bus::match::rules::type::signal() +
- sdbusplus::bus::match::rules::interface(dBusObjManager) +
- sdbusplus::bus::match::rules::path(userMgrObjBasePath),
- [&](sdbusplus::message::message& msg) {
- userUpdatedSignalHandler(*this, msg);
- });
- userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
- bus,
- sdbusplus::bus::match::rules::type::signal() +
- sdbusplus::bus::match::rules::interface(userMgrInterface) +
- sdbusplus::bus::match::rules::path(userMgrObjBasePath),
- [&](sdbusplus::message::message& msg) {
- userUpdatedSignalHandler(*this, msg);
- });
- userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
- bus,
- sdbusplus::bus::match::rules::type::signal() +
- sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
- sdbusplus::bus::match::rules::interface(
- dBusPropertiesInterface) +
- sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
- sdbusplus::bus::match::rules::argN(0, usersInterface),
- [&](sdbusplus::message::message& msg) {
- userUpdatedSignalHandler(*this, msg);
- });
- signalHndlrObject = true;
- }
}
UserInfo* UserAccess::getUserInfo(const uint8_t userId)
@@ -683,33 +648,64 @@ static int pamFunctionConversation(int numMsg, const struct pam_message** msg,
* @return status
*/
-bool pamUpdatePasswd(const char* username, const char* password)
+int pamUpdatePasswd(const char* username, const char* password)
{
const struct pam_conv localConversation = {pamFunctionConversation,
const_cast<char*>(password)};
pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
- if (pam_start("passwd", username, &localConversation, &localAuthHandle) !=
- PAM_SUCCESS)
+ int retval =
+ pam_start("passwd", username, &localConversation, &localAuthHandle);
+
+ if (retval != PAM_SUCCESS)
{
+ return retval;
+ }
+
+ retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
+ if (retval != PAM_SUCCESS)
+ {
+ pam_end(localAuthHandle, retval);
+ return retval;
+ }
+
+ return pam_end(localAuthHandle, PAM_SUCCESS);
+}
+
+bool pamUserCheckAuthenticate(std::string_view username,
+ std::string_view password)
+{
+ const struct pam_conv localConversation = {
+ pamFunctionConversation, const_cast<char*>(password.data())};
+
+ pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
+
+ if (pam_start("dropbear", username.data(), &localConversation,
+ &localAuthHandle) != PAM_SUCCESS)
+ {
+ log<level::ERR>("User Authentication Failure");
return false;
}
- int retval = pam_chauthtok(localAuthHandle, PAM_SILENT);
+
+ int retval = pam_authenticate(localAuthHandle,
+ PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
if (retval != PAM_SUCCESS)
{
- if (retval == PAM_AUTHTOK_ERR)
- {
- log<level::DEBUG>("Authentication Failure");
- }
- else
- {
- log<level::DEBUG>("pam_chauthtok returned failure",
- entry("ERROR=%d", retval));
- }
+ log<level::DEBUG>("pam_authenticate returned failure",
+ entry("ERROR=%d", retval));
+
pam_end(localAuthHandle, retval);
return false;
}
+
+ if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
+ PAM_SUCCESS)
+ {
+ pam_end(localAuthHandle, PAM_SUCCESS);
+ return false;
+ }
+
if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
{
return false;
@@ -717,33 +713,51 @@ bool pamUpdatePasswd(const char* username, const char* password)
return true;
}
+ipmi_ret_t UserAccess::setSpecialUserPassword(const std::string& userName,
+ const std::string& userPassword)
+{
+ if (pamUpdatePasswd(userName.c_str(), userPassword.c_str()) != PAM_SUCCESS)
+ {
+ log<level::DEBUG>("Failed to update password");
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ return IPMI_CC_OK;
+}
+
ipmi_ret_t UserAccess::setUserPassword(const uint8_t userId,
const char* userPassword)
{
std::string userName;
- if (ipmiUserGetUserName(userId, userName) != IPMI_CC_OK)
+ if (ipmiUserGetUserName(userId, userName) != ipmi::ccSuccess)
{
log<level::DEBUG>("User Name not found",
- entry("USER-ID:%d", (uint8_t)userId));
- return IPMI_CC_PARM_OUT_OF_RANGE;
+ entry("USER-ID=%d", (uint8_t)userId));
+ return ipmi::ccParmOutOfRange;
}
std::string passwd;
passwd.assign(reinterpret_cast<const char*>(userPassword), 0,
maxIpmi20PasswordSize);
- if (!std::regex_match(passwd.c_str(),
- std::regex("[a-zA-z_0-9][a-zA-Z_0-9,?:`!\"]*")))
- {
- log<level::DEBUG>("Invalid password fields",
- entry("USER-ID:%d", (uint8_t)userId));
- return IPMI_CC_INVALID_FIELD_REQUEST;
- }
- if (!pamUpdatePasswd(userName.c_str(), passwd.c_str()))
+
+ int retval = pamUpdatePasswd(userName.c_str(), passwd.c_str());
+
+ switch (retval)
{
- log<level::DEBUG>("Failed to update password",
- entry("USER-ID:%d", (uint8_t)userId));
- return IPMI_CC_UNSPECIFIED_ERROR;
+ case PAM_SUCCESS:
+ {
+ return ipmi::ccSuccess;
+ }
+ case PAM_AUTHTOK_ERR:
+ {
+ log<level::DEBUG>("Bad authentication token");
+ return ipmi::ccInvalidFieldRequest;
+ }
+ default:
+ {
+ log<level::DEBUG>("Failed to update password",
+ entry("USER-ID=%d", (uint8_t)userId));
+ return ipmi::ccUnspecifiedError;
+ }
}
- return IPMI_CC_OK;
}
ipmi_ret_t UserAccess::setUserEnabledState(const uint8_t userId,
@@ -783,6 +797,60 @@ ipmi_ret_t UserAccess::setUserEnabledState(const uint8_t userId,
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,
@@ -878,6 +946,26 @@ ipmi_ret_t UserAccess::getUserName(const uint8_t userId, std::string& userName)
return IPMI_CC_OK;
}
+bool UserAccess::isIpmiInAvailableGroupList()
+{
+ if (std::find(availableGroups.begin(), availableGroups.end(),
+ ipmiGrpName) != availableGroups.end())
+ {
+ return true;
+ }
+ if (availableGroups.empty())
+ {
+ // available groups shouldn't be empty, re-query
+ getSystemPrivAndGroups();
+ if (std::find(availableGroups.begin(), availableGroups.end(),
+ ipmiGrpName) != availableGroups.end())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
ipmi_ret_t UserAccess::setUserName(const uint8_t userId,
const char* userNameInChar)
{
@@ -923,6 +1011,10 @@ ipmi_ret_t UserAccess::setUserName(const uint8_t userId,
{
try
{
+ if (!isIpmiInAvailableGroupList())
+ {
+ return IPMI_CC_UNSPECIFIED_ERROR;
+ }
// Create new user
auto method = bus.new_method_call(
getUserServiceName().c_str(), userMgrObjBasePath,
@@ -990,6 +1082,98 @@ static constexpr const char* jsonAccCallbk = "access_callback";
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()
{
@@ -1013,6 +1197,7 @@ void UserAccess::readUserData()
throw std::runtime_error(
"Corrupted IPMI user data file - invalid user count");
}
+
// user index 0 is reserved, starts with 1
for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
{
@@ -1036,6 +1221,48 @@ void UserAccess::readUserData()
userInfo[jsonLinkAuthEnabled].get<std::vector<bool>>();
std::vector<bool> accessCallback =
userInfo[jsonAccCallbk].get<std::vector<bool>>();
+
+ // Payload Enables Processing.
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
+ stdPayload = {};
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>
+ oemPayload = {};
+ try
+ {
+ const auto jsonPayloadEnabled = userInfo.at(payloadEnabledStr);
+ 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");
+ }
+ }
+ }
+ catch (Json::out_of_range& e)
+ {
+ // Key not found in 'userInfo'; possibly an old JSON file. Use
+ // default values for all payloads, and SOL payload default is true.
+ stdPayload[static_cast<uint8_t>(ipmi::PayloadType::SOL)].fill(true);
+ }
+
if (privilege.size() != ipmiMaxChannels ||
ipmiEnabled.size() != ipmiMaxChannels ||
linkAuthEnabled.size() != ipmiMaxChannels ||
@@ -1058,6 +1285,8 @@ void UserAccess::readUserData()
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 =
@@ -1078,15 +1307,6 @@ void UserAccess::writeUserData()
boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
userLock{*userMutex};
- static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
- std::ofstream oUsrData(tmpFile, std::ios::out | std::ios::binary);
- if (!oUsrData.good())
- {
- log<level::ERR>("Error in creating temporary IPMI user data file");
- throw std::ios_base::failure(
- "Error in creating temporary IPMI user data file");
- }
-
Json jsonUsersTbl = Json::array();
// user index 0 is reserved, starts with 1
for (size_t usrIndex = 1; usrIndex <= ipmiMaxUsers; ++usrIndex)
@@ -1099,6 +1319,12 @@ void UserAccess::writeUserData()
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] =
@@ -1118,12 +1344,35 @@ void UserAccess::writeUserData()
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);
}
- oUsrData << jsonUsersTbl;
- oUsrData.flush();
- oUsrData.close();
+ static std::string tmpFile{std::string(ipmiUserDataFile) + "_tmp"};
+ int fd = open(tmpFile.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_SYNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ {
+ log<level::ERR>("Error in creating temporary IPMI user data file");
+ throw std::ios_base::failure(
+ "Error in creating temporary IPMI user data file");
+ }
+ const auto& writeStr = jsonUsersTbl.dump();
+ if (write(fd, writeStr.c_str(), writeStr.size()) !=
+ static_cast<ssize_t>(writeStr.size()))
+ {
+ close(fd);
+ log<level::ERR>("Error in writing temporary IPMI user data file");
+ throw std::ios_base::failure(
+ "Error in writing temporary IPMI user data file");
+ }
+ close(fd);
if (std::rename(tmpFile.c_str(), ipmiUserDataFile) != 0)
{
@@ -1252,13 +1501,11 @@ void UserAccess::getSystemPrivAndGroups()
auto key = t.first;
if (key == allPrivProperty)
{
- availablePrivileges =
- variant_ns::get<std::vector<std::string>>(t.second);
+ availablePrivileges = std::get<std::vector<std::string>>(t.second);
}
else if (key == allGrpProperty)
{
- availableGroups =
- variant_ns::get<std::vector<std::string>>(t.second);
+ availableGroups = std::get<std::vector<std::string>>(t.second);
}
}
// TODO: Implement Supported Privilege & Groups verification logic
@@ -1285,15 +1532,15 @@ void UserAccess::getUserProperties(const DbusUserObjProperties& properties,
std::string key = t.first;
if (key == userPrivProperty)
{
- usrPriv = variant_ns::get<std::string>(t.second);
+ usrPriv = std::get<std::string>(t.second);
}
else if (key == userGrpProperty)
{
- usrGrps = variant_ns::get<std::vector<std::string>>(t.second);
+ usrGrps = std::get<std::vector<std::string>>(t.second);
}
else if (key == userEnabledProperty)
{
- usrEnabled = variant_ns::get<bool>(t.second);
+ usrEnabled = std::get<bool>(t.second);
}
}
return;
@@ -1312,7 +1559,7 @@ int UserAccess::getUserObjProperties(const DbusUserObjValue& userObjs,
return -EIO;
}
-void UserAccess::initUserDataFile()
+void UserAccess::cacheUserDataFile()
{
boost::interprocess::scoped_lock<boost::interprocess::named_recursive_mutex>
userLock{*userMutex};
@@ -1331,10 +1578,49 @@ void UserAccess::initUserDataFile()
{
usersTbl.user[userIndex].userPrivAccess[chIndex].privilege =
privNoAccess;
+ usersTbl.user[userIndex]
+ .payloadAccess[chIndex]
+ .stdPayloadEnables1[static_cast<uint8_t>(
+ ipmi::PayloadType::SOL)] = true;
}
}
writeUserData();
}
+ sigHndlrLock = boost::interprocess::file_lock(ipmiUserDataFile);
+ // Register it for single object and single process either netipimd /
+ // host-ipmid
+ if (userUpdatedSignal == nullptr && sigHndlrLock.try_lock())
+ {
+ log<level::DEBUG>("Registering signal handler");
+ userUpdatedSignal = std::make_unique<sdbusplus::bus::match_t>(
+ bus,
+ sdbusplus::bus::match::rules::type::signal() +
+ sdbusplus::bus::match::rules::interface(dBusObjManager) +
+ sdbusplus::bus::match::rules::path(userMgrObjBasePath),
+ [&](sdbusplus::message::message& msg) {
+ userUpdatedSignalHandler(*this, msg);
+ });
+ userMgrRenamedSignal = std::make_unique<sdbusplus::bus::match_t>(
+ bus,
+ sdbusplus::bus::match::rules::type::signal() +
+ sdbusplus::bus::match::rules::interface(userMgrInterface) +
+ sdbusplus::bus::match::rules::path(userMgrObjBasePath),
+ [&](sdbusplus::message::message& msg) {
+ userUpdatedSignalHandler(*this, msg);
+ });
+ userPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
+ bus,
+ sdbusplus::bus::match::rules::type::signal() +
+ sdbusplus::bus::match::rules::path_namespace(userObjBasePath) +
+ sdbusplus::bus::match::rules::interface(
+ dBusPropertiesInterface) +
+ sdbusplus::bus::match::rules::member(propertiesChangedSignal) +
+ sdbusplus::bus::match::rules::argN(0, usersInterface),
+ [&](sdbusplus::message::message& msg) {
+ userUpdatedSignalHandler(*this, msg);
+ });
+ signalHndlrObject = true;
+ }
std::map<DbusUserObjPath, DbusUserObjValue> managedObjs;
try
{
@@ -1351,7 +1637,7 @@ void UserAccess::initUserDataFile()
entry("PATH=%s", userMgrObjBasePath));
return;
}
-
+ bool updateRequired = false;
UsersTbl* userData = &usersTbl;
// user index 0 is reserved, starts with 1
for (size_t usrIdx = 1; usrIdx <= ipmiMaxUsers; ++usrIdx)
@@ -1361,7 +1647,6 @@ void UserAccess::initUserDataFile()
{
std::vector<std::string> usrGrps;
std::string usrPriv;
- bool usrEnabled;
std::string userName(
reinterpret_cast<char*>(userData->user[usrIdx].userName), 0,
@@ -1372,12 +1657,15 @@ void UserAccess::initUserDataFile()
auto usrObj = managedObjs.find(usersPath);
if (usrObj != managedObjs.end())
{
+ bool usrEnabled = false;
+
// User exist. Lets check and update other fileds
getUserObjProperties(usrObj->second, usrGrps, usrPriv,
usrEnabled);
if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) ==
usrGrps.end())
{
+ updateRequired = true;
// Group "ipmi" is removed so lets remove user in IPMI
deleteUserIndex(usrIdx);
}
@@ -1393,6 +1681,7 @@ void UserAccess::initUserDataFile()
.userPrivAccess[getUsrMgmtSyncIndex()]
.privilege != priv)
{
+ updateRequired = true;
for (size_t chIndex = 0; chIndex < ipmiMaxChannels;
++chIndex)
{
@@ -1403,6 +1692,7 @@ void UserAccess::initUserDataFile()
}
if (userData->user[usrIdx].userEnabled != usrEnabled)
{
+ updateRequired = true;
userData->user[usrIdx].userEnabled = usrEnabled;
}
}
@@ -1412,6 +1702,7 @@ void UserAccess::initUserDataFile()
}
else
{
+ updateRequired = true;
deleteUserIndex(usrIdx);
}
}
@@ -1423,7 +1714,7 @@ void UserAccess::initUserDataFile()
{
std::vector<std::string> usrGrps;
std::string usrPriv, userName;
- bool usrEnabled;
+ bool usrEnabled = false;
std::string usrObjPath = std::string(usrObj.first);
if (getUserNameFromPath(usrObj.first.str, userName) != 0)
{
@@ -1435,6 +1726,7 @@ void UserAccess::initUserDataFile()
if (std::find(usrGrps.begin(), usrGrps.end(), ipmiGrpName) !=
usrGrps.end())
{
+ updateRequired = true;
// CREATE NEW USER
if (true != addUserEntry(userName, usrPriv, usrEnabled))
{
@@ -1443,8 +1735,11 @@ void UserAccess::initUserDataFile()
}
}
- // All userData slots update done. Lets write the data
- writeUserData();
+ if (updateRequired)
+ {
+ // All userData slots update done. Lets write the data
+ writeUserData();
+ }
return;
}
diff --git a/user_channel/user_mgmt.hpp b/user_channel/user_mgmt.hpp
index 9ea9f6b..159b15c 100644
--- a/user_channel/user_mgmt.hpp
+++ b/user_channel/user_mgmt.hpp
@@ -16,19 +16,19 @@
#pragma once
#include "user_layer.hpp"
-#include <ipmid/api.h>
-
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/named_recursive_mutex.hpp>
#include <cstdint>
#include <ctime>
+#include <ipmid/api.hpp>
#include <sdbusplus/bus.hpp>
+#include <variant>
namespace ipmi
{
using DbusUserPropVariant =
- sdbusplus::message::variant<std::vector<std::string>, std::string, bool>;
+ std::variant<std::vector<std::string>, std::string, bool>;
using DbusUserObjPath = sdbusplus::message::object_path;
@@ -74,6 +74,7 @@ struct UserInfo
bool userEnabled;
bool userInSystem;
bool fixedUserName;
+ PayloadAccess payloadAccess[ipmiMaxChannels];
};
/** @struct UsersTbl
@@ -86,6 +87,16 @@ struct UsersTbl
UserInfo user[ipmiMaxUsers + 1];
};
+/** @brief PAM User Authentication check
+ *
+ * @param[in] username - username in string
+ * @param[in] password - password in string
+ *
+ * @return status
+ */
+bool pamUserCheckAuthenticate(std::string_view username,
+ std::string_view password);
+
class UserAccess;
UserAccess& getUserAccessObject();
@@ -155,6 +166,12 @@ class UserAccess
*/
bool isValidUserName(const char* userNameInChar);
+ /** @brief determines whether ipmi is in available groups list
+ *
+ * @return true if ipmi group is present, false otherwise
+ */
+ bool isIpmiInAvailableGroupList();
+
/** @brief provides user id of the user
*
* @param[in] userName - user name
@@ -217,6 +234,16 @@ class UserAccess
*/
ipmi_ret_t setUserPassword(const uint8_t userId, const char* userPassword);
+ /** @brief to set special user password
+ *
+ * @param[in] userName - user name
+ * @param[in] userPassword - new password of the user
+ *
+ * @return IPMI_CC_OK for success, others for failure.
+ */
+ ipmi_ret_t setSpecialUserPassword(const std::string& userName,
+ const std::string& userPassword);
+
/** @brief to set user privilege and access details
*
* @param[in] userId - user id
@@ -231,6 +258,56 @@ class UserAccess
const UserPrivAccess& privAccess,
const bool& otherPrivUpdates);
+ /** @brief to get user payload access details from userInfo entry.
+ *
+ * @param[in] userInfo - userInfo entry in usersTbl.
+ * @param[out] stdPayload - stdPayloadEnables1 in a 2D-array.
+ * @param[out] oemPayload - oemPayloadEnables1 in a 2D-array.
+ *
+ * @details Update the given 2D-arrays using the payload access details
+ * available in the given userInfo entry (from usersTbl).
+ * This 2D-array will be mapped to a JSON object (which will be written to
+ * a JSON file subsequently).
+ */
+ void readPayloadAccessFromUserInfo(
+ const UserInfo& userInfo,
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
+ stdPayload,
+ std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
+ oemPayload);
+
+ /** @brief to update user payload access details in userInfo entry.
+ *
+ * @param[in] stdPayload - stdPayloadEnables1 in a 2D-array.
+ * @param[in] oemPayload - oemPayloadEnables1 in a 2D-array.
+ * @param[out] userInfo - userInfo entry in usersTbl.
+ *
+ * @details Update user payload access details of a given userInfo
+ * entry (in usersTbl) with the information provided in given 2D-arrays.
+ * This 2D-array was created out of a JSON object (which was created by
+ * parsing a JSON file).
+ */
+ void updatePayloadAccessInUserInfo(
+ const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
+ stdPayload,
+ const std::array<std::array<bool, ipmiMaxChannels>, payloadsPerByte>&
+ oemPayload,
+ UserInfo& userInfo);
+
+ /** @brief to set user payload access details
+ *
+ * @param[in] chNum - channel number
+ * @param[in] operation - Enable / Disable
+ * @param[in] userId - user id
+ * @param[in] payloadAccess - payload access
+ *
+ * @return IPMI_CC_OK for success, others for failure.
+ */
+ ipmi_ret_t setUserPayloadAccess(const uint8_t chNum,
+ const uint8_t operation,
+ const uint8_t userId,
+ const PayloadAccess& payloadAccess);
+
/** @brief reads user management related data from configuration file
*
*/
@@ -321,8 +398,9 @@ class UserAccess
void getSystemPrivAndGroups();
/** @brief function to init user data from configuration & D-Bus objects
+ * and to register for signals
*
*/
- void initUserDataFile();
+ void cacheUserDataFile();
};
} // namespace ipmi
diff --git a/user_channel/usercommands.cpp b/user_channel/usercommands.cpp
index 489eeaf..3396d2d 100644
--- a/user_channel/usercommands.cpp
+++ b/user_channel/usercommands.cpp
@@ -37,6 +37,8 @@ static constexpr uint8_t setPassword = 0x02;
static constexpr uint8_t testPassword = 0x03;
static constexpr uint8_t passwordKeySize20 = 1;
static constexpr uint8_t passwordKeySize16 = 0;
+static constexpr uint8_t enableOperation = 0x00;
+static constexpr uint8_t disableOperation = 0x01;
/** @struct SetUserNameReq
*
@@ -130,7 +132,7 @@ ipmi::RspType<> ipmiSetUserAccess(ipmi::Context::ptr ctx, uint4_t channel,
{
uint8_t sessLimit = sessionLimit.value_or(0);
uint8_t chNum =
- convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx);
+ convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
if (reserved1 != 0 || reserved2 != 0 || sessLimit != 0 ||
(!isValidChannel(chNum)) ||
(!ipmiUserIsValidPrivilege(static_cast<uint8_t>(privilege))) ||
@@ -199,7 +201,7 @@ ipmi::RspType<uint6_t, // max channel users
uint6_t userId, uint2_t reserved2)
{
uint8_t chNum =
- convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx);
+ convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
if (reserved1 != 0 || reserved2 != 0 || (!isValidChannel(chNum)) ||
(EChannelSessSupported::none == getChannelSessionSupport(chNum)))
{
@@ -307,7 +309,7 @@ ipmi_ret_t ipmiGetUserName(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
if (ipmiUserGetUserName(req->userId, userName) != IPMI_CC_OK)
{ // Invalid User ID
log<level::DEBUG>("User Name not found",
- entry("USER-ID:%d", (uint8_t)req->userId));
+ entry("USER-ID=%d", (uint8_t)req->userId));
return IPMI_CC_PARM_OUT_OF_RANGE;
}
GetUserNameResp* resp = static_cast<GetUserNameResp*>(response);
@@ -366,7 +368,7 @@ ipmi_ret_t ipmiSetUserPassword(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
if (ipmiUserGetUserName(req->userId, userName) != IPMI_CC_OK)
{
log<level::DEBUG>("User Name not found",
- entry("USER-ID:%d", (uint8_t)req->userId));
+ entry("USER-ID=%d", (uint8_t)req->userId));
return IPMI_CC_PARM_OUT_OF_RANGE;
}
if (req->operation == setPassword)
@@ -391,7 +393,7 @@ ipmi_ret_t ipmiSetUserPassword(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
if (password != testPassword)
{
log<level::DEBUG>("Test password failed",
- entry("USER-ID:%d", (uint8_t)req->userId));
+ entry("USER-ID=%d", (uint8_t)req->userId));
return static_cast<ipmi_ret_t>(
IPMISetPasswordReturnCodes::ipmiCCPasswdFailMismatch);
}
@@ -450,7 +452,7 @@ ipmi::RspType<uint8_t, // channel number
{
uint8_t channel =
- convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx);
+ convertCurrentChannelNum(static_cast<uint8_t>(chNum), ctx->channel);
if (reserved1 || reserved2 || !isValidChannel(channel) ||
!isValidPrivLimit(static_cast<uint8_t>(privLevel)) ||
@@ -485,10 +487,192 @@ ipmi::RspType<uint8_t, // channel number
rmcp, rmcpp, reserved5, oemID, oemAuxillary);
}
+/** @brief implements the set user payload access command.
+ * @param ctx - IPMI context pointer (for channel)
+ * @param channel - channel number (4 bits)
+ * @param reserved1 - skip 4 bits
+ * @param userId - user id (6 bits)
+ * @param operation - access ENABLE /DISABLE. (2 bits)
+ * @param stdPayload0 - IPMI - reserved. (1 bit)
+ * @param stdPayload1 - SOL. (1 bit)
+ * @param stdPayload2 - (1 bit)
+ * @param stdPayload3 - (1 bit)
+ * @param stdPayload4 - (1 bit)
+ * @param stdPayload5 - (1 bit)
+ * @param stdPayload6 - (1 bit)
+ * @param stdPayload7 - (1 bit)
+ * @param stdPayloadEnables2Reserved - (8 bits)
+ * @param oemPayload0 - (1 bit)
+ * @param oemPayload1 - (1 bit)
+ * @param oemPayload2 - (1 bit)
+ * @param oemPayload3 - (1 bit)
+ * @param oemPayload4 - (1 bit)
+ * @param oemPayload5 - (1 bit)
+ * @param oemPayload6 - (1 bit)
+ * @param oemPayload7 - (1 bit)
+ * @param oemPayloadEnables2Reserved - (8 bits)
+ *
+ * @returns IPMI completion code
+ */
+ipmi::RspType<> ipmiSetUserPayloadAccess(
+ ipmi::Context::ptr ctx,
+
+ uint4_t channel, uint4_t reserved,
+
+ uint6_t userId, uint2_t operation,
+
+ bool stdPayload0ipmiReserved, bool stdPayload1SOL, bool stdPayload2,
+ bool stdPayload3, bool stdPayload4, bool stdPayload5, bool stdPayload6,
+ bool stdPayload7,
+
+ uint8_t stdPayloadEnables2Reserved,
+
+ bool oemPayload0, bool oemPayload1, bool oemPayload2, bool oemPayload3,
+ bool oemPayload4, bool oemPayload5, bool oemPayload6, bool oemPayload7,
+
+ uint8_t oemPayloadEnables2Reserved)
+{
+ // Validate the reserved args. Only SOL payload is supported as on date.
+ if (reserved || stdPayload0ipmiReserved || stdPayload2 || stdPayload3 ||
+ stdPayload4 || stdPayload5 || stdPayload6 || stdPayload7 ||
+ oemPayload0 || oemPayload1 || oemPayload2 || oemPayload3 ||
+ oemPayload4 || oemPayload5 || oemPayload6 || oemPayload7 ||
+ stdPayloadEnables2Reserved || oemPayloadEnables2Reserved)
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+
+ auto chNum =
+ convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
+ if ((operation != enableOperation && operation != disableOperation) ||
+ (!isValidChannel(chNum)) ||
+ (getChannelSessionSupport(chNum) == EChannelSessSupported::none))
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+
+ if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
+ {
+ return ipmi::responseParmOutOfRange();
+ }
+
+ PayloadAccess payloadAccess = {0};
+ payloadAccess.stdPayloadEnables1[1] = stdPayload1SOL;
+
+ return ipmi::response(ipmiUserSetUserPayloadAccess(
+ chNum, static_cast<uint8_t>(operation), static_cast<uint8_t>(userId),
+ payloadAccess));
+}
+
+/** @brief implements the get user payload access command
+ * This command returns information about user payload enable settings
+ * that were set using the 'Set User Payload Access' Command.
+ *
+ * @param ctx - IPMI context pointer (for channel)
+ * @param channel - channel number
+ * @param reserved1 - skip 4 bits
+ * @param userId - user id
+ * @param reserved2 - skip 2 bits
+ *
+ * @returns IPMI completion code plus response data
+ * - stdPayload0ipmiReserved - IPMI payload (reserved).
+ * - stdPayload1SOL - SOL payload
+ * - stdPayload2
+ * - stdPayload3
+ * - stdPayload4
+ * - stdPayload5
+ * - stdPayload6
+ * - stdPayload7
+
+ * - stdPayloadEnables2Reserved - Reserved.
+
+ * - oemPayload0
+ * - oemPayload1
+ * - oemPayload2
+ * - oemPayload3
+ * - oemPayload4
+ * - oemPayload5
+ * - oemPayload6
+ * - oemPayload7
+
+ * - oemPayloadEnables2Reserved - Reserved
+ */
+ipmi::RspType<bool, // stdPayload0ipmiReserved
+ bool, // stdPayload1SOL
+ bool, // stdPayload2
+ bool, // stdPayload3
+ bool, // stdPayload4
+ bool, // stdPayload5
+ bool, // stdPayload6
+ bool, // stdPayload7
+
+ uint8_t, // stdPayloadEnables2Reserved
+
+ bool, // oemPayload0
+ bool, // oemPayload1
+ bool, // oemPayload2
+ bool, // oemPayload3
+ bool, // oemPayload4
+ bool, // oemPayload5
+ bool, // oemPayload6
+ bool, // oemPayload7
+
+ uint8_t // oemPayloadEnables2Reserved
+ >
+ ipmiGetUserPayloadAccess(ipmi::Context::ptr ctx,
+
+ uint4_t channel, uint4_t reserved1,
+
+ uint6_t userId, uint2_t reserved2)
+{
+ uint8_t chNum =
+ convertCurrentChannelNum(static_cast<uint8_t>(channel), ctx->channel);
+ if (reserved1 != 0 || reserved2 != 0 || (!isValidChannel(chNum)) ||
+ (getChannelSessionSupport(chNum) == EChannelSessSupported::none))
+ {
+ return ipmi::responseInvalidFieldRequest();
+ }
+ if (!ipmiUserIsValidUserId(static_cast<uint8_t>(userId)))
+ {
+ return ipmi::responseParmOutOfRange();
+ }
+
+ ipmi::Cc retStatus;
+ PayloadAccess payloadAccess = {};
+ retStatus = ipmiUserGetUserPayloadAccess(
+ chNum, static_cast<uint8_t>(userId), payloadAccess);
+ if (retStatus != IPMI_CC_OK)
+ {
+ return ipmi::response(retStatus);
+ }
+ constexpr uint8_t res8bits = 0;
+ return ipmi::responseSuccess(payloadAccess.stdPayloadEnables1.test(0),
+ payloadAccess.stdPayloadEnables1.test(1),
+ payloadAccess.stdPayloadEnables1.test(2),
+ payloadAccess.stdPayloadEnables1.test(3),
+ payloadAccess.stdPayloadEnables1.test(4),
+ payloadAccess.stdPayloadEnables1.test(5),
+ payloadAccess.stdPayloadEnables1.test(6),
+ payloadAccess.stdPayloadEnables1.test(7),
+
+ res8bits,
+
+ payloadAccess.oemPayloadEnables1.test(0),
+ payloadAccess.oemPayloadEnables1.test(1),
+ payloadAccess.oemPayloadEnables1.test(2),
+ payloadAccess.oemPayloadEnables1.test(3),
+ payloadAccess.oemPayloadEnables1.test(4),
+ payloadAccess.oemPayloadEnables1.test(5),
+ payloadAccess.oemPayloadEnables1.test(6),
+ payloadAccess.oemPayloadEnables1.test(7),
+
+ res8bits);
+}
+
void registerUserIpmiFunctions() __attribute__((constructor));
void registerUserIpmiFunctions()
{
- ipmiUserInit();
+ post_work([]() { ipmiUserInit(); });
ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
ipmi::app::cmdSetUserAccessCommand,
ipmi::Privilege::Admin, ipmiSetUserAccess);
@@ -510,6 +694,15 @@ void registerUserIpmiFunctions()
ipmi::app::cmdGetChannelAuthCapabilities,
ipmi::Privilege::Callback,
ipmiGetChannelAuthenticationCapabilities);
+
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
+ ipmi::app::cmdSetUserPayloadAccess,
+ ipmi::Privilege::Admin, ipmiSetUserPayloadAccess);
+
+ ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp,
+ ipmi::app::cmdGetUserPayloadAccess,
+ ipmi::Privilege::Operator, ipmiGetUserPayloadAccess);
+
return;
}
} // namespace ipmi
OpenPOWER on IntegriCloud