/* // 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 "users.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace phosphor { namespace user { inline constexpr size_t ipmiMaxUsers = 15; inline constexpr size_t maxSystemUsers = 30; inline constexpr uint8_t minPasswdLength = 8; inline constexpr size_t maxSystemGroupNameLength = 32; inline constexpr size_t maxSystemGroupCount = 64; using UserMgrIface = sdbusplus::xyz::openbmc_project::User::server::Manager; using UserSSHLists = std::pair, std::vector>; using AccountPolicyIface = sdbusplus::xyz::openbmc_project::User::server::AccountPolicy; using Ifaces = sdbusplus::server::object_t; using Privilege = std::string; using GroupList = std::vector; using UserEnabled = bool; using PropertyName = std::string; using ServiceEnabled = bool; using UserInfo = std::variant; using UserInfoMap = std::map; using DbusUserObjPath = sdbusplus::message::object_path; using DbusUserPropVariant = std::variant; using DbusUserObjProperties = std::map; using Interface = std::string; using DbusUserObjValue = std::map; using DbusUserObj = std::map; std::string getCSVFromVector(std::span vec); bool removeStringFromCSV(std::string& csvStr, const std::string& delStr); template std::vector executeCmd(const char* path, ArgTypes&&... tArgs) { std::vector stdOutput; boost::process::ipstream stdOutStream; boost::process::child execProg(path, const_cast(tArgs)..., boost::process::std_out > stdOutStream); std::string stdOutLine; while (stdOutStream && std::getline(stdOutStream, stdOutLine) && !stdOutLine.empty()) { stdOutput.emplace_back(stdOutLine); } execProg.wait(); int retCode = execProg.exit_code(); if (retCode) { lg2::error("Command {PATH} execution failed, return code {RETCODE}", "PATH", path, "RETCODE", retCode); phosphor::logging::elog< sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>(); } return stdOutput; } /** @class UserMgr * @brief Responsible for managing user accounts over the D-Bus interface. */ class UserMgr : public Ifaces { public: UserMgr() = delete; ~UserMgr() = default; UserMgr(const UserMgr&) = delete; UserMgr& operator=(const UserMgr&) = delete; UserMgr(UserMgr&&) = delete; UserMgr& operator=(UserMgr&&) = delete; /** @brief Constructs UserMgr object. * * @param[in] bus - sdbusplus handler * @param[in] path - D-Bus path */ UserMgr(sdbusplus::bus_t& bus, const char* path); /** @brief create user method. * This method creates a new user as requested * * @param[in] userName - Name of the user which has to be created * @param[in] groupNames - Group names list, to which user has to be added. * @param[in] priv - Privilege of the user. * @param[in] enabled - State of the user enabled / disabled. */ void createUser(std::string userName, std::vector groupNames, std::string priv, bool enabled) override; /** @brief rename user method. * This method renames the user as requested * * @param[in] userName - current name of the user * @param[in] newUserName - new user name to which it has to be renamed. */ void renameUser(std::string userName, std::string newUserName) override; /** @brief delete user method. * This method deletes the user as requested * * @param[in] userName - Name of the user which has to be deleted */ void deleteUser(std::string userName); /** @brief Update user groups & privilege. * This method updates user groups & privilege * * @param[in] userName - user name, for which update is requested * @param[in] groupName - Group to be updated.. * @param[in] priv - Privilege to be updated. */ void updateGroupsAndPriv(const std::string& userName, std::vector groups, const std::string& priv); /** @brief Update user enabled state. * This method enables / disables user * * @param[in] userName - user name, for which update is requested * @param[in] enabled - enable / disable the user */ void userEnable(const std::string& userName, bool enabled); /** @brief get user enabled state * method to get user enabled state. * * @param[in] userName - name of the user * @return - user enabled status (true/false) */ virtual bool isUserEnabled(const std::string& userName); /** @brief update minimum password length requirement * * @param[in] val - minimum password length * @return - minimum password length */ uint8_t minPasswordLength(uint8_t val) override; /** @brief update old password history count * * @param[in] val - number of times old passwords has to be avoided * @return - number of times old password has to be avoided */ uint8_t rememberOldPasswordTimes(uint8_t val) override; /** @brief update maximum number of failed login attempt before locked * out. * * @param[in] val - number of allowed attempt * @return - number of allowed attempt */ uint16_t maxLoginAttemptBeforeLockout(uint16_t val) override; /** @brief update timeout to unlock the account * * @param[in] val - value in seconds * @return - value in seconds */ uint32_t accountUnlockTimeout(uint32_t val) override; /** @brief parses the faillock output for locked user status * * @param[in] - output from faillock for the user * @return - true / false indicating user locked / un-locked **/ bool parseFaillockForLockout(const std::vector& faillockOutput); /** @brief lists user locked state for failed attempt * * @param[in] - user name * @return - true / false indicating user locked / un-locked **/ virtual bool userLockedForFailedAttempt(const std::string& userName); /** @brief lists user locked state for failed attempt * * @param[in]: user name * @param[in]: value - false -unlock user account, true - no action taken **/ bool userLockedForFailedAttempt(const std::string& userName, const bool& value); /** @brief shows if the user's password is expired * * @param[in]: user name * @return - true / false indicating user password expired **/ virtual bool userPasswordExpired(const std::string& userName); /** @brief returns user info * Checks if user is local user, then returns map of properties of user. * like user privilege, list of user groups, user enabled state and user * locked state. If its not local user, then it checks if its a ldap user, * then it gets the privilege mapping of the LDAP group. * * @param[in] - user name * @return - map of user properties **/ UserInfoMap getUserInfo(std::string userName) override; /** @brief get IPMI user count * method to get IPMI user count * * @return - returns user count */ virtual size_t getIpmiUsersCount(void); void createGroup(std::string groupName) override; void deleteGroup(std::string groupName) override; static std::vector readAllGroupsOnSystem(); protected: /** @brief get pam argument value * method to get argument value from pam configuration * * @param[in] moduleName - name of the module from where arg has to be read * @param[in] argName - argument name * @param[out] argValue - argument value * * @return 0 - success state of the function */ int getPamModuleArgValue(const std::string& moduleName, const std::string& argName, std::string& argValue); /** @brief get pam argument value * method to get argument value from pam configuration * * @param[in] confFile - path of the module config file from where arg has * to be read * @param[in] argName - argument name * @param[out] argValue - argument value * * @return 0 - success state of the function */ int getPamModuleConfValue(const std::string& confFile, const std::string& argName, std::string& argValue); /** @brief set pam argument value * method to set argument value in pam configuration * * @param[in] moduleName - name of the module in which argument value has * to be set * @param[in] argName - argument name * @param[out] argValue - argument value * * @return 0 - success state of the function */ int setPamModuleArgValue(const std::string& moduleName, const std::string& argName, const std::string& argValue); /** @brief set pam argument value * method to set argument value in pam configuration * * @param[in] confFile - path of the module config file in which argument * value has to be set * @param[in] argName - argument name * @param[out] argValue - argument value * * @return 0 - success state of the function */ int setPamModuleConfValue(const std::string& confFile, const std::string& argName, const std::string& argValue); /** @brief check for user presence * method to check for user existence * * @param[in] userName - name of the user * @return -true if user exists and false if not. */ bool isUserExist(const std::string& userName); size_t getNonIpmiUsersCount(); /** @brief check user exists * method to check whether user exist, and throw if not. * * @param[in] userName - name of the user */ void throwForUserDoesNotExist(const std::string& userName); /** @brief check user does not exist * method to check whether does not exist, and throw if exists. * * @param[in] userName - name of the user */ void throwForUserExists(const std::string& userName); /** @brief check user name constraints * method to check user name constraints and throw if failed. * * @param[in] userName - name of the user * @param[in] groupNames - user groups */ void throwForUserNameConstraints(const std::string& userName, const std::vector& groupNames); /** @brief check group user count * method to check max group user count, and throw if limit reached * * @param[in] groupNames - group name */ void throwForMaxGrpUserCount(const std::vector& groupNames); virtual void executeUserAdd(const char* userName, const char* groups, bool sshRequested, bool enabled); virtual void executeUserDelete(const char* userName); /** @brief clear user's failure records * method to clear user fail records and throw if failed. * * @param[in] userName - name of the user */ virtual void executeUserClearFailRecords(const char* userName); virtual void executeUserRename(const char* userName, const char* newUserName); virtual void executeUserModify(const char* userName, const char* newGroups, bool sshRequested); virtual void executeUserModifyUserEnable(const char* userName, bool enabled); virtual void executeGroupCreation(const char* groupName); virtual void executeGroupDeletion(const char* groupName); virtual std::vector getFailedAttempt(const char* userName); /** @brief check for valid privielge * method to check valid privilege, and throw if invalid * * @param[in] priv - privilege of the user */ void throwForInvalidPrivilege(const std::string& priv); /** @brief check for valid groups * method to check valid groups, and throw if invalid * * @param[in] groupNames - user groups */ void throwForInvalidGroups(const std::vector& groupName); void initializeAccountPolicy(); /** @brief checks if the group creation meets all constraints * @param groupName - group to check */ void checkCreateGroupConstraints(const std::string& groupName); /** @brief checks if the group deletion meets all constraints * @param groupName - group to check */ void checkDeleteGroupConstraints(const std::string& groupName); /** @brief checks if the group name is legal and whether it's allowed to * change. The daemon doesn't allow arbitrary group to be created * @param groupName - group to check */ void checkAndThrowForDisallowedGroupCreation(const std::string& groupName); private: /** @brief sdbusplus handler */ sdbusplus::bus_t& bus; /** @brief object path */ const std::string path; /** @brief privilege manager container */ const std::vector privMgr = {"priv-admin", "priv-operator", "priv-user"}; /** @brief groups manager container */ std::vector groupsMgr; /** @brief map container to hold users object */ using UserName = std::string; std::unordered_map> usersList; /** @brief get users in group * method to get group user list * * @param[in] groupName - group name * * @return userList - list of users in the group. */ std::vector getUsersInGroup(const std::string& groupName); /** @brief get user & SSH users list * method to get the users and ssh users list. * *@return - vector of User & SSH user lists */ UserSSHLists getUserAndSshGrpList(void); /** @brief initialize the user manager objects * method to initialize the user manager objects accordingly * */ void initUserObjects(void); /** @brief get service name * method to get dbus service name * * @param[in] path - object path * @param[in] intf - interface * @return - service name */ std::string getServiceName(std::string&& path, std::string&& intf); /** @brief get primary group ID of specified user * * @param[in] - userName * @return - primary group ID */ virtual gid_t getPrimaryGroup(const std::string& userName) const; /** @brief check whether if the user is a member of the group * * @param[in] - userName * @param[in] - ID of the user's primary group * @param[in] - groupName * @return - true if the user is a member of the group */ virtual bool isGroupMember(const std::string& userName, gid_t primaryGid, const std::string& groupName) const; protected: /** @brief get privilege mapper object * method to get dbus privilege mapper object * * @return - map of user object */ virtual DbusUserObj getPrivilegeMapperObject(void); friend class TestUserMgr; std::string faillockConfigFile; std::string pwHistoryConfigFile; std::string pwQualityConfigFile; }; } // namespace user } // namespace phosphor