From 87f8ca5b7908a64ad5c70f2dcd46ae4e41715737 Mon Sep 17 00:00:00 2001 From: Dirk Goetz Date: Wed, 14 Feb 2018 13:21:59 +0100 Subject: [PATCH 1/7] Fixed URL encoding for HOSTNAME and SERVICENAME in mail notification Refs #5540 --- etc/icinga2/scripts/mail-host-notification.sh | 13 ++++++++++++- etc/icinga2/scripts/mail-service-notification.sh | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/etc/icinga2/scripts/mail-host-notification.sh b/etc/icinga2/scripts/mail-host-notification.sh index 8512a8c87..c63f63b4d 100755 --- a/etc/icinga2/scripts/mail-host-notification.sh +++ b/etc/icinga2/scripts/mail-host-notification.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # # Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) +# Except of function urlencode which is Copyright (C) by Brian White (brian@aljex.com) used under MIT license PROG="`basename $0`" ICINGA2HOST="`hostname`" @@ -49,6 +50,16 @@ Error() { exit 1; } +urlencode() { + local LANG=C i c e='' + for ((i=0;i<${#1};i++)); do + c=${1:$i:1} + [[ "$c" =~ [a-zA-Z0-9\.\~\_\-] ]] || printf -v c '%%%02X' "'$c" + e+="$c" + done + echo "$e" +} + ## Main while getopts 4:6::b:c:d:f:hi:l:n:o:r:s:t:v: opt do @@ -128,7 +139,7 @@ fi if [ -n "$ICINGAWEB2URL" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE -$ICINGAWEB2URL/monitoring/host/show?host=$HOSTNAME" +$ICINGAWEB2URL/monitoring/host/show?host=$(urlencode "$HOSTNAME")" fi ## Check whether verbose mode was enabled and log to syslog. diff --git a/etc/icinga2/scripts/mail-service-notification.sh b/etc/icinga2/scripts/mail-service-notification.sh index 5f3181486..8831df5d2 100755 --- a/etc/icinga2/scripts/mail-service-notification.sh +++ b/etc/icinga2/scripts/mail-service-notification.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # # Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) +# Except of function urlencode which is Copyright (C) by Brian White (brian@aljex.com) used under MIT license PROG="`basename $0`" ICINGA2HOST="`hostname`" @@ -51,6 +52,16 @@ Error() { exit 1; } +urlencode() { + local LANG=C i c e='' + for ((i=0;i<${#1};i++)); do + c=${1:$i:1} + [[ "$c" =~ [a-zA-Z0-9\.\~\_\-] ]] || printf -v c '%%%02X' "'$c" + e+="$c" + done + echo "$e" +} + ## Main while getopts 4:6:b:c:d:e:f:hi:l:n:o:r:s:t:u:v: opt do @@ -134,7 +145,7 @@ fi if [ -n "$ICINGAWEB2URL" ] ; then NOTIFICATION_MESSAGE="$NOTIFICATION_MESSAGE -$ICINGAWEB2URL/monitoring/service/show?host=$HOSTNAME&service=$SERVICENAME" +$ICINGAWEB2URL/monitoring/service/show?host=$(urlencode "$HOSTNAME")&service=$(urlencode "$SERVICENAME")" fi ## Check whether verbose mode was enabled and log to syslog. From bef37a3051e6a83bac474138674ee80bd51dce37 Mon Sep 17 00:00:00 2001 From: Dirk Goetz Date: Mon, 15 Jan 2018 14:49:28 +0100 Subject: [PATCH 2/7] SELinux: Add InfluxDB as example for services requiring `icinga2_can_connect_all`. Fixes #5915 --- doc/14-features.md | 3 +++ doc/22-selinux.md | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/14-features.md b/doc/14-features.md index 215400b8f..7c9f661de 100644 --- a/doc/14-features.md +++ b/doc/14-features.md @@ -333,6 +333,9 @@ predominantly affects Windows paths e.g. `C:\` becomes `C:_`. The database is assumed to exist so this object will make no attempt to create it currently. +If [SELinux](22-selinux.md#selinux) is enabled, it will not allow access for Icinga 2 to InfluxDB until the [boolean](22-selinux.md#booleans) +`icinga2_can_connect_all` is set to true as InfluxDB is not providing its own policy. + More configuration details can be found [here](09-object-types.md#objecttype-influxdbwriter). #### Instance Tagging diff --git a/doc/22-selinux.md b/doc/22-selinux.md index 20a0cfff4..0e442ecf3 100644 --- a/doc/22-selinux.md +++ b/doc/22-selinux.md @@ -104,15 +104,15 @@ SELinux is based on the least level of access required for a service to run. Usi **icinga2_can_connect_all** -Having this boolean enabled allows icinga2 to connect to all ports. This can be necessary if you use features which connect to unconfined services. +Having this boolean enabled allows icinga2 to connect to all ports. This can be necessary if you use features which connect to unconfined services, for example the [influxdb writer](14-features.md#influxdb-writer). **httpd_can_write_icinga2_command** -Having this boolean enabled allows httpd to write to the command pipe of icinga2. This is enabled by default, if not needed you can disable it for more security. +To allow httpd to write to the command pipe of icinga2 this boolean has to be enabled. This is enabled by default, if not needed you can disable it for more security. **httpd_can_connect_icinga2_api** -Having this boolean enabled allows httpd to connect to the API of icinga2 (Ports labeled icinga2_port_t). This is enabled by default, if not needed you can disable it for more security. +Enabling this boolean allows httpd to connect to the API of icinga2 (Ports labeled `icinga2_port_t`). This is enabled by default, if not needed you can disable it for more security. ### Configuration Examples From 88f77f9f8dad7dfae3df60f282f2f358409e0e56 Mon Sep 17 00:00:00 2001 From: Jean Flach Date: Wed, 29 Nov 2017 13:56:10 +0100 Subject: [PATCH 3/7] Fix prepare-dirs permission exploit refs #5793 --- etc/initsystem/icinga2.sysconfig.cmake | 7 +++--- etc/initsystem/prepare-dirs | 35 +++++++++++--------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/etc/initsystem/icinga2.sysconfig.cmake b/etc/initsystem/icinga2.sysconfig.cmake index e7fa54baf..7daf305be 100644 --- a/etc/initsystem/icinga2.sysconfig.cmake +++ b/etc/initsystem/icinga2.sysconfig.cmake @@ -3,9 +3,10 @@ ICINGA2_CONFIG_FILE=@CMAKE_INSTALL_FULL_SYSCONFDIR@/icinga2/icinga2.conf ICINGA2_RUN_DIR=@ICINGA2_RUNDIR@ ICINGA2_STATE_DIR=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@ ICINGA2_PID_FILE=$ICINGA2_RUN_DIR/icinga2/icinga2.pid -ICINGA2_ERROR_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/error.log -ICINGA2_STARTUP_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/startup.log -ICINGA2_LOG=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2/icinga2.log +ICINGA2_LOG_DIR=@CMAKE_INSTALL_FULL_LOCALSTATEDIR@/log/icinga2 +ICINGA2_ERROR_LOG=$ICINGA2_LOG_DIR/error.log +ICINGA2_STARTUP_LOG=$ICINGA2_LOG_DIR/startup.log +ICINGA2_LOG=$ICINGA2_LOG_DIR/icinga2.log ICINGA2_CACHE_DIR=$ICINGA2_STATE_DIR/cache/icinga2 ICINGA2_USER=@ICINGA2_USER@ ICINGA2_GROUP=@ICINGA2_GROUP@ diff --git a/etc/initsystem/prepare-dirs b/etc/initsystem/prepare-dirs index 5d67d476d..799e3226f 100644 --- a/etc/initsystem/prepare-dirs +++ b/etc/initsystem/prepare-dirs @@ -29,33 +29,28 @@ getent passwd $ICINGA2_USER >/dev/null 2>&1 || (echo "Icinga user '$ICINGA2_USER getent group $ICINGA2_GROUP >/dev/null 2>&1 || (echo "Icinga group '$ICINGA2_GROUP' does not exist. Exiting." && exit 6) getent group $ICINGA2_COMMAND_GROUP >/dev/null 2>&1 || (echo "Icinga command group '$ICINGA2_COMMAND_GROUP' does not exist. Exiting." && exit 6) -mkdir -p $(dirname -- $ICINGA2_PID_FILE) -chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $(dirname -- $ICINGA2_PID_FILE) -if [ -f $ICINGA2_PID_FILE ]; then - chown $ICINGA2_USER:$ICINGA2_GROUP $ICINGA2_PID_FILE +if [ ! -e "$ICINGA2_RUN_DIR"/icinga2 ]; then + mkdir "$ICINGA2_RUN_DIR"/icinga2 + mkdir "$ICINGA2_RUN_DIR"/icinga2/cmd + chmod 755 "$ICINGA2_RUN_DIR"/icinga2 + chmod 2750 "$ICINGA2_RUN_DIR"/icinga2/cmd + chown -R $ICINGA2_USER:$ICINGA2_COMMAND_GROUP "$ICINGA2_RUN_DIR"/icinga2 fi -mkdir -p $(dirname -- $ICINGA2_ERROR_LOG) -chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $(dirname -- $ICINGA2_ERROR_LOG) -chmod 750 $(dirname -- $ICINGA2_ERROR_LOG) -if [ -f $ICINGA2_ERROR_LOG ]; then - chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_ERROR_LOG -fi -if [ -f $ICINGA2_LOG ]; then - chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_LOG +# Could be undefined in installations where sysconf is not overridden on upgrade +if [ -z "$ICINGA2_LOG_DIR" ]; then + $ICINGA2_LOG_DIR=$(dirname -- "$ICINGA2_LOG") fi -mkdir -p $ICINGA2_RUN_DIR/icinga2/cmd -chown $ICINGA2_USER:$ICINGA2_COMMAND_GROUP $ICINGA2_RUN_DIR/icinga2/cmd +test -e "$ICINGA2_LOG_DIR" || install -m 750 -o $ICINGA2_USER -g $ICINGA2_COMMAND_GROUP -d "$ICINGA2_LOG_DIR" + if type restorecon >/dev/null 2>&1; then - restorecon -R $ICINGA2_RUN_DIR/icinga2/ + restorecon -R "$ICINGA2_RUN_DIR"/icinga2/ fi -chmod 2750 $ICINGA2_RUN_DIR/icinga2/cmd # Add a fallback if the user did not specify this directory in the sysconfig file if [ -z "$ICINGA2_CACHE_DIR" ]; then - ICINGA2_CACHE_DIR=$ICINGA2_STATE_DIR/cache/icinga2 + ICINGA2_CACHE_DIR="$ICINGA2_STATE_DIR"/cache/icinga2 fi -mkdir -p $ICINGA2_CACHE_DIR -chown $ICINGA2_USER:$ICINGA2_GROUP $ICINGA2_CACHE_DIR -chmod 750 $ICINGA2_CACHE_DIR + +test -e "$ICINGA2_CACHE_DIR" || install -m 750 -o $ICINGA2_USER -g $ICINGA2_COMMAND_GROUP -d "$ICINGA2_CACHE_DIR" From ba41d7f2499d31c2b0a15d2be412ed66f1c20b52 Mon Sep 17 00:00:00 2001 From: Jean Flach Date: Wed, 17 Jan 2018 13:25:40 +0100 Subject: [PATCH 4/7] Get ICINGA2_USER and GROUP from sysconfig --- etc/initsystem/icinga2.init.d.cmake | 14 ++++++-------- etc/initsystem/prepare-dirs | 14 ++++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/etc/initsystem/icinga2.init.d.cmake b/etc/initsystem/icinga2.init.d.cmake index 080fb2779..ac494a8a2 100644 --- a/etc/initsystem/icinga2.init.d.cmake +++ b/etc/initsystem/icinga2.init.d.cmake @@ -31,16 +31,14 @@ if [ ! -e $ICINGA2_CONFIG_FILE ]; then exit 6 fi -ICINGA2_USER=`$DAEMON variable get --current RunAsUser` -if [ $? != 0 ]; then - echo "Could not fetch RunAsUser variable. Error '$ICINGA2_USER'. Exiting." - exit 6 +if [ ! $ICINGA2_USER ]; then + echo "Could not fetch \$ICINGA2_USER. Exiting." + exit 6 fi -ICINGA2_GROUP=`$DAEMON variable get --current RunAsGroup` -if [ $? != 0 ]; then - echo "Could not fetch RunAsGroup variable. Error '$ICINGA2_GROUP'. Exiting." - exit 6 +if [ ! $ICINGA2_GROUP ]; then + echo "Could not fetch \$ICINGA2_GROUP. Exiting." + exit 6 fi getent passwd $ICINGA2_USER >/dev/null 2>&1 || (echo "Icinga user '$ICINGA2_USER' does not exist. Exiting." && exit 6) diff --git a/etc/initsystem/prepare-dirs b/etc/initsystem/prepare-dirs index 799e3226f..44b8343a8 100644 --- a/etc/initsystem/prepare-dirs +++ b/etc/initsystem/prepare-dirs @@ -13,16 +13,14 @@ else fi -ICINGA2_USER=`$DAEMON variable get --current RunAsUser` -if [ $? != 0 ]; then - echo "Could not fetch RunAsUser variable. Error '$ICINGA2_USER'. Exiting." - exit 6 +if [ ! $ICINGA2_USER ]; then + echo "Could not fetch \$ICINGA2_USER. Exiting." + exit 6 fi -ICINGA2_GROUP=`$DAEMON variable get --current RunAsGroup` -if [ $? != 0 ]; then - echo "Could not fetch RunAsGroup variable. Error '$ICINGA2_GROUP'. Exiting." - exit 6 +if [ ! $ICINGA2_GROUP ]; then + echo "Could not fetch \$ICINGA2_GROUP. Exiting." + exit 6 fi getent passwd $ICINGA2_USER >/dev/null 2>&1 || (echo "Icinga user '$ICINGA2_USER' does not exist. Exiting." && exit 6) From 6ae376b7fde595a44b23fdf0d1a65f6ff54fcdf4 Mon Sep 17 00:00:00 2001 From: Jean Flach Date: Wed, 17 Jan 2018 13:26:19 +0100 Subject: [PATCH 5/7] Add cli tool to send signals as Icinga user fixes #5991 --- etc/initsystem/icinga2.init.d.cmake | 88 ++++++++++++++--------------- lib/cli/CMakeLists.txt | 1 + lib/cli/internalsignalcommand.cpp | 84 +++++++++++++++++++++++++++ lib/cli/internalsignalcommand.hpp | 50 ++++++++++++++++ 4 files changed, 179 insertions(+), 44 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 bb2c75f47..258597dec 100644 --- a/lib/cli/CMakeLists.txt +++ b/lib/cli/CMakeLists.txt @@ -30,6 +30,7 @@ set(cli_SOURCES featureenablecommand.cpp featureenablecommand.hpp featurelistcommand.cpp featurelistcommand.hpp featureutility.cpp featureutility.hpp + internalsignalcommand.cpp internalsignalcommand.hpp nodesetupcommand.cpp nodesetupcommand.hpp nodeutility.cpp nodeutility.hpp nodewizardcommand.cpp nodewizardcommand.hpp 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 */ From c8c193a9d825acc6c6da8fc33688971d01c7fbd7 Mon Sep 17 00:00:00 2001 From: Jean Flach Date: Fri, 26 Jan 2018 16:27:16 +0100 Subject: [PATCH 6/7] Remove need for RunAsUser/Group They are now read form the sysconfig file which is owned by root --- config.h.cmake | 2 +- etc/icinga2/init.conf.cmake | 2 -- icinga-app/icinga.cpp | 14 ++++++++++++-- lib/base/application.cpp | 21 +++++++++++++++++++++ lib/base/application.hpp | 5 ++++- lib/base/utility.cpp | 32 ++++++++++++++++++++++++++++++++ lib/base/utility.hpp | 2 ++ 7 files changed, 72 insertions(+), 6 deletions(-) diff --git a/config.h.cmake b/config.h.cmake index e8a7bdcba..c461e029f 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -21,7 +21,7 @@ #define ICINGA_INCLUDECONFDIR "${CMAKE_INSTALL_FULL_DATADIR}/icinga2/include" #define ICINGA_USER "${ICINGA2_USER}" #define ICINGA_GROUP "${ICINGA2_GROUP}" - +#define ICINGA_SYSCONFIGFILE "${ICINGA2_SYSCONFIGFILE}" #define ICINGA_BUILD_HOST_NAME "${ICINGA2_BUILD_HOST_NAME}" #define ICINGA_BUILD_COMPILER_NAME "${ICINGA2_BUILD_COMPILER_NAME}" #define ICINGA_BUILD_COMPILER_VERSION "${ICINGA2_BUILD_COMPILER_VERSION}" diff --git a/etc/icinga2/init.conf.cmake b/etc/icinga2/init.conf.cmake index 9f57bca82..22406a998 100644 --- a/etc/icinga2/init.conf.cmake +++ b/etc/icinga2/init.conf.cmake @@ -3,5 +3,3 @@ * configuration file (icinga2.conf) is processed. */ -const RunAsUser = "@ICINGA2_USER@" -const RunAsGroup = "@ICINGA2_GROUP@" diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index ef6627818..f40a13541 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -143,6 +143,7 @@ static int Main() #endif /* _WIN32 */ Application::DeclarePrefixDir(ICINGA_PREFIX); + Application::DeclareSysconfigFile(ICINGA_SYSCONFIGFILE); Application::DeclareSysconfDir(ICINGA_SYSCONFDIR); Application::DeclareRunDir(ICINGA_RUNDIR); Application::DeclareLocalStateDir(ICINGA_LOCALSTATEDIR); @@ -153,8 +154,17 @@ static int Main() #endif /* _WIN32 */ Application::DeclareZonesDir(Application::GetSysconfDir() + "/icinga2/zones.d"); - Application::DeclareRunAsUser(ICINGA_USER); - Application::DeclareRunAsGroup(ICINGA_GROUP); + + String icinga_user = Utility::GetFromSysconfig("ICINGA2_USER"); + if (icinga_user.IsEmpty()) + icinga_user = ICINGA_USER; + + String icinga_group = Utility::GetFromSysconfig("ICINGA2_GROUP"); + if (icinga_group.IsEmpty()) + icinga_group = ICINGA_GROUP; + + Application::DeclareRunAsUser(icinga_user); + Application::DeclareRunAsGroup(icinga_group); #ifdef __linux__ Application::DeclareRLimitFiles(Application::GetDefaultRLimitFiles()); Application::DeclareRLimitProcesses(Application::GetDefaultRLimitProcesses()); diff --git a/lib/base/application.cpp b/lib/base/application.cpp index 7c552eaeb..1c1aa6776 100644 --- a/lib/base/application.cpp +++ b/lib/base/application.cpp @@ -1326,6 +1326,27 @@ void Application::DeclareStatePath(const String& path) ScriptGlobal::Set("StatePath", path); } +/** + * Retrives the path of the sysconfig file. + * + * @returns The path. + */ +String Application::GetSysconfigFile(void) +{ + return ScriptGlobal::Get("SysconfigFile"); +} + +/** + * Sets the path of the sysconfig file. + * + * @param path The new path. + */ +void Application::DeclareSysconfigFile(const String& path) +{ + if (!ScriptGlobal::Exists("SysconfigFile")) + ScriptGlobal::Set("SysconfigFile", path); +} + /** * Retrieves the path for the modified attributes file. * diff --git a/lib/base/application.hpp b/lib/base/application.hpp index ecdb1e92b..03d83599b 100644 --- a/lib/base/application.hpp +++ b/lib/base/application.hpp @@ -106,7 +106,10 @@ public: static String GetIncludeConfDir(); static void DeclareIncludeConfDir(const String& path); - static String GetStatePath(); + static String GetSysconfigFile(void); + static void DeclareSysconfigFile(const String& path); + + static String GetStatePath(void); static void DeclareStatePath(const String& path); static String GetModAttrPath(); diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index f9cf18cdb..6869e353d 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -1935,3 +1935,35 @@ String Utility::GetIcingaDataPath() } #endif /* _WIN32 */ + +String Utility::GetFromSysconfig(const String& env) +{ +#ifndef _WIN32 + String sysconf = Application::GetSysconfigFile(); + if (sysconf.IsEmpty()) + return ""; + + String cmdInner = ". " + EscapeShellArg(sysconf) + " 2>&1 >/dev/null;echo \"$" + env + "\""; + String cmd = "sh -c " + EscapeShellArg(cmdInner); + + FILE *fp = popen(cmd.CStr(), "r"); + + if (!fp) + return ""; + + char line[1024]; + String out; + + if (fgets(line, sizeof(line), fp)) + out = line; + else + return ""; + + pclose(fp); + + return out.Trim(); +#else + //TODO: Figure out how to do this on windows + return ""; +#endif /* _WIN32 */ +} diff --git a/lib/base/utility.hpp b/lib/base/utility.hpp index dd542c30a..97bb834b8 100644 --- a/lib/base/utility.hpp +++ b/lib/base/utility.hpp @@ -147,6 +147,8 @@ public: static String GetIcingaDataPath(); #endif /* _WIN32 */ + static String GetFromSysconfig(const String& env); + #ifdef I2_DEBUG static void SetTime(double); static void IncrementTime(double); From 87adc8898900dad326534afef2f218a7e64927d2 Mon Sep 17 00:00:00 2001 From: Jean Flach Date: Mon, 29 Jan 2018 14:23:53 +0100 Subject: [PATCH 7/7] Remove need for init.conf --- doc/17-language-reference.md | 10 ++--- etc/CMakeLists.txt | 4 -- etc/icinga2/init.conf.cmake | 5 --- icinga-app/icinga.cpp | 82 ++++++++++++++++++++++++------------ 4 files changed, 59 insertions(+), 42 deletions(-) delete mode 100644 etc/icinga2/init.conf.cmake diff --git a/doc/17-language-reference.md b/doc/17-language-reference.md index 93991a7a2..e288c611a 100644 --- a/doc/17-language-reference.md +++ b/doc/17-language-reference.md @@ -389,8 +389,8 @@ ObjectsPath |**Read-write.** Contains the path of the Icinga 2 objects f PidPath |**Read-write.** Contains the path of the Icinga 2 PID file. Defaults to RunDir + "/icinga2/icinga2.pid". Vars |**Read-write.** Contains a dictionary with global custom attributes. Not set by default. NodeName |**Read-write.** Contains the cluster node name. Set to the local hostname by default. -RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Used in the `init.conf` configuration file. -RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Used in the `init.conf` configuration file. +RunAsUser |**Read-write.** Defines the user the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig. +RunAsGroup |**Read-write.** Defines the group the Icinga 2 daemon is running as. Set in the Icinga 2 sysconfig. PlatformName |**Read-only.** The name of the operating system, e.g. "Ubuntu". PlatformVersion |**Read-only.** The version of the operating system, e.g. "14.04.3 LTS". PlatformKernel |**Read-only.** The name of the operating system kernel, e.g. "Linux". @@ -407,9 +407,9 @@ Variable |Description --------------------|------------------- EventEngine |**Read-write.** The name of the socket event engine, can be `poll` or `epoll`. The epoll interface is only supported on Linux. AttachDebugger |**Read-write.** Whether to attach a debugger when Icinga 2 crashes. Defaults to `false`. -RLimitFiles |**Read-write.** Defines the resource limit for RLIMIT_NOFILE that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. -RLimitProcesses |**Read-write.** Defines the resource limit for RLIMIT_NPROC that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. -RLimitStack |**Read-write.** Defines the resource limit for RLIMIT_STACK that should be set at start-up. Value cannot be set lower than the default `256 * 1024`. 0 disables the setting. Used in the `init.conf` configuration file. +RLimitFiles |**Read-write.** Defines the resource limit for RLIMIT_NOFILE that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. +RLimitProcesses |**Read-write.** Defines the resource limit for RLIMIT_NPROC that should be set at start-up. Value cannot be set lower than the default `16 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. +RLimitStack |**Read-write.** Defines the resource limit for RLIMIT_STACK that should be set at start-up. Value cannot be set lower than the default `256 * 1024`. 0 disables the setting. Set in Icinga 2 sysconfig. ## Apply diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt index bce13366b..bffca3016 100644 --- a/etc/CMakeLists.txt +++ b/etc/CMakeLists.txt @@ -15,8 +15,6 @@ # along with this program; if not, write to the Free Software Foundation # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -configure_file(icinga2/init.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2/init.conf @ONLY) - if(NOT WIN32) configure_file(icinga2/constants.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/icinga2/constants.conf @ONLY) endif() @@ -25,8 +23,6 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") configure_file(logrotate.d/icinga2.cmake ${CMAKE_CURRENT_BINARY_DIR}/logrotate.d/icinga2 @ONLY) endif() -install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/icinga2/init.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) - if(NOT WIN32) install_if_not_exists(${CMAKE_CURRENT_BINARY_DIR}/icinga2/constants.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) install_if_not_exists(icinga2/icinga2.conf ${CMAKE_INSTALL_SYSCONFDIR}/icinga2) diff --git a/etc/icinga2/init.conf.cmake b/etc/icinga2/init.conf.cmake deleted file mode 100644 index 22406a998..000000000 --- a/etc/icinga2/init.conf.cmake +++ /dev/null @@ -1,5 +0,0 @@ -/** - * This file is read by Icinga 2 before the main - * configuration file (icinga2.conf) is processed. - */ - diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index f40a13541..af8a1dda9 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -155,21 +155,62 @@ static int Main() Application::DeclareZonesDir(Application::GetSysconfDir() + "/icinga2/zones.d"); - String icinga_user = Utility::GetFromSysconfig("ICINGA2_USER"); - if (icinga_user.IsEmpty()) - icinga_user = ICINGA_USER; + String icingaUser = Utility::GetFromSysconfig("ICINGA2_USER"); + if (icingaUser.IsEmpty()) + icingaUser = ICINGA_USER; - String icinga_group = Utility::GetFromSysconfig("ICINGA2_GROUP"); - if (icinga_group.IsEmpty()) - icinga_group = ICINGA_GROUP; + String icingaGroup = Utility::GetFromSysconfig("ICINGA2_GROUP"); + if (icingaGroup.IsEmpty()) + icingaGroup = ICINGA_GROUP; + + Application::DeclareRunAsUser(icingaUser); + Application::DeclareRunAsGroup(icingaGroup); + +#ifdef RLIMIT_NOFILE + String rLimitFiles = Utility::GetFromSysconfig("ICINGA2_RLIMIT_FILES"); + if (rLimitFiles.IsEmpty()) + Application::DeclareRLimitFiles(Application::GetDefaultRLimitFiles()); + else { + try { + Application::DeclareRLimitFiles(Convert::ToLong(rLimitFiles)); + } catch (const std::invalid_argument& ex) { + std::cout + << "Error while parsing \"ICINGA2_RLIMIT_FILES\" from sysconfig: " << ex.what() << '\n'; + return EXIT_FAILURE; + } + } +#endif /* RLIMIT_NOFILE */ + +#ifdef RLIMIT_NPROC + String rLimitProcesses = Utility::GetFromSysconfig("ICINGA2_RLIMIT_PROCESSES"); + if (rLimitProcesses.IsEmpty()) + Application::DeclareRLimitProcesses(Application::GetDefaultRLimitProcesses()); + else { + try { + Application::DeclareRLimitProcesses(Convert::ToLong(rLimitProcesses)); + } catch (const std::invalid_argument& ex) { + std::cout + << "Error while parsing \"ICINGA2_RLIMIT_PROCESSES\" from sysconfig: " << ex.what() << '\n'; + return EXIT_FAILURE; + } + } +#endif /* RLIMIT_NPROC */ + +#ifdef RLIMIT_STACK + String rLimitStack = Utility::GetFromSysconfig("ICINGA2_RLIMIT_STACK"); + if (rLimitStack.IsEmpty()) + Application::DeclareRLimitStack(Application::GetDefaultRLimitStack()); + else { + try { + Application::DeclareRLimitStack(Convert::ToLong(rLimitStack)); + } catch (const std::invalid_argument& ex) { + std::cout + << "Error while parsing \"ICINGA2_RLIMIT_STACK\" from sysconfig: " << ex.what() << '\n'; + return EXIT_FAILURE; + } + } +#endif /* RLIMIT_STACK */ - Application::DeclareRunAsUser(icinga_user); - Application::DeclareRunAsGroup(icinga_group); -#ifdef __linux__ - Application::DeclareRLimitFiles(Application::GetDefaultRLimitFiles()); - Application::DeclareRLimitProcesses(Application::GetDefaultRLimitProcesses()); - Application::DeclareRLimitStack(Application::GetDefaultRLimitStack()); -#endif /* __linux__ */ Application::DeclareConcurrency(std::thread::hardware_concurrency()); Application::DeclareMaxConcurrentChecks(Application::GetDefaultMaxConcurrentChecks()); @@ -185,21 +226,6 @@ static int Main() ScriptGlobal::Set("BuildCompilerName", ICINGA_BUILD_COMPILER_NAME); ScriptGlobal::Set("BuildCompilerVersion", ICINGA_BUILD_COMPILER_VERSION); - String initconfig = Application::GetSysconfDir() + "/icinga2/init.conf"; - - if (Utility::PathExists(initconfig)) { - std::unique_ptr expression; - try { - expression = ConfigCompiler::CompileFile(initconfig); - - ScriptFrame frame(true); - expression->Evaluate(frame); - } catch (const std::exception& ex) { - Log(LogCritical, "config", DiagnosticInformation(ex)); - return EXIT_FAILURE; - } - } - if (!autocomplete) Application::SetResourceLimits();