From 02650d53027326ed9b24a58b23596a74e5456654 Mon Sep 17 00:00:00 2001 From: Ayushi Smriti Date: Wed, 15 May 2019 11:59:09 +0000 Subject: User-mgmt: Add IPMI user pam authenticate check API PAM user authentication check must be performed, before any RMCP+ session establishment, as this will be able to check whether user is already locked out, due to failed attempt. This patch introduces the pam user check API, which will be used by netipmid daemon. Tested: Verified the API call check and making sure it works. Real testing is performed by including the same in phosphor-ipmi-net for RMCP+ session establishment both for user locked for failed attempt and normal case. Commands used- Created new user using ipmitool ipmitool user set name 2 testuser ipmitool user enable 2 ipmitool user set password 2 pas1tes2 ipmitool user priv 2 4 3 ipmitool user list 3 //New user entry can be seen listed ipmitool channel getaccess 3 2 //For getting channel access ipmitool channel setaccess 3 2 ipmi=on priviledge=4 Normal Case: ipmitool -I lanplus -U testuser -P pas1tes2 -H raw 6 1 //Command 23 00 00 00 02 bf 57 01 00 7b 00 00 00 00 00 //Response Negative Case: busctl set-property xyz.openbmc_project.User.Manager /xyz/openbmc_project/user xyz.openbmc_project.User.AccountPolicy MaxLoginAttemptBeforeLockout q 3 Tried 3 failed login attempts from webpage, and then tried to establish IPMI RMCP+ as expected, session establishment failed. wait for the timeout or unlock the user using- busctl set-property xyz.openbmc_project.User.Manager /xyz/openbmc_project/user/sayushi xyz.openbmc_project.User.Attributes UserLockedForFailedAttempt b false busctl get-property xyz.openbmc_project.User.Manager /xyz/openbmc_project/user/sayushi xyz.openbmc_project.User.Attributes UserLockedForFailedAttempt b false //Command b false //Response After this RMCP+ session will be established as usual. Change-Id: I5ee2dc0848944a12f682f0775930091d32508bde Signed-off-by: Ayushi Smriti --- user_channel/user_layer.cpp | 6 ++++++ user_channel/user_layer.hpp | 11 +++++++++++ user_channel/user_mgmt.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ user_channel/user_mgmt.hpp | 10 ++++++++++ 4 files changed, 68 insertions(+) diff --git a/user_channel/user_layer.cpp b/user_channel/user_layer.cpp index adfc656..00f6a7f 100644 --- a/user_channel/user_layer.cpp +++ b/user_channel/user_layer.cpp @@ -170,4 +170,10 @@ 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); +} + } // namespace ipmi diff --git a/user_channel/user_layer.hpp b/user_channel/user_layer.hpp index 57f5317..7926c59 100644 --- a/user_channel/user_layer.hpp +++ b/user_channel/user_layer.hpp @@ -210,4 +210,15 @@ 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); + } // namespace ipmi diff --git a/user_channel/user_mgmt.cpp b/user_channel/user_mgmt.cpp index a1d2443..9b40f6c 100644 --- a/user_channel/user_mgmt.cpp +++ b/user_channel/user_mgmt.cpp @@ -715,6 +715,47 @@ bool pamUpdatePasswd(const char* username, const char* password) return true; } +bool pamUserCheckAuthenticate(std::string_view username, + std::string_view password) +{ + const struct pam_conv localConversation = { + pamFunctionConversation, const_cast(password.data())}; + + pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start + + if (pam_start("dropbear", username.data(), &localConversation, + &localAuthHandle) != PAM_SUCCESS) + { + log("User Authentication Failure"); + return false; + } + + int retval = pam_authenticate(localAuthHandle, + PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); + + if (retval != PAM_SUCCESS) + { + log("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; + } + return true; +} + ipmi_ret_t UserAccess::setSpecialUserPassword(const std::string& userName, const std::string& userPassword) { diff --git a/user_channel/user_mgmt.hpp b/user_channel/user_mgmt.hpp index 8061482..8b650c8 100644 --- a/user_channel/user_mgmt.hpp +++ b/user_channel/user_mgmt.hpp @@ -87,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(); -- cgit v1.2.1