From: Gunnar Beutner Date: Fri, 24 Oct 2014 13:29:46 +0000 (+0200) Subject: Implement support for running specific CLI commands as root X-Git-Tag: v2.2.0~266 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=80a3298b5eab28a0ff7d4a8038c1fa09c6bdb741;p=icinga2 Implement support for running specific CLI commands as root fixes #7380 --- diff --git a/icinga-app/icinga.cpp b/icinga-app/icinga.cpp index 16a9ae9a1..70554338d 100644 --- a/icinga-app/icinga.cpp +++ b/icinga-app/icinga.cpp @@ -333,66 +333,73 @@ int Main(void) rc = 0; } else if (command) { #ifndef _WIN32 - String group = Application::GetRunAsGroup(); + if (command->GetImpersonationLevel() == ImpersonateRoot) { + if (getuid() != 0) { + Log(LogCritical, "cli", "This command must be run as root."); + return 0; + } + } else if (command && command->GetImpersonationLevel() == ImpersonateIcinga) { + String group = Application::GetRunAsGroup(); - errno = 0; - struct group *gr = getgrnam(group.CStr()); + errno = 0; + struct group *gr = getgrnam(group.CStr()); - if (!gr) { - if (errno == 0) { - Log(LogCritical, "cli") - << "Invalid group specified: " << group; - return EXIT_FAILURE; - } else { - Log(LogCritical, "cli") - << "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; - return EXIT_FAILURE; + if (!gr) { + if (errno == 0) { + Log(LogCritical, "cli") + << "Invalid group specified: " << group; + return EXIT_FAILURE; + } else { + Log(LogCritical, "cli") + << "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; + return EXIT_FAILURE; + } } - } - if (getgid() != gr->gr_gid) { - if (!vm.count("reload-internal") && setgroups(0, NULL) < 0) { - Log(LogCritical, "cli") - << "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; - return EXIT_FAILURE; - } + if (getgid() != gr->gr_gid) { + if (!vm.count("reload-internal") && setgroups(0, NULL) < 0) { + Log(LogCritical, "cli") + << "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; + return EXIT_FAILURE; + } - if (setgid(gr->gr_gid) < 0) { - Log(LogCritical, "cli") - << "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; - return EXIT_FAILURE; + if (setgid(gr->gr_gid) < 0) { + Log(LogCritical, "cli") + << "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; + return EXIT_FAILURE; + } } - } - String user = Application::GetRunAsUser(); + String user = Application::GetRunAsUser(); - errno = 0; - struct passwd *pw = getpwnam(user.CStr()); + errno = 0; + struct passwd *pw = getpwnam(user.CStr()); - if (!pw) { - if (errno == 0) { - Log(LogCritical, "cli") - << "Invalid user specified: " << user; - return EXIT_FAILURE; - } else { - Log(LogCritical, "cli") - << "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; - return EXIT_FAILURE; + if (!pw) { + if (errno == 0) { + Log(LogCritical, "cli") + << "Invalid user specified: " << user; + return EXIT_FAILURE; + } else { + Log(LogCritical, "cli") + << "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; + return EXIT_FAILURE; + } } - } - // also activate the additional groups the configured user is member of - if (getuid() != pw->pw_uid) { - if (!vm.count("reload-internal") && initgroups(user.CStr(), pw->pw_gid) < 0) { - Log(LogCritical, "cli") - << "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; - return EXIT_FAILURE; - } + // also activate the additional groups the configured user is member of + if (getuid() != pw->pw_uid) { + if (!vm.count("reload-internal") && initgroups(user.CStr(), pw->pw_gid) < 0) { + Log(LogCritical, "cli") + << "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; + return EXIT_FAILURE; + } - if (setuid(pw->pw_uid) < 0) { - Log(LogCritical, "cli") - << "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; - return EXIT_FAILURE; + if (setuid(pw->pw_uid) < 0) { + Log(LogCritical, "cli") + << "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\""; + return EXIT_FAILURE; + } } } #endif /* _WIN32 */ diff --git a/lib/cli/agentsetupcommand.cpp b/lib/cli/agentsetupcommand.cpp index a31d7d0fe..1a727fa6b 100644 --- a/lib/cli/agentsetupcommand.cpp +++ b/lib/cli/agentsetupcommand.cpp @@ -77,6 +77,11 @@ std::vector AgentSetupCommand::GetArgumentSuggestions(const String& argu return CLICommand::GetArgumentSuggestions(argument, word); } +ImpersonationLevel AgentSetupCommand::GetImpersonationLevel(void) const +{ + return ImpersonateRoot; +} + /** * The entry point for the "agent setup" CLI command. * diff --git a/lib/cli/agentsetupcommand.hpp b/lib/cli/agentsetupcommand.hpp index 4a1fd3b9a..05e1be7e1 100644 --- a/lib/cli/agentsetupcommand.hpp +++ b/lib/cli/agentsetupcommand.hpp @@ -40,6 +40,7 @@ public: virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const; + virtual ImpersonationLevel GetImpersonationLevel(void) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const; private: diff --git a/lib/cli/clicommand.cpp b/lib/cli/clicommand.cpp index 0930be809..441dd2e92 100644 --- a/lib/cli/clicommand.cpp +++ b/lib/cli/clicommand.cpp @@ -159,6 +159,11 @@ void CLICommand::InitParameters(boost::program_options::options_description& vis boost::program_options::options_description& hiddenDesc) const { } +ImpersonationLevel CLICommand::GetImpersonationLevel(void) const +{ + return ImpersonateIcinga; +} + bool CLICommand::ParseCommand(int argc, char **argv, po::options_description& visibleDesc, po::options_description& hiddenDesc, po::positional_options_description& positionalDesc, diff --git a/lib/cli/clicommand.hpp b/lib/cli/clicommand.hpp index 562589f3d..20ad1f80d 100644 --- a/lib/cli/clicommand.hpp +++ b/lib/cli/clicommand.hpp @@ -32,6 +32,13 @@ namespace icinga std::vector I2_CLI_API GetBashCompletionSuggestions(const String& type, const String& word); std::vector I2_CLI_API GetFieldCompletionSuggestions(const Type *type, const String& word); +enum ImpersonationLevel +{ + ImpersonateNone, + ImpersonateRoot, + ImpersonateIcinga +}; + /** * A CLI command. * @@ -50,6 +57,7 @@ public: virtual int GetMaxArguments(void) const; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const; + virtual ImpersonationLevel GetImpersonationLevel(void) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const = 0; virtual std::vector GetArgumentSuggestions(const String& argument, const String& word) const; virtual std::vector GetPositionalSuggestions(const String& word) const; diff --git a/lib/cli/featuredisablecommand.cpp b/lib/cli/featuredisablecommand.cpp index 1e135b789..03e2e1465 100644 --- a/lib/cli/featuredisablecommand.cpp +++ b/lib/cli/featuredisablecommand.cpp @@ -51,6 +51,11 @@ int FeatureDisableCommand::GetMaxArguments(void) const return -1; } +ImpersonationLevel FeatureDisableCommand::GetImpersonationLevel(void) const +{ + return ImpersonateRoot; +} + /** * The entry point for the "feature disable" CLI command. * diff --git a/lib/cli/featuredisablecommand.hpp b/lib/cli/featuredisablecommand.hpp index 1331af246..722d89abb 100644 --- a/lib/cli/featuredisablecommand.hpp +++ b/lib/cli/featuredisablecommand.hpp @@ -40,6 +40,7 @@ public: virtual int GetMinArguments(void) const; virtual int GetMaxArguments(void) const; virtual std::vector GetPositionalSuggestions(const String& word) const; + virtual ImpersonationLevel GetImpersonationLevel(void) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const; }; diff --git a/lib/cli/featureenablecommand.cpp b/lib/cli/featureenablecommand.cpp index 3e7a7ee4a..612bede2f 100644 --- a/lib/cli/featureenablecommand.cpp +++ b/lib/cli/featureenablecommand.cpp @@ -51,6 +51,11 @@ int FeatureEnableCommand::GetMaxArguments(void) const return -1; } +ImpersonationLevel FeatureEnableCommand::GetImpersonationLevel(void) const +{ + return ImpersonateRoot; +} + /** * The entry point for the "feature enable" CLI command. * diff --git a/lib/cli/featureenablecommand.hpp b/lib/cli/featureenablecommand.hpp index 9488e363a..4a94aa019 100644 --- a/lib/cli/featureenablecommand.hpp +++ b/lib/cli/featureenablecommand.hpp @@ -40,6 +40,7 @@ public: virtual int GetMinArguments(void) const; virtual int GetMaxArguments(void) const; virtual std::vector GetPositionalSuggestions(const String& word) const; + virtual ImpersonationLevel GetImpersonationLevel(void) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const; }; diff --git a/lib/cli/repositorycommitcommand.cpp b/lib/cli/repositorycommitcommand.cpp index 9c5adc5d9..d2ee3da9c 100644 --- a/lib/cli/repositorycommitcommand.cpp +++ b/lib/cli/repositorycommitcommand.cpp @@ -58,6 +58,11 @@ void RepositoryCommitCommand::InitParameters(boost::program_options::options_des ("simulate", "Simulate to-be-committed changes"); } +ImpersonationLevel RepositoryCommitCommand::GetImpersonationLevel(void) const +{ + return ImpersonateRoot; +} + /** * The entry point for the "repository commit" CLI command. * diff --git a/lib/cli/repositorycommitcommand.hpp b/lib/cli/repositorycommitcommand.hpp index 09768bcc0..d853d25e1 100644 --- a/lib/cli/repositorycommitcommand.hpp +++ b/lib/cli/repositorycommitcommand.hpp @@ -42,6 +42,7 @@ public: virtual String GetShortDescription(void) const; virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const; + virtual ImpersonationLevel GetImpersonationLevel(void) const; virtual int Run(const boost::program_options::variables_map& vm, const std::vector& ap) const; };