]> granicus.if.org Git - icinga2/commitdiff
Implement support for running specific CLI commands as root
authorGunnar Beutner <gunnar@beutner.name>
Fri, 24 Oct 2014 13:29:46 +0000 (15:29 +0200)
committerGunnar Beutner <gunnar@beutner.name>
Fri, 24 Oct 2014 13:29:46 +0000 (15:29 +0200)
fixes #7380

icinga-app/icinga.cpp
lib/cli/agentsetupcommand.cpp
lib/cli/agentsetupcommand.hpp
lib/cli/clicommand.cpp
lib/cli/clicommand.hpp
lib/cli/featuredisablecommand.cpp
lib/cli/featuredisablecommand.hpp
lib/cli/featureenablecommand.cpp
lib/cli/featureenablecommand.hpp
lib/cli/repositorycommitcommand.cpp
lib/cli/repositorycommitcommand.hpp

index 16a9ae9a11d34f334af0ea7e5b628eed2bc448a9..70554338db2213df35567d043a4c94abc0f5a966 100644 (file)
@@ -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 */
index a31d7d0fec273884bcb24ae070e8c8053810daa2..1a727fa6b837a041e9a9874169f054b3275dc5e7 100644 (file)
@@ -77,6 +77,11 @@ std::vector<String> 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.
  *
index 4a1fd3b9a1c45142e14d4662daa03f4fc2084949..05e1be7e1e4ec2a15a1c8e98ab1c94c02ebf6dd1 100644 (file)
@@ -40,6 +40,7 @@ public:
        virtual void InitParameters(boost::program_options::options_description& visibleDesc,
            boost::program_options::options_description& hiddenDesc) const;
        virtual std::vector<String> 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<std::string>& ap) const;
 
 private:
index 0930be8097e72c0416d04eafa4908e3603c00db1..441dd2e925a671bb990fcbb1bc198e9ed3fe5c19 100644 (file)
@@ -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,
index 562589f3d2a6f73b0b1a2ba984b5281103626c67..20ad1f80d9911b2ed56366121591ea21d2d3c219 100644 (file)
@@ -32,6 +32,13 @@ namespace icinga
 std::vector<String> I2_CLI_API GetBashCompletionSuggestions(const String& type, const String& word);
 std::vector<String> 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<std::string>& ap) const = 0;
        virtual std::vector<String> GetArgumentSuggestions(const String& argument, const String& word) const;
        virtual std::vector<String> GetPositionalSuggestions(const String& word) const;
index 1e135b789e2dc92b814f6038cd70ad58742fd5a1..03e2e146572578a1308b838694135654c7e3eaa2 100644 (file)
@@ -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.
  *
index 1331af24617a9acb8826ffa686c6378be6598d30..722d89abbe62ee452370df86b01d300891c71e5d 100644 (file)
@@ -40,6 +40,7 @@ public:
        virtual int GetMinArguments(void) const;
        virtual int GetMaxArguments(void) const;
        virtual std::vector<String> GetPositionalSuggestions(const String& word) const;
+       virtual ImpersonationLevel GetImpersonationLevel(void) const;
        virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
 
 };
index 3e7a7ee4a742d170e9e64f6d10e3f539563f90d7..612bede2f69925047fc7690f22a4b4877dce7663 100644 (file)
@@ -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.
  *
index 9488e363a2f81ed6506fe2bd93cfc8124d3a37b7..4a94aa019a087a77851fa53458d364b7ce329945 100644 (file)
@@ -40,6 +40,7 @@ public:
        virtual int GetMinArguments(void) const;
        virtual int GetMaxArguments(void) const;
        virtual std::vector<String> GetPositionalSuggestions(const String& word) const;
+       virtual ImpersonationLevel GetImpersonationLevel(void) const;
        virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
 };
 
index 9c5adc5d974d3278626564a257206df51a47e345..d2ee3da9c433562e2e3931777f9144d27632e70b 100644 (file)
@@ -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.
  *
index 09768bcc086a8c2c3381c77ea9f9d8e14f6d945f..d853d25e1af9a1642263ce3b2ddc0a68eb9f162f 100644 (file)
@@ -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<std::string>& ap) const;
 };