Update pam_pwhistory to use pwhistory.conf
With libpam 1.5.3, pam_pwhistory added support to get configuration
options from pwhistory.conf similar to faillock and pwquality.
This updates pam_pwhistory to use pwhistory.conf for the remember
setting.
pwhistory remember was the last setting directly using the
common-password file, so this also removes the two functions to get and
set PAM module arg values which resolves #16.
Tested:
Confirmed that getting and setting the RememberOldPasswordTimes D-Bus
property gets and sets the remember value in pwhistory.conf.
Change-Id: If8f90720c120c5c49e2b8b4a840a427d46ffc7d9
Signed-off-by: Jason M. Bills <jason.m.bills@intel.com>
diff --git a/test/user_mgr_test.cpp b/test/user_mgr_test.cpp
index 0a19918..9c825a4 100644
--- a/test/user_mgr_test.cpp
+++ b/test/user_mgr_test.cpp
@@ -203,43 +203,14 @@
inline constexpr const char* objectRootInTest = "/xyz/openbmc_project/user";
// Fake configs; referenced configs on real BMC
-inline constexpr const char* rawConfig = R"(
-#
-# /etc/pam.d/common-password - password-related modules common to all services
-#
-# This file is included from other service-specific PAM config files,
-# and should contain a list of modules that define the services to be
-# used to change user passwords. The default is pam_unix.
-
-# Explanation of pam_unix options:
-#
-# The "sha512" option enables salted SHA512 passwords. Without this option,
-# the default is Unix crypt. Prior releases used the option "md5".
-#
-# The "obscure" option replaces the old `OBSCURE_CHECKS_ENAB' option in
-# login.defs.
-#
-# See the pam_unix manpage for other options.
-
-# here are the per-package modules (the "Primary" block)
-password [success=ok default=die] pam_faillock.so authsucc
-password [success=ok default=die] pam_pwquality.so debug
-password [success=ok default=die] pam_ipmicheck.so spec_grp_name=ipmi use_authtok
-password [success=ok ignore=ignore default=die] pam_pwhistory.so debug enforce_for_root remember=0 use_authtok
-password [success=ok default=die] pam_unix.so sha512 use_authtok
-password [success=1 default=die] pam_ipmisave.so spec_grp_name=ipmi spec_pass_file=/etc/ipmi_pass key_file=/etc/key_file
-# here's the fallback if no module succeeds
-password requisite pam_deny.so
-# prime the stack with a positive return value if there isn't one already;
-# this avoids us returning an error just because nothing sets a success code
-# since the modules above will each just jump around
-password required pam_permit.so
-# and here are more per-package modules (the "Additional" block)
-)";
inline constexpr const char* rawFailLockConfig = R"(
deny=2
unlock_time=3
)";
+inline constexpr const char* rawPWHistoryConfig = R"(
+enforce_for_root
+remember=0
+)";
inline constexpr const char* rawPWQualityConfig = R"(
enforce_for_root
minlen=8
@@ -273,20 +244,21 @@
public:
UserMgrInTest() : UserMgr(busInTest, objectRootInTest)
{
- tempPamConfigFile = "/tmp/test-data-XXXXXX";
- mktemp(tempPamConfigFile.data());
- EXPECT_NO_THROW(dumpStringToFile(rawConfig, tempPamConfigFile));
tempFaillockConfigFile = "/tmp/test-data-XXXXXX";
mktemp(tempFaillockConfigFile.data());
EXPECT_NO_THROW(
dumpStringToFile(rawFailLockConfig, tempFaillockConfigFile));
+ tempPWHistoryConfigFile = "/tmp/test-data-XXXXXX";
+ mktemp(tempPWHistoryConfigFile.data());
+ EXPECT_NO_THROW(
+ dumpStringToFile(rawPWHistoryConfig, tempPWHistoryConfigFile));
tempPWQualityConfigFile = "/tmp/test-data-XXXXXX";
mktemp(tempPWQualityConfigFile.data());
EXPECT_NO_THROW(
dumpStringToFile(rawPWQualityConfig, tempPWQualityConfigFile));
// Set config files to test files
- pamPasswdConfigFile = tempPamConfigFile;
faillockConfigFile = tempFaillockConfigFile;
+ pwHistoryConfigFile = tempPWHistoryConfigFile;
pwQualityConfigFile = tempPWQualityConfigFile;
ON_CALL(*this, executeUserAdd).WillByDefault(testing::Return());
@@ -319,8 +291,8 @@
~UserMgrInTest() override
{
- EXPECT_NO_THROW(removeFile(tempPamConfigFile));
EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
+ EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
EXPECT_NO_THROW(removeFile(tempPWQualityConfigFile));
}
@@ -351,21 +323,13 @@
protected:
static sdbusplus::bus_t busInTest;
- std::string tempPamConfigFile;
std::string tempFaillockConfigFile;
+ std::string tempPWHistoryConfigFile;
std::string tempPWQualityConfigFile;
};
sdbusplus::bus_t UserMgrInTest::busInTest = sdbusplus::bus::new_default();
-TEST_F(UserMgrInTest, GetPamModuleArgValueOnSuccess)
-{
- std::string remember;
- EXPECT_EQ(getPamModuleArgValue("pam_pwhistory.so", "remember", remember),
- 0);
- EXPECT_EQ(remember, "0");
-}
-
TEST_F(UserMgrInTest, GetPamModuleConfValueOnSuccess)
{
std::string minlen;
@@ -375,15 +339,11 @@
std::string deny;
EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
EXPECT_EQ(deny, "2");
-}
-
-TEST_F(UserMgrInTest, SetPamModuleArgValueOnSuccess)
-{
- EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), 0);
std::string remember;
- EXPECT_EQ(getPamModuleArgValue("pam_pwhistory.so", "remember", remember),
- 0);
- EXPECT_EQ(remember, "1");
+ EXPECT_EQ(
+ getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
+ 0);
+ EXPECT_EQ(remember, "0");
}
TEST_F(UserMgrInTest, SetPamModuleConfValueOnSuccess)
@@ -399,14 +359,14 @@
std::string deny;
EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), 0);
EXPECT_EQ(deny, "3");
-}
-TEST_F(UserMgrInTest, SetPamModuleArgValueTempFileOnSuccess)
-{
- EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), 0);
-
- std::string tmpFile = tempPamConfigFile + "_tmp";
- EXPECT_FALSE(std::filesystem::exists(tmpFile));
+ EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
+ 0);
+ std::string remember;
+ EXPECT_EQ(
+ getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
+ 0);
+ EXPECT_EQ(remember, "1");
}
TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnSuccess)
@@ -421,18 +381,12 @@
tmpFile = tempFaillockConfigFile + "_tmp";
EXPECT_FALSE(std::filesystem::exists(tmpFile));
-}
-TEST_F(UserMgrInTest, GetPamModuleArgValueOnFailure)
-{
- EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile));
- std::string remember;
- EXPECT_EQ(getPamModuleArgValue("pam_pwhistory.so", "remember", remember),
- -1);
+ EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
+ 0);
- EXPECT_NO_THROW(removeFile(tempPamConfigFile));
- EXPECT_EQ(getPamModuleArgValue("pam_pwhistory.so", "remember", remember),
- -1);
+ tmpFile = tempPWHistoryConfigFile + "_tmp";
+ EXPECT_FALSE(std::filesystem::exists(tmpFile));
}
TEST_F(UserMgrInTest, GetPamModuleConfValueOnFailure)
@@ -452,15 +406,17 @@
EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
EXPECT_EQ(getPamModuleConfValue(tempFaillockConfigFile, "deny", deny), -1);
-}
-TEST_F(UserMgrInTest, SetPamModuleArgValueOnFailure)
-{
- EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile));
- EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), -1);
+ EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
+ std::string remember;
+ EXPECT_EQ(
+ getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
+ -1);
- EXPECT_NO_THROW(removeFile(tempPamConfigFile));
- EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), -1);
+ EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
+ EXPECT_EQ(
+ getPamModuleConfValue(tempPWHistoryConfigFile, "remember", remember),
+ -1);
}
TEST_F(UserMgrInTest, SetPamModuleConfValueOnFailure)
@@ -478,20 +434,14 @@
EXPECT_NO_THROW(removeFile(tempFaillockConfigFile));
EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
-}
-TEST_F(UserMgrInTest, SetPamModuleArgValueTempFileOnFailure)
-{
- EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile));
- EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), -1);
+ EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
+ EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
+ -1);
- std::string tmpFile = tempPamConfigFile + "_tmp";
- EXPECT_FALSE(std::filesystem::exists(tmpFile));
-
- EXPECT_NO_THROW(removeFile(tempPamConfigFile));
- EXPECT_EQ(setPamModuleArgValue("pam_pwhistory.so", "remember", "1"), -1);
-
- EXPECT_FALSE(std::filesystem::exists(tmpFile));
+ EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
+ EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
+ -1);
}
TEST_F(UserMgrInTest, SetPamModuleConfValueTempFileOnFailure)
@@ -519,6 +469,19 @@
EXPECT_EQ(setPamModuleConfValue(tempFaillockConfigFile, "deny", "3"), -1);
EXPECT_FALSE(std::filesystem::exists(tmpFile));
+
+ EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
+ EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
+ -1);
+
+ tmpFile = tempPWHistoryConfigFile + "_tmp";
+ EXPECT_FALSE(std::filesystem::exists(tmpFile));
+
+ EXPECT_NO_THROW(removeFile(tempPWHistoryConfigFile));
+ EXPECT_EQ(setPamModuleConfValue(tempPWHistoryConfigFile, "remember", "1"),
+ -1);
+
+ EXPECT_FALSE(std::filesystem::exists(tmpFile));
}
TEST_F(UserMgrInTest, IsUserExistEmptyInputThrowsError)
@@ -814,7 +777,7 @@
TEST_F(UserMgrInTest, RememberOldPasswordTimesOnFailure)
{
- EXPECT_NO_THROW(dumpStringToFile("whatever", tempPamConfigFile));
+ EXPECT_NO_THROW(dumpStringToFile("whatever", tempPWHistoryConfigFile));
initializeAccountPolicy();
EXPECT_EQ(AccountPolicyIface::rememberOldPasswordTimes(), 0);
EXPECT_THROW(
diff --git a/user_mgr.cpp b/user_mgr.cpp
index 5bb1509..4f49925 100644
--- a/user_mgr.cpp
+++ b/user_mgr.cpp
@@ -61,15 +61,14 @@
static constexpr int failure = -1;
// pam modules related
-static constexpr const char* pamPWHistory = "pam_pwhistory.so";
static constexpr const char* minPasswdLenProp = "minlen";
static constexpr const char* remOldPasswdCount = "remember";
static constexpr const char* maxFailedAttempt = "deny";
static constexpr const char* unlockTimeout = "unlock_time";
-static constexpr const char* defaultPamPasswdConfigFile =
- "/etc/pam.d/common-password";
static constexpr const char* defaultFaillockConfigFile =
"/etc/security/faillock.conf";
+static constexpr const char* defaultPWHistoryConfigFile =
+ "/etc/security/pwhistory.conf";
static constexpr const char* defaultPWQualityConfigFile =
"/etc/security/pwquality.conf";
@@ -596,8 +595,8 @@
{
return value;
}
- if (setPamModuleArgValue(pamPWHistory, remOldPasswdCount,
- std::to_string(value)) != success)
+ if (setPamModuleConfValue(pwHistoryConfigFile, remOldPasswdCount,
+ std::to_string(value)) != success)
{
lg2::error("Unable to set rememberOldPasswordTimes to {VALUE}", "VALUE",
value);
@@ -638,51 +637,6 @@
return AccountPolicyIface::accountUnlockTimeout(value);
}
-int UserMgr::getPamModuleArgValue(const std::string& moduleName,
- const std::string& argName,
- std::string& argValue)
-{
- std::string fileName = pamPasswdConfigFile;
- std::ifstream fileToRead(fileName, std::ios::in);
- if (!fileToRead.is_open())
- {
- lg2::error("Failed to open pam configuration file {FILENAME}",
- "FILENAME", fileName);
- return failure;
- }
- std::string line;
- auto argSearch = argName + "=";
- size_t startPos = 0;
- size_t endPos = 0;
- while (getline(fileToRead, line))
- {
- // skip comments section starting with #
- if ((startPos = line.find('#')) != std::string::npos)
- {
- if (startPos == 0)
- {
- continue;
- }
- // skip comments after meaningful section and process those
- line = line.substr(0, startPos);
- }
- if (line.find(moduleName) != std::string::npos)
- {
- if ((startPos = line.find(argSearch)) != std::string::npos)
- {
- if ((endPos = line.find(' ', startPos)) == std::string::npos)
- {
- endPos = line.size();
- }
- startPos += argSearch.size();
- argValue = line.substr(startPos, endPos - startPos);
- return success;
- }
- }
- }
- return failure;
-}
-
int UserMgr::getPamModuleConfValue(const std::string& confFile,
const std::string& argName,
std::string& argValue)
@@ -724,72 +678,6 @@
return failure;
}
-int UserMgr::setPamModuleArgValue(const std::string& moduleName,
- const std::string& argName,
- const std::string& argValue)
-{
- std::string fileName = pamPasswdConfigFile;
- std::string tmpFileName = fileName + "_tmp";
- std::ifstream fileToRead(fileName, std::ios::in);
- std::ofstream fileToWrite(tmpFileName, std::ios::out);
- if (!fileToRead.is_open() || !fileToWrite.is_open())
- {
- lg2::error("Failed to open pam configuration file {FILENAME}",
- "FILENAME", fileName);
- // Delete the unused tmp file
- std::remove(tmpFileName.c_str());
- return failure;
- }
- std::string line;
- auto argSearch = argName + "=";
- size_t startPos = 0;
- size_t endPos = 0;
- bool found = false;
- while (getline(fileToRead, line))
- {
- // skip comments section starting with #
- if ((startPos = line.find('#')) != std::string::npos)
- {
- if (startPos == 0)
- {
- fileToWrite << line << std::endl;
- continue;
- }
- // skip comments after meaningful section and process those
- line = line.substr(0, startPos);
- }
- if (line.find(moduleName) != std::string::npos)
- {
- if ((startPos = line.find(argSearch)) != std::string::npos)
- {
- if ((endPos = line.find(' ', startPos)) == std::string::npos)
- {
- endPos = line.size();
- }
- startPos += argSearch.size();
- fileToWrite << line.substr(0, startPos) << argValue
- << line.substr(endPos, line.size() - endPos)
- << std::endl;
- found = true;
- continue;
- }
- }
- fileToWrite << line << std::endl;
- }
- fileToWrite.close();
- fileToRead.close();
- if (found)
- {
- if (std::rename(tmpFileName.c_str(), fileName.c_str()) == 0)
- {
- return success;
- }
- }
- // No changes, so delete the unused tmp file
- std::remove(tmpFileName.c_str());
- return failure;
-}
-
int UserMgr::setPamModuleConfValue(const std::string& confFile,
const std::string& argName,
const std::string& argValue)
@@ -1443,8 +1331,8 @@
AccountPolicyIface::minPasswordLength(value);
}
valueStr.clear();
- if (getPamModuleArgValue(pamPWHistory, remOldPasswdCount, valueStr) !=
- success)
+ if (getPamModuleConfValue(pwHistoryConfigFile, remOldPasswdCount,
+ valueStr) != success)
{
AccountPolicyIface::rememberOldPasswordTimes(0);
}
@@ -1589,8 +1477,8 @@
UserMgr::UserMgr(sdbusplus::bus_t& bus, const char* path) :
Ifaces(bus, path, Ifaces::action::defer_emit), bus(bus), path(path),
- pamPasswdConfigFile(defaultPamPasswdConfigFile),
faillockConfigFile(defaultFaillockConfigFile),
+ pwHistoryConfigFile(defaultPWHistoryConfigFile),
pwQualityConfigFile(defaultPWQualityConfigFile)
{
UserMgrIface::allPrivileges(privMgr);
diff --git a/user_mgr.hpp b/user_mgr.hpp
index f182968..d7b731c 100644
--- a/user_mgr.hpp
+++ b/user_mgr.hpp
@@ -494,8 +494,8 @@
friend class TestUserMgr;
- std::string pamPasswdConfigFile;
std::string faillockConfigFile;
+ std::string pwHistoryConfigFile;
std::string pwQualityConfigFile;
};