summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuryakanth Sekar <suryakanth.sekar@linux.intel.com>2019-11-15 14:46:28 +0300
committerWang, Kuiying <kuiying.wang@intel.com>2020-01-11 14:31:35 +0300
commit65d4fafd39553243d83834a87ce2806059c837b0 (patch)
tree0331155cdea5252bbd45edfb2b37e3bb3be560be
parent6d93fe942fe3df101a644ffa39e1e4feab4382e7 (diff)
downloadprovingground-65d4fafd39553243d83834a87ce2806059c837b0.tar.xz
Add Security Manager - ASD/User security Event
Daemon for below functionalities 1. To start the AtScaleDebug service when remote debug on jumper & special user status and enabled. 2. To stop the AtScaleDebug service when remote debug jumper disabled and disabled the special user status. 3. Log the corresponding AtScaleDebug Events 4. Check for user security breach and log the user security event. Tested: Detecting Remote Debug jumper - enabled or disabled Enable the ASD/Disable the ASD based on jumper and spl user password Corresponding the ASD security Event should be logged Check for unsupported shell- user security event: Change shell parameter for enabled user by usermod --shell=/bin/csh <enabled username> "SecurityUserUnsupportedShellEnabled" Event should be logged Check for unsupported shell removed - user security event: change shell parameter for enabled user by usermod --shell=/bin/sh <enabled username> "SecurityUserUnsupportedShellRemoved" Event should be logged Check for Weak Password hashing algorithm Event: change the password hashing algorithm by edit file : /etc/pam.d/common-password -->sha512 to md5 set new password for any user. "SecurityUserWeakHashAlgoEnabled" Event should be logged similar change from md5 to sha512 in /etc/pam.d/common-password file Set new password for any user. "SecurityUserStrongHashAlgoRestored" Event should be logged If root user is enabled "SecurityUserRootEnabled" Event should be logged If root user is disabled "SecurityUserRootDisabled" Event should be logged Change-Id: I88f8614df31df3f35e7d08d2e84aeef7a39edea4 Signed-off-by: Suryakanth Sekar <suryakanth.sekar@linux.intel.com>
-rw-r--r--security-manager/.clang-format98
-rw-r--r--security-manager/CMakeLists.txt63
-rw-r--r--security-manager/LICENSE13
-rw-r--r--security-manager/cmake-format.json12
-rw-r--r--security-manager/service_files/xyz.openbmc_project.SecurityManager.service13
-rw-r--r--security-manager/src/file.hpp86
-rw-r--r--security-manager/src/security-manager.cpp743
-rw-r--r--security-manager/src/security-manager.hpp37
8 files changed, 1065 insertions, 0 deletions
diff --git a/security-manager/.clang-format b/security-manager/.clang-format
new file mode 100644
index 0000000..ae9ad39
--- /dev/null
+++ b/security-manager/.clang-format
@@ -0,0 +1,98 @@
+---
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+PointerAlignment: Left
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^[<"](gtest|gmock)'
+ Priority: 5
+ - Regex: '^"config.h"'
+ Priority: -1
+ - Regex: '^".*\.hpp"'
+ Priority: 1
+ - Regex: '^<.*\.h>'
+ Priority: 2
+ - Regex: '^<.*'
+ Priority: 3
+ - Regex: '.*'
+ Priority: 4
+IndentCaseLabels: true
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+ReflowComments: true
+SortIncludes: true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 4
+UseTab: Never
+...
diff --git a/security-manager/CMakeLists.txt b/security-manager/CMakeLists.txt
new file mode 100644
index 0000000..cec3cb3
--- /dev/null
+++ b/security-manager/CMakeLists.txt
@@ -0,0 +1,63 @@
+cmake_minimum_required (VERSION 3.6 FATAL_ERROR)
+project (security-manager CXX)
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lstdc++fs \
+ -Werror \
+ -Wall \
+ -Wextra \
+ -Wshadow \
+ -Wnon-virtual-dtor \
+ -Wold-style-cast \
+ -Wunused \
+ -Woverloaded-virtual \
+ -Wpedantic \
+ -Wconversion \
+ -Wmisleading-indentation \
+ -Wduplicated-cond \
+ -Wduplicated-branches \
+ -Wlogical-op \
+ -Wnull-dereference \
+ -Wuseless-cast \
+ -Wdouble-promotion \
+ -Wformat=2 \
+")
+
+set (CMAKE_CXX_STANDARD 17)
+set (CMAKE_CXX_STANDARD_REQUIRED ON)
+
+add_executable (security-manager src/security-manager.cpp)
+
+target_include_directories (security-manager PRIVATE ${CMAKE_SOURCE_DIR})
+
+target_link_libraries (${PROJECT_NAME} -lstdc++fs)
+target_link_libraries (${PROJECT_NAME} gpiodcxx)
+target_link_libraries (${PROJECT_NAME} systemd)
+target_link_libraries (${PROJECT_NAME} sdbusplus)
+
+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+install (
+ TARGETS security-manager
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib/static
+)
+
+find_package (Boost 1.66 REQUIRED)
+include_directories (${BOOST_SRC_DIR})
+
+add_definitions (-DBOOST_ERROR_CODE_HEADER_ONLY)
+add_definitions (-DBOOST_SYSTEM_NO_DEPRECATED)
+add_definitions (-DBOOST_ALL_NO_LIB)
+add_definitions (-DBOOST_NO_RTTI)
+add_definitions (-DBOOST_NO_TYPEID)
+add_definitions (-DBOOST_ASIO_DISABLE_THREADS)
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
+
+set (
+ SERVICE_FILES
+ ${PROJECT_SOURCE_DIR}/service_files/xyz.openbmc_project.SecurityManager.service
+)
+install (FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/)
diff --git a/security-manager/LICENSE b/security-manager/LICENSE
new file mode 100644
index 0000000..729f4d4
--- /dev/null
+++ b/security-manager/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2019 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.
diff --git a/security-manager/cmake-format.json b/security-manager/cmake-format.json
new file mode 100644
index 0000000..4a701ae
--- /dev/null
+++ b/security-manager/cmake-format.json
@@ -0,0 +1,12 @@
+{
+ "enum_char": ".",
+ "line_ending": "unix",
+ "bullet_char": "*",
+ "max_subargs_per_line": 99,
+ "command_case": "lower",
+ "tab_size": 4,
+ "line_width": 80,
+ "separate_fn_name_with_space": true,
+ "dangle_parens": true,
+ "separate_ctrl_name_with_space": true
+}
diff --git a/security-manager/service_files/xyz.openbmc_project.SecurityManager.service b/security-manager/service_files/xyz.openbmc_project.SecurityManager.service
new file mode 100644
index 0000000..76d9f0d
--- /dev/null
+++ b/security-manager/service_files/xyz.openbmc_project.SecurityManager.service
@@ -0,0 +1,13 @@
+[Unit]
+Description= Security Manager - For At-ScaleDebug service, User security
+Requires=xyz.openbmc_project.EntityManager.service
+After=xyz.openbmc_project.ObjectMapper.service
+
+[Service]
+Restart=always
+ExecStart=/usr/bin/security-manager
+Type=simple
+SyslogIdentifier=security-manager
+
+[Install]
+WantedBy=multi-user.target
diff --git a/security-manager/src/file.hpp b/security-manager/src/file.hpp
new file mode 100644
index 0000000..7a286bf
--- /dev/null
+++ b/security-manager/src/file.hpp
@@ -0,0 +1,86 @@
+#pragma once
+
+#include <stdio.h>
+
+#include <filesystem>
+
+namespace security_manager
+{
+
+namespace fs = std::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 && fs::exists(name))
+ {
+ fs::remove(name);
+ }
+ }
+
+ auto operator()()
+ {
+ return fp;
+ }
+};
+
+} // namespace security_manager
diff --git a/security-manager/src/security-manager.cpp b/security-manager/src/security-manager.cpp
new file mode 100644
index 0000000..4d456dc
--- /dev/null
+++ b/security-manager/src/security-manager.cpp
@@ -0,0 +1,743 @@
+/*
+// Copyright (c) 2019 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.
+*/
+
+#include "security-manager.hpp"
+
+#include "file.hpp"
+
+#include <pwd.h>
+#include <shadow.h>
+#include <systemd/sd-journal.h>
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/asio.hpp>
+#include <boost/asio/posix/stream_descriptor.hpp>
+#include <gpiod.hpp>
+#include <iostream>
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+#include <string>
+#include <variant>
+#include <vector>
+
+namespace security_manager
+{
+
+static boost::asio::io_service io;
+static std::shared_ptr<sdbusplus::asio::connection> conn;
+static int inotifyFd = -1;
+static int inotifyPwdFd = -1;
+
+static bool atScaleDebugHarwareSupported = true;
+static uint8_t currentAtScaleDebugState = 0xFF;
+static constexpr uint8_t wolfPassBoardProductId = 0x7B;
+static uint8_t systemBoardProductId = 0xFF;
+static bool atScaleDebugHWInitDone = false;
+static UserAssertedEventRecord assertedEvent = {0, 0, 0, 0};
+
+std::unique_ptr<sdbusplus::bus::match_t> baseBoardUpdatedSignal;
+
+//----------------------------------
+// REMOTE_DEBUG_DETECTION function related definition
+//----------------------------------
+static gpiod::line remoteDebugDetectionLine;
+static boost::asio::posix::stream_descriptor remoteDebugDetectEvent(io);
+static boost::asio::posix::stream_descriptor fileChangeEvent(io);
+static boost::asio::posix::stream_descriptor filePwdChangeEvent(io);
+
+/** @brief implement Security event logging
+ * @param[in] Event message string
+ * @param[in] Event Severity
+ * @param[in] Event optional message
+ * @returns status
+ */
+static void securityEventlog(const std::string& msg, int severity)
+{
+
+ std::string eventStr = "OpenBMC.0.1." + msg;
+ sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
+ "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
+ eventStr.c_str(), NULL);
+}
+
+/** @brief implement check given user is active or not
+ * @param[in] username
+ * @param[out] algotype if user is enabled
+ * @returns user status
+ */
+
+static bool getUserStatusAndHashAlgoType(const std::string& username,
+ uint8_t& algo)
+{
+
+ std::array<char, 4096> sbuffer{};
+ struct spwd spwd;
+ struct spwd* resultPtr = nullptr;
+ // To get the shadow entry of asdbg user for verify the password is set or
+ // not
+ int status = getspnam_r(username.c_str(), &spwd, sbuffer.data(),
+ sbuffer.max_size(), &resultPtr);
+ if (!status && (&spwd == resultPtr))
+ {
+ // Encrypted Password may be NULL or single character '!' if user is
+ // disabled
+ if (resultPtr->sp_pwdp[0] == 0 || resultPtr->sp_pwdp[1] == 0)
+ {
+ return false; // user pwd not set
+ }
+ algo = static_cast<int8_t>(std::atoi(&resultPtr->sp_pwdp[1]));
+ return true; // user is enabled and password is set
+ }
+ return false; // assume user is disabled for any error.
+}
+
+/** @brief implement check any user related security breach
+ * @returns function status
+ */
+
+static void checkUserSecurityBreach()
+{
+
+ UserAssertedEventRecord currentAssertedEventState = {0, 0, 0, 0};
+ uint8_t algoType = 0;
+
+ std::vector<std::string> userList;
+ std::vector<std::string> sshUsersList;
+
+ struct passwd pw, *pwp = nullptr;
+ std::array<char, 1024> buffer{};
+
+ security_manager::File passwd("/etc/passwd", "r");
+ if ((passwd)() == NULL)
+ {
+ std::cerr << "\nSecurity-manager :Error in opening passwd file \n";
+ }
+
+ while (true)
+ {
+ auto r = fgetpwent_r((passwd)(), &pw, buffer.data(), buffer.max_size(),
+ &pwp);
+ if ((r != 0) || (pwp == NULL))
+ {
+ // break the loop. if reached EOF or any Error
+ break;
+ }
+
+ std::string userName(pwp->pw_name);
+ if (getUserStatusAndHashAlgoType(userName, algoType))
+ {
+ std::string loginShell(pwp->pw_shell);
+ if ((loginShell == "/bin/zsh") || (loginShell == "/bin/csh") ||
+ (loginShell == "/bin/ksh93") || (loginShell == "/bin/tcsh"))
+ {
+ if (!assertedEvent.unSupportedShellEvent)
+ {
+ assertedEvent.unSupportedShellEvent = true;
+ securityEventlog("SecurityUserUnsupportedShellEnabled",
+ LOG_CRIT);
+ }
+ currentAssertedEventState.unSupportedShellEvent = true;
+ }
+ if ((!("root" == userName)) && (pwp->pw_uid == 0))
+ {
+ if (!assertedEvent.uidZeroAssignedEvent)
+ {
+ assertedEvent.uidZeroAssignedEvent = true;
+
+ securityEventlog("SecurityUserNonRootUidZeroAssigned",
+ LOG_CRIT);
+ }
+ currentAssertedEventState.uidZeroAssignedEvent = true;
+ }
+ if (("root" == userName))
+ {
+ if (!assertedEvent.rootEnabledEvent)
+ {
+ assertedEvent.rootEnabledEvent = true;
+
+ securityEventlog("SecurityUserRootEnabled", LOG_CRIT);
+ }
+ currentAssertedEventState.rootEnabledEvent = true;
+ }
+ if (algoType <=
+ static_cast<uint8_t>(PasswordHashAlgorithm::hashAlgoNT))
+ {
+ if (!assertedEvent.weakHashAlgorithmEvent)
+ {
+ assertedEvent.weakHashAlgorithmEvent = true;
+
+ securityEventlog("SecurityUserWeakHashAlgoEnabled",
+ LOG_CRIT);
+ }
+ currentAssertedEventState.weakHashAlgorithmEvent = true;
+ }
+ }
+ }
+
+ endpwent();
+ if (currentAssertedEventState.weakHashAlgorithmEvent == false &&
+ assertedEvent.weakHashAlgorithmEvent == true)
+ {
+ securityEventlog("SecurityUserStrongHashAlgoRestored", LOG_INFO);
+ assertedEvent.weakHashAlgorithmEvent = false;
+ }
+
+ if (currentAssertedEventState.rootEnabledEvent == false &&
+ assertedEvent.rootEnabledEvent == true)
+ {
+ securityEventlog("SecurityUserRootDisabled", LOG_INFO);
+ assertedEvent.rootEnabledEvent = false;
+ }
+
+ if (currentAssertedEventState.uidZeroAssignedEvent == false &&
+ assertedEvent.uidZeroAssignedEvent == true)
+ {
+ securityEventlog("SecurityUserNonRootUidZeroRemoved", LOG_INFO);
+ assertedEvent.uidZeroAssignedEvent = false;
+ }
+
+ if (currentAssertedEventState.unSupportedShellEvent == false &&
+ assertedEvent.unSupportedShellEvent == true)
+ {
+ securityEventlog("SecurityUserUnsupportedShellRemoved", LOG_INFO);
+ assertedEvent.unSupportedShellEvent = false;
+ }
+
+ return;
+} // namespace security_manager
+
+/** @brief implement check and control At-Scale Debug service
+ * @returns function status
+ */
+
+static void checkAndControlAtScaleDebugService()
+{
+ const static constexpr char* systemDService = "org.freedesktop.systemd1";
+ const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1";
+ const static constexpr char* systemDMgrIntf =
+ "org.freedesktop.systemd1.Manager";
+ const static constexpr char* atScaleDebugService =
+ "com.intel.AtScaleDebug.service";
+ const std::string atScaleDebugUserName = "asdbg";
+
+ bool flag = true;
+ uint8_t algoType = 0;
+
+ // We need to check the hardware at-ScaleDebug enabled or disabled.
+ if (security_manager::atScaleDebugHarwareSupported)
+ {
+ flag = security_manager::remoteDebugDetectionLine.get_value();
+ }
+
+ // we need to enable at-ScaleDebug service only if special user is enabled.
+ if (flag)
+ {
+ flag = getUserStatusAndHashAlgoType(atScaleDebugUserName, algoType);
+ std::cerr << "Remote Debug Hardware Enabled \n";
+ }
+ // We have to avoid service start or stop if already in desired state.
+ if (currentAtScaleDebugState == flag)
+ {
+ return;
+ }
+ currentAtScaleDebugState = flag;
+
+ conn->async_method_call(
+ [flag](const boost::system::error_code ec) {
+ if (ec)
+ {
+ std::cerr << "\n Error in start or stop AtScaleDebug service:"
+ << ec.message() << "\n";
+ // Keep Current AtScale Debug State by default
+ currentAtScaleDebugState = 0xFF;
+ return;
+ }
+
+ if (flag)
+ {
+ securityEventlog("AtScaleDebugFeatureEnabled", LOG_CRIT);
+ }
+ else
+ {
+ securityEventlog("AtScaleDebugFeatureDisabled", LOG_INFO);
+ }
+ },
+ systemDService, systemDObjPath, systemDMgrIntf,
+ flag ? "StartUnit" : "StopUnit", atScaleDebugService, "replace");
+
+ return;
+}
+
+/** @brief implement register GPIO events
+ * @param[in] GPIO PIN name
+ * @param[in] Function Callback handler
+ * @param[in] GPIO line
+ * @param[in] stream Event descriptor
+ * @returns function status
+ */
+
+static bool requestGPIOEvents(
+ const std::string& name, const std::function<void()>& handler,
+ gpiod::line& gpioLine,
+ boost::asio::posix::stream_descriptor& gpioEventDescriptor)
+{
+ // Find the GPIO line
+ gpioLine = gpiod::find_line(name);
+ if (!gpioLine)
+ {
+ std::cerr << "Failed to find the " << name << "GPIO line\n";
+ return false;
+ }
+
+ try
+ {
+ gpioLine.request(
+ {"security-manager", gpiod::line_request::EVENT_BOTH_EDGES, 0});
+ }
+ catch (std::exception&)
+ {
+ std::cerr << "Failed to request events for " << name << "\n";
+ return false;
+ }
+
+ int gpioLineFd = gpioLine.event_get_fd();
+ if (gpioLineFd < 0)
+ {
+ std::cerr << "Failed to get " << name << " fd\n";
+ return false;
+ }
+
+ gpioEventDescriptor.assign(gpioLineFd);
+
+ gpioEventDescriptor.async_wait(
+ boost::asio::posix::stream_descriptor::wait_read,
+ [handler](const boost::system::error_code ec) {
+ if (ec)
+ {
+ std::cerr << "RemoteDebugEnable fd handler error: "
+ << ec.message() << "\n";
+ return;
+ }
+ handler();
+ });
+ return true;
+}
+
+/** @brief implement check remote Debug on and log the event
+ * @returns function status
+ */
+
+static void remoteDebugDetectionHandler()
+{
+ gpiod::line_event gpioLineEvent = remoteDebugDetectionLine.event_read();
+
+ bool remoteDebugEnable =
+ (gpioLineEvent.event_type == gpiod::line_event::RISING_EDGE);
+
+ if (remoteDebugEnable)
+ {
+
+ // Log the atScaleDebugHardware enable Event
+ securityEventlog("AtScaleDebugFeatureEnabledAtHardware", LOG_CRIT);
+ }
+ else
+ {
+ // Log the atScaleDebugHardware disable Event
+ securityEventlog("AtScaleDebugFeatureDisabledAtHardware", LOG_INFO);
+ }
+
+ checkAndControlAtScaleDebugService();
+ remoteDebugDetectEvent.async_wait(
+ boost::asio::posix::stream_descriptor::wait_read,
+ [](const boost::system::error_code ec) {
+ if (ec)
+ {
+ std::cerr << "RemoteDebugEnable handler error: " << ec.message()
+ << "\n";
+ return;
+ }
+ remoteDebugDetectionHandler();
+ });
+}
+
+/** @brief implement register file change Event
+ * @param[in] file descriptor
+ * @param[in] file name
+ * @param[in] Function Callback handler
+ * @param[in] stream Event descriptor
+ * @returns function status
+ */
+
+static bool requestFileChangeEvents(
+ int& fd, const std::string& filename, const std::function<void()>& handler,
+ boost::asio::posix::stream_descriptor& fileChangeEventDescriptor)
+{
+
+ fd = inotify_init1(IN_NONBLOCK);
+ if (-1 == fd)
+ {
+ return false;
+ }
+
+ fileChangeEventDescriptor.assign(fd);
+ auto wd = inotify_add_watch(fd, filename.c_str(),
+ IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF |
+ IN_MOVE_SELF | IN_MODIFY);
+ if (-1 == wd)
+ {
+ close(fd);
+ return false;
+ }
+
+ fileChangeEventDescriptor.async_wait(
+ boost::asio::posix::stream_descriptor::wait_read,
+ [handler](const boost::system::error_code ec) {
+ if (ec)
+ {
+ std::cerr << "shadow fd handler error: " << ec.message()
+ << "\n";
+ return;
+ }
+ handler();
+ });
+ return true;
+}
+
+static void addInotifyWatch(int& fd, const std::string filename)
+{
+
+ auto wd = inotify_add_watch(fd, filename.c_str(),
+ IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF |
+ IN_MOVE_SELF | IN_MODIFY);
+ if (-1 == wd)
+ {
+ std::cerr << "Error in adding notify : " << filename.c_str() << "\n";
+ return;
+ }
+}
+
+/** @brief implement shadow file Event handler
+ @Wait for inotify event and Parse shadow file inotify event
+ @Log the Event if any security breach
+ @If asdbg user is set or disabled then control the AtScale Debug service.
+ * @returns function status
+ */
+
+static void fileShadowChangeHandler()
+{
+
+ std::array<char, 4096> buffer{};
+ struct inotify_event* event = NULL;
+ int index = 0;
+ bool exec = 0;
+
+ int len = read(inotifyFd, buffer.data(), sizeof(buffer));
+ if (len < 0)
+ {
+ std::cerr << "fileChangeHandler length error: " << len;
+ }
+
+ event = reinterpret_cast<inotify_event*>(&buffer[index]);
+ while (event != NULL)
+ {
+
+ event = reinterpret_cast<inotify_event*>(&buffer[index]);
+
+ if (((event->mask & IN_MOVE_SELF) || (event->mask & IN_CLOSE_WRITE) ||
+ (event->mask & IN_MODIFY) || (event->mask & IN_DELETE_SELF)))
+ {
+ exec = true;
+ }
+
+ if (event->mask & IN_IGNORED)
+ {
+ addInotifyWatch(inotifyFd, "/etc/shadow");
+ }
+ /* Move to next struct */
+ len -= sizeof(inotify_event) + event->len;
+ if (len > 0)
+ index += (sizeof(inotify_event) + event->len);
+ else
+ event = NULL;
+ }
+
+ if (exec)
+ {
+ checkAndControlAtScaleDebugService();
+ checkUserSecurityBreach();
+ }
+
+ fileChangeEvent.async_wait(boost::asio::posix::stream_descriptor::wait_read,
+ [](const boost::system::error_code ec) {
+ if (ec)
+ {
+ std::cerr
+ << "Recvd File read signal-error: "
+ << ec.message() << "\n";
+ return;
+ }
+
+ fileShadowChangeHandler();
+ });
+}
+
+/** @brief implement Passwd file Event handler
+ @Wait for inotify event and Parse passwd file inotify event
+ @Log the Event if any security breach
+ * @returns function status
+ */
+
+static void filePwdChangeHandler()
+{
+
+ std::array<char, 4096> buffer{};
+ struct inotify_event* event = NULL;
+ int index = 0;
+ bool exec = 0;
+
+ int len = read(inotifyPwdFd, buffer.data(), sizeof(buffer));
+ if (len < 0)
+ {
+ std::cerr << "filePwdChangeHandler length error: " << len;
+ }
+
+ event = reinterpret_cast<inotify_event*>(&buffer[index]);
+ while (event != NULL)
+ {
+
+ event = reinterpret_cast<inotify_event*>(&buffer[index]);
+
+ if (((event->mask & IN_MOVE_SELF) || (event->mask & IN_CLOSE_WRITE) ||
+ (event->mask & IN_MODIFY) || (event->mask & IN_DELETE_SELF)))
+ {
+ exec = true;
+ }
+
+ if (event->mask & IN_IGNORED)
+ {
+ addInotifyWatch(inotifyPwdFd, "/etc/passwd");
+ }
+ /* Move to next struct */
+ len -= sizeof(inotify_event) + event->len;
+ if (len > 0)
+ index += (sizeof(inotify_event) + event->len);
+ else
+ event = NULL;
+ }
+
+ if (exec)
+ {
+ checkUserSecurityBreach();
+ }
+
+ filePwdChangeEvent.async_wait(
+ boost::asio::posix::stream_descriptor::wait_read,
+ [](const boost::system::error_code ec) {
+ if (ec)
+ {
+ std::cerr << "Recvd File read signal-error: " << ec.message()
+ << "\n";
+ return;
+ }
+
+ filePwdChangeHandler();
+ });
+}
+
+/** @brief implement manager function
+ @Register for GPIO and file change event with callback function
+ * @returns function status
+ */
+
+static void coreMonitor()
+{
+
+ if (security_manager::atScaleDebugHarwareSupported)
+ {
+
+ // Request REMOTE_DEBUG_ENABLE GPIO events
+ if (!security_manager::requestGPIOEvents(
+ "REMOTE_DEBUG_ENABLE",
+ security_manager::remoteDebugDetectionHandler,
+ security_manager::remoteDebugDetectionLine,
+ security_manager::remoteDebugDetectEvent))
+ {
+ return;
+ }
+ }
+ // We need to need enable or disable based on at-ScaleDebug special
+ // user and Hardware status
+ security_manager::checkAndControlAtScaleDebugService();
+
+ // Request file change events
+ if (!security_manager::requestFileChangeEvents(
+ inotifyFd, "/etc/shadow", security_manager::fileShadowChangeHandler,
+ security_manager::fileChangeEvent))
+ {
+ return;
+ }
+
+ // Request Pwd file change events
+ if (!security_manager::requestFileChangeEvents(
+ inotifyPwdFd, "/etc/passwd", security_manager::filePwdChangeHandler,
+ security_manager::filePwdChangeEvent))
+ {
+ return;
+ }
+
+ security_manager::checkUserSecurityBreach();
+
+ atScaleDebugHWInitDone = true;
+}
+static void registerAtScaleDebugMonitor(const std::string& baseboardObjPath)
+{
+
+ // Get the Baseboard object to find the Product id
+
+ conn->async_method_call(
+ [](boost::system::error_code ec,
+ const std::variant<std::uint64_t>& property) {
+ if (ec)
+ {
+ return;
+ }
+ systemBoardProductId =
+ static_cast<uint8_t>(std::get<uint64_t>(property));
+ security_manager::atScaleDebugHarwareSupported =
+ systemBoardProductId == wolfPassBoardProductId ? false : true;
+ coreMonitor();
+ },
+ "xyz.openbmc_project.EntityManager", baseboardObjPath,
+ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.Inventory.Item.Board.Motherboard", "ProductId");
+
+ return;
+}
+
+static bool startAtScaleDebugMonitor()
+{
+
+ // Get the all objects related with inventory to find the Baseboard object
+ // path
+ conn->async_method_call(
+ [](const boost::system::error_code ec,
+ const std::vector<std::string>& subtree) {
+ if (ec)
+ {
+
+ std::cerr << "Failed to get SubTree for "
+ "BaseBoard \n";
+ return;
+ }
+ const std::string match = "board";
+
+ for (const std::string& objpath : subtree)
+ {
+ // Iterate over all retrieved ObjectPaths.
+
+ if (!boost::ends_with(objpath, match))
+ {
+ continue;
+ }
+
+ // Baseboard object path found
+ registerAtScaleDebugMonitor(objpath);
+ return;
+ }
+ // Failed to get BaseBoard Object Path so waiting for EntityManager
+ // Signal
+
+ const static constexpr char* baseBoardInterface =
+ "xyz.openbmc_project.Inventory.Item.Board.Motherboard";
+ const static constexpr char* baseBoardObjBasePath =
+ "/xyz/openbmc_project/inventory/system/board/";
+
+ security_manager::baseBoardUpdatedSignal = std::make_unique<
+ sdbusplus::bus::match_t>(
+ *security_manager::conn,
+ sdbusplus::bus::match::rules::interfacesAdded() +
+ sdbusplus::bus::match::rules::argNpath(
+ 0, baseBoardObjBasePath),
+ [](sdbusplus::message::message& msg) {
+ sdbusplus::message::object_path objPath;
+ boost::container::flat_map<
+ std::string,
+ boost::container::flat_map<
+ std::string, std::variant<std::string, uint64_t>>>
+ msgData;
+ msg.read(objPath, msgData);
+
+ // Check for xyz.openbmc_project.Inventory.Item.Board
+ // interface match
+ auto intfFound = msgData.find(baseBoardInterface);
+ if (msgData.end() != intfFound)
+ {
+ // Check for ProductId property match
+
+ auto prodIdFound = intfFound->second.find("ProductId");
+ if (intfFound->second.end() != prodIdFound)
+ {
+
+ systemBoardProductId = static_cast<uint8_t>(
+ std::get<uint64_t>(prodIdFound->second));
+ security_manager::atScaleDebugHarwareSupported =
+ systemBoardProductId == wolfPassBoardProductId
+ ? false
+ : true;
+
+ if (atScaleDebugHWInitDone == false)
+ {
+ coreMonitor();
+ }
+ }
+ }
+ return;
+ });
+ return;
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
+ "/xyz/openbmc_project/inventory", 0,
+ std::array<const char*, 1>{
+ "xyz.openbmc_project.Inventory.Item.Board.Motherboard"});
+
+ return true;
+}
+
+} // namespace security_manager
+
+int main()
+{
+
+ const static constexpr char* securityManagerService =
+ "xyz.openbmc_project.SecurityManager";
+
+ // setup connection to dbus
+ security_manager::conn =
+ std::make_shared<sdbusplus::asio::connection>(security_manager::io);
+
+ // Security manager Object
+ security_manager::conn->request_name(securityManagerService);
+ sdbusplus::asio::object_server server =
+ sdbusplus::asio::object_server(security_manager::conn);
+ // Start the monitoring based on the platform id
+ security_manager::startAtScaleDebugMonitor();
+
+ security_manager::io.run();
+
+ return 0;
+}
diff --git a/security-manager/src/security-manager.hpp b/security-manager/src/security-manager.hpp
new file mode 100644
index 0000000..b3380e6
--- /dev/null
+++ b/security-manager/src/security-manager.hpp
@@ -0,0 +1,37 @@
+/*
+// Copyright (c) 2019 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.
+*/
+
+namespace security_manager
+{
+
+struct UserAssertedEventRecord
+{
+ bool rootEnabledEvent;
+ bool unSupportedShellEvent;
+ bool uidZeroAssignedEvent;
+ bool weakHashAlgorithmEvent;
+};
+
+enum class PasswordHashAlgorithm : unsigned char
+{
+ hashAlgoMD5 = 1,
+ hashAlgoBlowFish = 2,
+ hashAlgoEksblowfish = 3,
+ hashAlgoNT = 4,
+ hashAlgoMax
+};
+
+} // namespace security_manager