summaryrefslogtreecommitdiffstats
path: root/user_channel/user_mgmt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'user_channel/user_mgmt.cpp')
-rw-r--r--user_channel/user_mgmt.cpp495
1 files changed, 395 insertions, 100 deletions
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;
}
OpenPOWER on IntegriCloud