summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--special-mode-mgr/CMakeLists.txt4
-rw-r--r--special-mode-mgr/cmake/FindPAM.cmake71
-rw-r--r--special-mode-mgr/include/file.hpp79
-rw-r--r--special-mode-mgr/src/specialmodemgr.cpp113
4 files changed, 267 insertions, 0 deletions
diff --git a/special-mode-mgr/CMakeLists.txt b/special-mode-mgr/CMakeLists.txt
index fa69da8..6fe7f86 100644
--- a/special-mode-mgr/CMakeLists.txt
+++ b/special-mode-mgr/CMakeLists.txt
@@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(specialmodemgr CXX)
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
@@ -38,12 +39,15 @@ link_directories(${DBUSINTERFACE_LIBRARY_DIRS})
find_package(PkgConfig REQUIRED)
pkg_check_modules(LOGGING phosphor-logging REQUIRED)
+find_package(PAM REQUIRED)
+
add_executable(${PROJECT_NAME} ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} systemd)
target_link_libraries(${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES})
target_link_libraries(${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES})
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
target_link_libraries(${PROJECT_NAME} phosphor_logging)
+target_link_libraries(${PROJECT_NAME} pam)
link_directories(${EXTERNAL_INSTALL_LOCATION}/lib)
diff --git a/special-mode-mgr/cmake/FindPAM.cmake b/special-mode-mgr/cmake/FindPAM.cmake
new file mode 100644
index 0000000..25307bd
--- /dev/null
+++ b/special-mode-mgr/cmake/FindPAM.cmake
@@ -0,0 +1,71 @@
+# - Try to find the PAM libraries
+# Once done this will define
+#
+# PAM_FOUND - system has pam
+# PAM_INCLUDE_DIR - the pam include directory
+# PAM_LIBRARIES - libpam library
+
+if (PAM_INCLUDE_DIR AND PAM_LIBRARY)
+ # Already in cache, be silent
+ set(PAM_FIND_QUIETLY TRUE)
+endif (PAM_INCLUDE_DIR AND PAM_LIBRARY)
+
+find_path(PAM_INCLUDE_DIR NAMES security/pam_appl.h pam/pam_appl.h)
+find_library(PAM_LIBRARY pam)
+find_library(DL_LIBRARY dl)
+
+if (PAM_INCLUDE_DIR AND PAM_LIBRARY)
+ set(PAM_FOUND TRUE)
+ if (DL_LIBRARY)
+ set(PAM_LIBRARIES ${PAM_LIBRARY} ${DL_LIBRARY})
+ else (DL_LIBRARY)
+ set(PAM_LIBRARIES ${PAM_LIBRARY})
+ endif (DL_LIBRARY)
+
+ if (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h)
+ # darwin claims to be something special
+ set(HAVE_PAM_PAM_APPL_H 1)
+ endif (EXISTS ${PAM_INCLUDE_DIR}/pam/pam_appl.h)
+
+ if (NOT DEFINED PAM_MESSAGE_CONST)
+ include(CheckCXXSourceCompiles)
+ # XXX does this work with plain c?
+ check_cxx_source_compiles("
+#if ${HAVE_PAM_PAM_APPL_H}+0
+# include <pam/pam_appl.h>
+#else
+# include <security/pam_appl.h>
+#endif
+static int PAM_conv(
+ int num_msg,
+ const struct pam_message **msg, /* this is the culprit */
+ struct pam_response **resp,
+ void *ctx)
+{
+ return 0;
+}
+int main(void)
+{
+ struct pam_conv PAM_conversation = {
+ &PAM_conv, /* this bombs out if the above does not match */
+ 0
+ };
+ return 0;
+}
+" PAM_MESSAGE_CONST)
+ endif (NOT DEFINED PAM_MESSAGE_CONST)
+ set(PAM_MESSAGE_CONST ${PAM_MESSAGE_CONST} CACHE BOOL "PAM expects a conversation function with const pam_message")
+
+endif (PAM_INCLUDE_DIR AND PAM_LIBRARY)
+
+if (PAM_FOUND)
+ if (NOT PAM_FIND_QUIETLY)
+ message(STATUS "Found PAM: ${PAM_LIBRARIES}")
+ endif (NOT PAM_FIND_QUIETLY)
+else (PAM_FOUND)
+ if (PAM_FIND_REQUIRED)
+ message(FATAL_ERROR "PAM was not found")
+ endif(PAM_FIND_REQUIRED)
+endif (PAM_FOUND)
+
+mark_as_advanced(PAM_INCLUDE_DIR PAM_LIBRARY DL_LIBRARY PAM_MESSAGE_CONST)
diff --git a/special-mode-mgr/include/file.hpp b/special-mode-mgr/include/file.hpp
new file mode 100644
index 0000000..3ea0d50
--- /dev/null
+++ b/special-mode-mgr/include/file.hpp
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <stdio.h>
+
+#include <filesystem>
+
+/** @class File
+ * @brief Responsible for handling file pointer
+ * Needed by putspent(3)
+ */
+class File
+{
+ private:
+ /** @brief handler for operating on file */
+ FILE* fp = NULL;
+
+ /** @brief File name. Needed in the case where the temp
+ * needs to be removed
+ */
+ const std::string& name;
+
+ /** @brief Should the file be removed at exit */
+ bool removeOnExit = false;
+
+ public:
+ File() = delete;
+ File(const File&) = delete;
+ File& operator=(const File&) = delete;
+ File(File&&) = delete;
+ File& operator=(File&&) = delete;
+
+ /** @brief Opens file and uses it to do file operation
+ *
+ * @param[in] name - File name
+ * @param[in] mode - File open mode
+ * @param[in] removeOnExit - File to be removed at exit or no
+ */
+ File(const std::string& filename, const std::string& mode,
+ bool removeExit = false) :
+ name(filename),
+ removeOnExit(removeExit)
+ {
+ fp = fopen(name.c_str(), mode.c_str());
+ }
+
+ /** @brief Opens file using provided file descriptor
+ *
+ * @param[in] fd - File descriptor
+ * @param[in] name - File name
+ * @param[in] mode - File open mode
+ * @param[in] removeOnExit - File to be removed at exit or no
+ */
+ File(int fd, const std::string& filename, const std::string& mode,
+ bool removeExit = false) :
+ name(filename),
+ removeOnExit(removeExit)
+ {
+ fp = fdopen(fd, mode.c_str());
+ }
+
+ ~File()
+ {
+ if (fp)
+ {
+ fclose(fp);
+ }
+
+ // Needed for exception safety
+ if (removeOnExit && std::filesystem::exists(name))
+ {
+ std::filesystem::remove(name);
+ }
+ }
+
+ auto operator()()
+ {
+ return fp;
+ }
+};
diff --git a/special-mode-mgr/src/specialmodemgr.cpp b/special-mode-mgr/src/specialmodemgr.cpp
index 132b26e..61c1d8a 100644
--- a/special-mode-mgr/src/specialmodemgr.cpp
+++ b/special-mode-mgr/src/specialmodemgr.cpp
@@ -15,9 +15,13 @@
*/
#include "specialmodemgr.hpp"
+#include "file.hpp"
+#include <security/pam_appl.h>
#include <sys/sysinfo.h>
+#include <pwd.h>
+#include <shadow.h>
#include <fstream>
#include <phosphor-logging/log.hpp>
#include <string>
@@ -46,6 +50,112 @@ using VariantValue =
namespace secCtrl = sdbusplus::xyz::openbmc_project::Control::Security::server;
+#ifdef BMC_VALIDATION_UNSECURE_FEATURE
+
+static int pamFunctionConversation(int numMsg, const struct pam_message** msg,
+ struct pam_response** resp, void* appdataPtr)
+{
+ if (appdataPtr == nullptr)
+ {
+ return PAM_AUTH_ERR;
+ }
+ size_t passSize = std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1;
+ char* pass = reinterpret_cast<char*>(malloc(passSize));
+ std::strncpy(pass, reinterpret_cast<char*>(appdataPtr), passSize);
+
+ *resp = reinterpret_cast<pam_response*>(
+ calloc(numMsg, sizeof(struct pam_response)));
+
+ for (int i = 0; i < numMsg; ++i)
+ {
+ if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
+ {
+ continue;
+ }
+ resp[i]->resp = pass;
+ }
+ return PAM_SUCCESS;
+}
+
+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
+
+ 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);
+}
+
+static void checkAndConfigureSpecialUser()
+{
+ std::array<char, 4096> sbuffer{};
+ struct spwd spwd;
+ struct spwd* resultPtr = nullptr;
+ constexpr const char* specialUser = "root";
+ constexpr const char* specialUserDefPasswd = "0penBmc1";
+
+ // Query shadow entry for special user.
+ int status = getspnam_r(specialUser, &spwd, sbuffer.data(),
+ sbuffer.max_size(), &resultPtr);
+ if (status || (&spwd != resultPtr))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Error in querying shadow entry for special user");
+ }
+ // Encrypted Password may be NULL or single character '!' if user is
+ // disabled
+ if (resultPtr->sp_pwdp[0] == 0 || resultPtr->sp_pwdp[1] == 0)
+ {
+ pamUpdatePasswd(specialUser, specialUserDefPasswd);
+ // requery the special user shadow entry as there is password
+ // update.
+ resultPtr = nullptr;
+ status = getspnam_r(specialUser, &spwd, sbuffer.data(),
+ sbuffer.max_size(), &resultPtr);
+ if (status || (&spwd != resultPtr))
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Error in querying shadow entry for special user");
+ }
+ // Mark the password as expired to force update the password
+ File passwdFd("/etc/shadow", "r+");
+ if ((passwdFd)() == nullptr)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Error in opening shadow file");
+ return;
+ }
+ // Mark the special user password as expired. This will
+ // force the user to set new password on first login.
+ resultPtr->sp_lstchg = 0;
+ putspent(resultPtr, (passwdFd)());
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Configured special user sucessfully");
+ }
+ else
+ {
+ phosphor::logging::log<phosphor::logging::level::DEBUG>(
+ "Skip configuring special user as it is already enabled");
+ }
+}
+
+#endif
+
SpecialModeMgr::SpecialModeMgr(
boost::asio::io_service& io_, sdbusplus::asio::object_server& srv_,
std::shared_ptr<sdbusplus::asio::connection>& conn_) :
@@ -192,6 +302,9 @@ void SpecialModeMgr::checkAndAddSpecialModeProperty(const std::string& provMode)
sd_journal_send("MESSAGE=%s", "Manufacturing mode - Entered",
"PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
"OpenBMC.0.1.ManufacturingModeEntered", NULL);
+#ifdef BMC_VALIDATION_UNSECURE_FEATURE
+ checkAndConfigureSpecialUser();
+#endif
}
addSpecialModeProperty();
if (!specialModeLockoutSeconds)