mirror of
https://github.com/Icinga/icinga2.git
synced 2025-09-26 11:08:51 +02:00
Merge pull request #10538 from Icinga/allow-uid-gid-icinga-user-and-group
Allow UID/GID in ICINGA2_(USER|GROUP) environment variables
This commit is contained in:
commit
0c2fd00383
@ -2334,12 +2334,12 @@ Also see `CMakeLists.txt` for details.
|
|||||||
* `ICINGA2_CONFIGDIR`: Main config directory; defaults to `CMAKE_INSTALL_SYSCONFDIR/icinga2` usually `/etc/icinga2`
|
* `ICINGA2_CONFIGDIR`: Main config directory; defaults to `CMAKE_INSTALL_SYSCONFDIR/icinga2` usually `/etc/icinga2`
|
||||||
* `ICINGA2_CACHEDIR`: Directory for cache files; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/cache/icinga2` usually `/var/cache/icinga2`
|
* `ICINGA2_CACHEDIR`: Directory for cache files; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/cache/icinga2` usually `/var/cache/icinga2`
|
||||||
* `ICINGA2_DATADIR`: Data directory for the daemon; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/lib/icinga2` usually `/var/lib/icinga2`
|
* `ICINGA2_DATADIR`: Data directory for the daemon; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/lib/icinga2` usually `/var/lib/icinga2`
|
||||||
* `ICINGA2_LOGDIR`: Logfiles of the daemon; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/log/icinga2 usually `/var/log/icinga2`
|
* `ICINGA2_LOGDIR`: Logfiles of the daemon; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/log/icinga2` usually `/var/log/icinga2`
|
||||||
* `ICINGA2_SPOOLDIR`: Spooling directory ; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/spool/icinga2` usually `/var/spool/icinga2`
|
* `ICINGA2_SPOOLDIR`: Spooling directory ; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/spool/icinga2` usually `/var/spool/icinga2`
|
||||||
* `ICINGA2_INITRUNDIR`: Runtime data for the init system; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/run/icinga2` usually `/run/icinga2`
|
* `ICINGA2_INITRUNDIR`: Runtime data for the init system; defaults to `CMAKE_INSTALL_LOCALSTATEDIR/run/icinga2` usually `/run/icinga2`
|
||||||
* `ICINGA2_GIT_VERSION_INFO`: Whether to use Git to determine the version number; defaults to `ON`
|
* `ICINGA2_GIT_VERSION_INFO`: Whether to use Git to determine the version number; defaults to `ON`
|
||||||
* `ICINGA2_USER`: The user Icinga 2 should run as; defaults to `icinga`
|
* `ICINGA2_USER`: The user or user-id Icinga 2 should run as; defaults to `icinga`
|
||||||
* `ICINGA2_GROUP`: The group Icinga 2 should run as; defaults to `icinga`
|
* `ICINGA2_GROUP`: The group or group-id Icinga 2 should run as; defaults to `icinga`
|
||||||
* `ICINGA2_COMMAND_GROUP`: The command group Icinga 2 should use; defaults to `icingacmd`
|
* `ICINGA2_COMMAND_GROUP`: The command group Icinga 2 should use; defaults to `icingacmd`
|
||||||
* `ICINGA2_SYSCONFIGFILE`: Where to put the config file the initscript/systemd pulls it's dirs from;
|
* `ICINGA2_SYSCONFIGFILE`: Where to put the config file the initscript/systemd pulls it's dirs from;
|
||||||
* defaults to `CMAKE_INSTALL_PREFIX/etc/sysconfig/icinga2`
|
* defaults to `CMAKE_INSTALL_PREFIX/etc/sysconfig/icinga2`
|
||||||
|
@ -569,42 +569,60 @@ static int Main()
|
|||||||
} else if (command && command->GetImpersonationLevel() == ImpersonateIcinga) {
|
} else if (command && command->GetImpersonationLevel() == ImpersonateIcinga) {
|
||||||
String group = Configuration::RunAsGroup;
|
String group = Configuration::RunAsGroup;
|
||||||
String user = Configuration::RunAsUser;
|
String user = Configuration::RunAsUser;
|
||||||
|
gid_t gid = 0;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
struct group *gr = getgrnam(group.CStr());
|
try {
|
||||||
|
gid = boost::lexical_cast<gid_t>(group);
|
||||||
if (!gr) {
|
} catch (const boost::bad_lexical_cast&) {
|
||||||
if (errno == 0) {
|
struct group* gr = getgrnam(group.CStr());
|
||||||
Log(LogCritical, "cli")
|
if (!gr) {
|
||||||
<< "Invalid group specified: " << group;
|
if (errno == 0) {
|
||||||
return EXIT_FAILURE;
|
Log(LogCritical, "cli")
|
||||||
} else {
|
<< "Invalid group specified: " << group;
|
||||||
Log(LogCritical, "cli")
|
} else {
|
||||||
<< "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
Log(LogCritical, "cli")
|
||||||
|
<< "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||||
|
}
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gid = gr->gr_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getgid() != gr->gr_gid) {
|
if (getgid() != gid) {
|
||||||
if (!vm.count("reload-internal") && setgroups(0, nullptr) < 0) {
|
if (!vm.count("reload-internal") && setgroups(0, nullptr) < 0) {
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
<< "setgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "Please re-run this command as a privileged user or using the \"" << user << "\" account.";
|
<< "Please rerun this command as a privileged user or using the \"" << user << "\" account.";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setgid(gr->gr_gid) < 0) {
|
if (setgid(gid) < 0) {
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
<< "setgid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||||
|
Log(LogCritical, "cli")
|
||||||
|
<< "Please rerun this command as a privileged user or using the \"" << user << "\" account.";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
std::optional<uid_t> uid;
|
||||||
struct passwd *pw = getpwnam(user.CStr());
|
struct passwd *pw = nullptr;
|
||||||
|
|
||||||
if (!pw) {
|
errno = 0;
|
||||||
|
try {
|
||||||
|
uid = boost::lexical_cast<uid_t>(user);
|
||||||
|
pw = getpwuid(*uid);
|
||||||
|
} catch (const boost::bad_lexical_cast&) {
|
||||||
|
pw = getpwnam(user.CStr());
|
||||||
|
if (pw) {
|
||||||
|
uid = pw->pw_uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uid) {
|
||||||
if (errno == 0) {
|
if (errno == 0) {
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "Invalid user specified: " << user;
|
<< "Invalid user specified: " << user;
|
||||||
@ -617,20 +635,22 @@ static int Main()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// also activate the additional groups the configured user is member of
|
// also activate the additional groups the configured user is member of
|
||||||
if (getuid() != pw->pw_uid) {
|
if (getuid() != *uid) {
|
||||||
if (!vm.count("reload-internal") && initgroups(user.CStr(), pw->pw_gid) < 0) {
|
// initgroups() is only called when either getpwuid() or getpwnam() returned a valid user entry.
|
||||||
|
// Otherwise it makes no sense to set any additional groups.
|
||||||
|
if (!vm.count("reload-internal") && pw && initgroups(user.CStr(), pw->pw_gid) < 0) {
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
<< "initgroups() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "Please re-run this command as a privileged user or using the \"" << user << "\" account.";
|
<< "Please rerun this command as a privileged user or using the \"" << user << "\" account.";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setuid(pw->pw_uid) < 0) {
|
if (setuid(*uid) < 0) {
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
<< "setuid() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "Please re-run this command as a privileged user or using the \"" << user << "\" account.";
|
<< "Please rerun this command as a privileged user or using the \"" << user << "\" account.";
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -800,43 +800,67 @@ void Utility::RenameFile(const String& source, const String& target)
|
|||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Set file permissions
|
* Set the ownership of the specified file to the given user and group.
|
||||||
|
*
|
||||||
|
* In case of an error, false is returned and the error is logged.
|
||||||
|
*
|
||||||
|
* @note This operation will fail if the program is not run as root or the given user is
|
||||||
|
* not already the owner and member of the given group.
|
||||||
|
*
|
||||||
|
* @param file The path to the file as a string
|
||||||
|
* @param user Either the username or their UID as a string
|
||||||
|
* @param group Either the group's name or its GID as a string
|
||||||
|
*
|
||||||
|
* @return 'true' if the operation was successful, 'false' if an error occurred.
|
||||||
*/
|
*/
|
||||||
bool Utility::SetFileOwnership(const String& file, const String& user, const String& group)
|
bool Utility::SetFileOwnership(const String& file, const String& user, const String& group)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
errno = 0;
|
uid_t uid = 0;
|
||||||
struct passwd *pw = getpwnam(user.CStr());
|
try {
|
||||||
|
uid = boost::lexical_cast<uid_t>(user);
|
||||||
|
} catch (const boost::bad_lexical_cast&) {
|
||||||
|
errno = 0;
|
||||||
|
struct passwd* pw = getpwnam(user.CStr());
|
||||||
|
|
||||||
if (!pw) {
|
if (!pw) {
|
||||||
if (errno == 0) {
|
if (errno == 0) {
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "Invalid user specified: " << user;
|
<< "Invalid user specified: " << user;
|
||||||
return false;
|
} else {
|
||||||
} else {
|
Log(LogCritical, "cli") << "getpwnam() failed with error code " << errno << ", \""
|
||||||
Log(LogCritical, "cli")
|
<< Utility::FormatErrorNumber(errno) << "\"";
|
||||||
<< "getpwnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid = pw->pw_uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
struct group *gr = getgrnam(group.CStr());
|
|
||||||
|
|
||||||
if (!gr) {
|
gid_t gid = 0;
|
||||||
if (errno == 0) {
|
try {
|
||||||
Log(LogCritical, "cli")
|
gid = boost::lexical_cast<gid_t>(group);
|
||||||
<< "Invalid group specified: " << group;
|
} catch (const boost::bad_lexical_cast&) {
|
||||||
return false;
|
errno = 0;
|
||||||
} else {
|
struct group* gr = getgrnam(group.CStr());
|
||||||
Log(LogCritical, "cli")
|
|
||||||
<< "getgrnam() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
if (!gr) {
|
||||||
|
if (errno == 0) {
|
||||||
|
Log(LogCritical, "cli")
|
||||||
|
<< "Invalid group specified: " << group;
|
||||||
|
} else {
|
||||||
|
Log(LogCritical, "cli") << "getgrnam() failed with error code " << errno << ", \""
|
||||||
|
<< Utility::FormatErrorNumber(errno) << "\"";
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gid = gr->gr_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chown(file.CStr(), pw->pw_uid, gr->gr_gid) < 0) {
|
if (chown(file.CStr(), uid, gid) < 0) {
|
||||||
Log(LogCritical, "cli")
|
Log(LogCritical, "cli")
|
||||||
<< "chown() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
<< "chown() failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user