mirror of https://github.com/Icinga/icinga2.git
Implement support for running specific CLI commands as root
fixes #7380
This commit is contained in:
parent
d3c9e052e9
commit
80a3298b5e
|
@ -333,66 +333,73 @@ int Main(void)
|
|||
rc = 0;
|
||||
} else if (command) {
|
||||
#ifndef _WIN32
|
||||
String group = Application::GetRunAsGroup();
|
||||
|
||||
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 (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();
|
||||
|
||||
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;
|
||||
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 (setgid(gr->gr_gid) < 0) {
|
||||
Log(LogCritical, "cli")
|
||||
<< "setgid() 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;
|
||||
}
|
||||
|
||||
String user = Application::GetRunAsUser();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (setgid(gr->gr_gid) < 0) {
|
||||
Log(LogCritical, "cli")
|
||||
<< "setgid() 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;
|
||||
String user = Application::GetRunAsUser();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue