summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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