From c6b86680a028f4f4c609aadd708e2454eae53cb0 Mon Sep 17 00:00:00 2001 From: Jean Flach Date: Wed, 17 Jan 2018 13:26:19 +0100 Subject: [PATCH] Add cli tool to send signals as Icinga user fixes #5991 --- etc/initsystem/icinga2.init.d.cmake | 88 ++++++++++++++--------------- lib/cli/CMakeLists.txt | 2 +- lib/cli/internalsignalcommand.cpp | 84 +++++++++++++++++++++++++++ lib/cli/internalsignalcommand.hpp | 50 ++++++++++++++++ 4 files changed, 179 insertions(+), 45 deletions(-) create mode 100644 lib/cli/internalsignalcommand.cpp create mode 100644 lib/cli/internalsignalcommand.hpp diff --git a/etc/initsystem/icinga2.init.d.cmake b/etc/initsystem/icinga2.init.d.cmake index ac494a8a2..bc41ccf67 100644 --- a/etc/initsystem/icinga2.init.d.cmake +++ b/etc/initsystem/icinga2.init.d.cmake @@ -47,14 +47,14 @@ getent group $ICINGA2_COMMAND_GROUP >/dev/null 2>&1 || (echo "Icinga command gro # Get function from functions library if [ -f /etc/rc.d/init.d/functions ]; then - . /etc/rc.d/init.d/functions + . /etc/rc.d/init.d/functions elif [ -f /etc/init.d/functions ]; then - . /etc/init.d/functions + . /etc/init.d/functions fi # Load extra environment variables if [ -f /etc/default/icinga2 ]; then - . /etc/default/icinga2 + . /etc/default/icinga2 fi # Start Icinga 2 @@ -72,34 +72,33 @@ start() { # Restart Icinga 2 stop() { - printf "Stopping Icinga 2: " + printf "Stopping Icinga 2: " - if [ ! -e $ICINGA2_PID_FILE ]; then - echo "The PID file '$ICINGA2_PID_FILE' does not exist." - if [ "x$1" = "xnofail" ]; then + if [ ! -e $ICINGA2_PID_FILE ]; then + echo "The PID file '$ICINGA2_PID_FILE' does not exist." + if [ "x$1" = "xnofail" ]; then return else exit 7 fi - fi + fi pid=`cat $ICINGA2_PID_FILE` - - if kill -INT $pid >/dev/null 2>&1; then + + if icinga2 internal signal -s SIGINT -p $pid >/dev/null 2>&1; then for i in 1 2 3 4 5 6 7 8 9 10; do - if ! kill -CHLD $pid >/dev/null 2>&1; then + if ! icinga2 internal signal -s SIGCHLD -p $pid >/dev/null 2>&1; then break fi printf '.' - sleep 3 done fi - if kill -CHLD $pid >/dev/null 2>&1; then - kill -KILL $pid - fi + if icinga2 internal signal -s SIGCHLD -p $pid >/dev/null 2>&1; then + icinga2 internal signal -s SIGKILL -p $pid >/dev/null 2>&1 + fi echo "Done" } @@ -114,21 +113,21 @@ checkconfig() { printf "Checking configuration: " if ! $DAEMON daemon -c $ICINGA2_CONFIG_FILE -C > $ICINGA2_STARTUP_LOG 2>&1; then - if [ "x$1" = "x" ]; then + if [ "x$1" = "x" ]; then cat $ICINGA2_STARTUP_LOG echo "Icinga 2 detected configuration errors. Check '$ICINGA2_STARTUP_LOG' for details." - exit 1 - else + exit 1 + else echo "Not "$1"ing Icinga 2 due to configuration errors. Check '$ICINGA2_STARTUP_LOG' for details." - if [ "x$2" = "xfail" ]; then - exit 1 - fi - fi - fi - + if [ "x$2" = "xfail" ]; then + exit 1 + fi + fi + fi + echo "Done" # no arguments requires full output - if [ "x$1" = "x" ]; then + if [ "x$1" = "x" ]; then cat $ICINGA2_STARTUP_LOG fi } @@ -143,7 +142,7 @@ status() { fi pid=`cat $ICINGA2_PID_FILE` - if kill -CHLD $pid >/dev/null 2>&1; then + if icinga2 internal signal -s SIGCHLD -p $pid >/dev/null 2>&1; then echo "Running" else echo "Not running" @@ -155,33 +154,34 @@ status() { case "$1" in start) checkconfig start fail - start - ;; + start + ;; stop) - stop - ;; + stop + ;; status) - status - ;; + status + ;; restart) checkconfig restart fail - stop nofail - start - ;; + stop nofail + start + ;; condrestart) - status > /dev/null 2>&1 || exit 0 - checkconfig restart fail - stop nofail - start - ;; + status > /dev/null 2>&1 || exit 0 + checkconfig restart fail + stop nofail + start + ;; reload) reload - ;; + ;; checkconfig) checkconfig - ;; + ;; *) - echo "Usage: $0 {start|stop|restart|reload|checkconfig|status}" - exit 3 + echo "Usage: $0 {start|stop|restart|reload|checkconfig|status}" + exit 3 esac + exit 0 diff --git a/lib/cli/CMakeLists.txt b/lib/cli/CMakeLists.txt index f4783fa6f..941c983e1 100644 --- a/lib/cli/CMakeLists.txt +++ b/lib/cli/CMakeLists.txt @@ -26,7 +26,7 @@ set(cli_SOURCES objectlistcommand.cpp objectlistutility.cpp pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp pkirequestcommand.cpp pkisavecertcommand.cpp pkiticketcommand.cpp variablegetcommand.cpp variablelistcommand.cpp variableutility.cpp - apiusercommand.cpp troubleshootcommand.cpp + internalsignalcommand.cpp apiusercommand.cpp troubleshootcommand.cpp ) if(ICINGA2_UNITY_BUILD) diff --git a/lib/cli/internalsignalcommand.cpp b/lib/cli/internalsignalcommand.cpp new file mode 100644 index 000000000..3e196728d --- /dev/null +++ b/lib/cli/internalsignalcommand.cpp @@ -0,0 +1,84 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "cli/internalsignalcommand.hpp" +#include "base/logger.hpp" +#include + +using namespace icinga; +namespace po = boost::program_options; + +REGISTER_CLICOMMAND("internal/signal", InternalSignalCommand); + +String InternalSignalCommand::GetDescription() const +{ + return "Send signal as Icinga user"; +} + +String InternalSignalCommand::GetShortDescription() const +{ + return "Send signal as Icinga user"; +} + +ImpersonationLevel InternalSignalCommand::GetImpersonationLevel() const +{ + return ImpersonateIcinga; +} + +bool InternalSignalCommand::IsHidden() const +{ + return true; +} + +void InternalSignalCommand::InitParameters(boost::program_options::options_description& visibleDesc, + boost::program_options::options_description& hiddenDesc) const +{ + visibleDesc.add_options() + ("pid,p", po::value(), "Target PID") + ("sig,s", po::value(), "Signal (POSIX string) to send") + ; +} + +/** + * The entry point for the "internal signal" CLI command. + * + * @returns An exit status. + */ +int InternalSignalCommand::Run(const boost::program_options::variables_map& vm, const std::vector& ap) const +{ +#ifndef _WIN32 + String signal = vm["sig"].as(); + + /* Thank POSIX */ + if (signal == "SIGKILL") + return kill(vm["pid"].as(), SIGKILL); + if (signal == "SIGINT") + return kill(vm["pid"].as(), SIGINT); + if (signal == "SIGCHLD") + return kill(vm["pid"].as(), SIGCHLD); + if (signal == "SIGHUP") + return kill(vm["pid"].as(), SIGHUP); + + Log(LogCritical, "cli") << "Unsupported signal \"" << signal << "\""; +#else + Log(LogCritical, "cli", "Unsupported action on Windows."); +#endif /* _Win32 */ + return 1; +} + diff --git a/lib/cli/internalsignalcommand.hpp b/lib/cli/internalsignalcommand.hpp new file mode 100644 index 000000000..44830ccd9 --- /dev/null +++ b/lib/cli/internalsignalcommand.hpp @@ -0,0 +1,50 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef INTERNALSIGNALCOMMAND_H +#define INTERNALSIGNALCOMMAND_H + +#include "cli/clicommand.hpp" + +namespace icinga +{ + +/** + * The "internal signal" command. + * + * @ingroup cli + */ +class InternalSignalCommand final : public CLICommand +{ +public: + DECLARE_PTR_TYPEDEFS(InternalSignalCommand); + + String GetDescription() const override; + String GetShortDescription() const override; + ImpersonationLevel GetImpersonationLevel() const override; + bool IsHidden() const override; + void InitParameters(boost::program_options::options_description& visibleDesc, + boost::program_options::options_description& hiddenDesc) const override; + int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const override; + +}; + +} + +#endif /* INTERNALSIGNALCOMMAND_H */